diff --git a/.github/LinuxMain.stencil b/.github/LinuxMain.stencil deleted file mode 100644 index 11d1618ec..000000000 --- a/.github/LinuxMain.stencil +++ /dev/null @@ -1,19 +0,0 @@ -@testable import Core -@testable import A_ -import XCTest - -//TODO get this to run on CI and don’t have it committed -//NOTE problem is Sourcery doesn’t support Linux currently -//USAGE: cd PromiseKit/Sources/.. && sourcery --config .github/sourcery.yml - -{% for type in types.classes|based:"XCTestCase" %} -extension {{ type.name }} { - static var allTests = [ - {% for method in type.methods %}{% if method.parameters.count == 0 and method.shortName|hasPrefix:"test" %} ("{{ method.shortName }}", {{type.name}}.{{ method.shortName }}), - {% endif %}{% endfor %}] -} - -{% endfor %} -XCTMain([ -{% for type in types.classes|based:"XCTestCase" %}{% if not type.annotations.excludeFromLinuxMain %} testCase({{ type.name }}.allTests), -{% endif %}{% endfor %}]) diff --git a/.github/codecov.yml b/.github/codecov.yml index 8ffbde74d..12c801e77 100644 --- a/.github/codecov.yml +++ b/.github/codecov.yml @@ -1,7 +1,7 @@ ignore: - "Tests" - "README.md" - - "Documentation" + - "Documents" - ".travis.yml" codecov: diff --git a/.github/jazzy.yml b/.github/jazzy.yml index 9e8d71f05..01ed6c269 100644 --- a/.github/jazzy.yml +++ b/.github/jazzy.yml @@ -7,12 +7,10 @@ custom_categories: - Thenable - CatchMixin - Resolver -xcodebuild_arguments: - - UseModernBuildSystem=NO output: ../output # output directory is relative to config file… ugh readme: - Documentation/README.md + Documents/README.md theme: fullwidth diff --git a/.github/sourcery.yml b/.github/sourcery.yml deleted file mode 100644 index e965499c6..000000000 --- a/.github/sourcery.yml +++ /dev/null @@ -1,12 +0,0 @@ -sources: - include: - - ../Tests/A+ - - ../Tests/CorePromise - exclude: - - ../Tests/A+/0.0.0.swift - - ../Tests/CorePromise/Utilities.swift -templates: - include: - - LinuxMain.stencil -output: - ../Tests/LinuxMain.swift diff --git a/.github/spelling-skip-words b/.github/spelling-skip-words new file mode 100644 index 000000000..01eae0876 --- /dev/null +++ b/.github/spelling-skip-words @@ -0,0 +1,131 @@ +PromiseKit +NSError +ObjC +AnyPromise +AnyPromises +iOS +Xcode +CocoaPods +Submodules +Agostini.tech +1.x +2.x +3.x +4.x +5.x +6.x +7.x +8.x +9.x +10.x +Alamofire +APIs +PMKConfiguration +Kitura +RxSwift +Zalgo +macOS +watchOS +CoreLocation +CancellablePromiseKit +UIKit +tvOS +SDKs +hair-raisingly +deallocate +deallocated +initializer +initializers +work-arounds +i.e. +e.g. +SwiftPM +CorePromise +submodules +CorePromise +tuplegate +Swift-ese +codebase +subspecs +finalizers +ReactiveSwift +asynchronicity +composable +presentee +Optionals +StackOverflow +backtrace +backport +reframe +runtime +_ +misinference +Podfile +Xcodes +TideLift +Gitter +top-100 +CocoaPod +conformant +PromiseKits +CancellablePromise +CancellableThenable +thenable +CancellableCatchable +catchable +cancellableRecover +ensureThen +Alamofire.request +responseDecodable +DecodableObject.self +BFTask +CLLocationManager.requestLocation +URLSession.shared.dataTask +MapKit +MKDirections +URLSession.shared.GET +StoreKit +SKProductsRequest +SystemConfiguration +SCNetworkReachability.promise +UIViewPropertyAnimator +startAnimation +Alamofire.DataRequest +responseData +responseString +responseJSON +responsePropertyList +Alamofire.DownloadRequest +CLLocationManager +requestLocation +authorizationType +requestAuthorization +requestedAuthorizationType +NotificationCenter +NSObject +keyPath +URLSession +dataTask +uploadTask +fromFile +downloadTask +HomeKit +HMPromiseAccessoryBrowser +scanInterval +HMHomeManager +calculateETA +MKMapSnapshotter +SKReceiptRefreshRequest +SCNetworkReachability +Cancellability +HealthKit +enum +cancellize +UIImage +PMKFinalizercancelthendonePromise +VoidPending +PromiseURLSessionresumewait +unusedResult +discardableResultcatchreturncauterize +PMKFinalizercancelthenMapthenFlatMapthendonePromise +Accio diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index 4a8b06c96..e347dacb1 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -4,8 +4,11 @@ on: inputs: version: required: true + pods: + required: false jobs: pods: + if: ${{ github.event.inputs.pods != 'false' }} runs-on: macos-latest steps: @@ -18,58 +21,11 @@ jobs: env: pods - uses: actions/checkout@v2 - with: - submodules: true - run: pod trunk push --allow-warnings --skip-tests --skip-import-validation env: COCOAPODS_TRUNK_TOKEN: ${{ secrets.COCOAPODS_TRUNK_TOKEN }} - - - name: Seal Deployment - uses: bobheadxi/deployments@v0.5.2 - if: always() - with: - step: finish - token: ${{ secrets.GITHUB_TOKEN }} - status: ${{ job.status }} - deployment_id: ${{ steps.deployment.outputs.deployment_id }} - - carthage: - runs-on: macos-latest - steps: - - - name: Start Deployment - uses: bobheadxi/deployments@v0.5.2 - id: deployment - with: - step: start - token: ${{ secrets.GITHUB_TOKEN }} - env: carthage - - - uses: maxim-lobanov/setup-xcode@v1 - with: - xcode-version: ^11 - # Waiting on https://github.com/Carthage/Carthage/issues/3103 for Xcode 12 - - - uses: joutvhu/get-release@v1 - id: release - with: - tag_name: ${{ github.event.inputs.version }} - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - uses: actions/checkout@v2 - - run: carthage build --no-skip-current --platform macOS,iOS,watchOS,tvOS --archive - - run: mv PromiseKit.framework.zip PromiseKit-$v.framework.zip - - - uses: actions/upload-release-asset@v1 - with: - upload_url: ${{ steps.release.outputs.upload_url }} - asset_path: ./PromiseKit-${{ github.event.inputs.version }}.framework.zip - asset_name: PromiseKit-${{ github.event.inputs.version }}.framework.zip - asset_content_type: application/zip - env: - GITHUB_TOKEN: ${{ github.token }} + PMKVersion: ${{ github.event.inputs.version }} - name: Seal Deployment uses: bobheadxi/deployments@v0.5.2 @@ -92,6 +48,10 @@ jobs: token: ${{ secrets.GITHUB_TOKEN }} env: docs + - run: echo "v=${v:0:1}" >> $GITHUB_ENV + env: + v: ${{ github.event.inputs.version }} + - uses: actions/checkout@v2 - run: gem install jazzy - run: | @@ -100,9 +60,9 @@ jobs: --module-version ${{ github.event.inputs.version }} - run: git remote update - run: git checkout gh-pages - - run: rm -rf reference/v6 - - run: mv output reference/v6 - - run: git add reference/v6 + - run: rm -rf reference/v$v + - run: mv output reference/v$v + - run: git add reference/v$v - run: git config user.name github-actions - run: git config user.email github-actions@github.com - run: git commit -m 'Updated docs for v${{ github.event.inputs.version }}' diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 574dbf8cb..8f4bad2dd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,117 +1,93 @@ name: CI on: - workflow_dispatch: pull_request: paths: - Sources/** - Tests/** - .github/workflows/ci.yml +concurrency: + group: ${{ github.head_ref }} + cancel-in-progress: true jobs: - auto-cancel: + lint: runs-on: ubuntu-latest steps: - - uses: technote-space/auto-cancel-redundant-job@v1 + - uses: harupy/find-trailing-whitespace@v1.0 linux: - needs: auto-cancel - runs-on: ubuntu-18.04 - strategy: - matrix: - swift: - - 4.0.3 - - 4.1.3 - - 4.2.4 - container: - image: swift:${{ matrix.swift }} - steps: - - uses: actions/checkout@v2 - - run: swift build -Xswiftc -warnings-as-errors -Xswiftc -swift-version -Xswiftc 3 - - run: swift build # generated linuxmain requires Swift 5 sadly - - linux-code-cov: - name: linux - needs: auto-cancel - runs-on: ubuntu-18.04 + runs-on: ubuntu-latest strategy: matrix: swift: - - 5.0.3 - - 5.1.5 - - 5.2.5 - - 5.3.3 - - 5.4.1 + - swift:5.3 + - swift:5.4 + - swiftlang/swift:nightly-5.5 container: - image: swift:${{ matrix.swift }} + image: ${{ matrix.swift }} steps: - uses: actions/checkout@v2 - - run: swift build -Xswiftc -warnings-as-errors -Xswiftc -swift-version -Xswiftc 4 - - run: swift build -Xswiftc -warnings-as-errors -Xswiftc -swift-version -Xswiftc 4.2 - - run: swift test --enable-code-coverage --parallel + - run: swift test --enable-code-coverage --parallel --enable-test-discovery - name: Generate Coverage Report - if: ${{ matrix.swift != '5.4.1' }} # fails for SOME REASON run: | apt-get -qq update - apt-get -qq install llvm-10 curl - export b=$(swift build --show-bin-path) && llvm-cov-10 \ - export -format lcov \ - -instr-profile=$b/codecov/default.profdata \ + apt-get -qq install curl # for codecov action 🙄 + b=$(swift build --show-bin-path) + llvm-cov export \ + -format lcov \ + -instr-profile="$b"/codecov/default.profdata \ --ignore-filename-regex='\.build/' \ - $b/*.xctest \ + "$b"/*.xctest \ > info.lcov - uses: codecov/codecov-action@v1 with: file: ./info.lcov - verify-linuxmain: - runs-on: macos-latest - name: linux (validate manifests) - steps: - - uses: actions/checkout@v2 - - run: swift test --generate-linuxmain - - run: git diff --exit-code - - test: - runs-on: macos-latest + apple: + runs-on: ${{ matrix.swift == '5.3' && 'macos-10.15' || 'macos-11' }} strategy: matrix: - dst: - - platform=macOS - - platform=tvOS Simulator,OS=14.3,name=Apple TV - - platform=iOS Simulator,OS=14.4,name=iPhone 12 + platform: + - macOS + - tvOS + - iOS + - watchOS + swift: + - 5.3 + - 5.4 + - 5.5 + name: ${{ matrix.platform }} (${{ matrix.swift }}) steps: - - uses: maxim-lobanov/setup-xcode@v1 - with: - xcode-version: 12.4 - uses: actions/checkout@v2 - - uses: sersoft-gmbh/xcodebuild-action@v1 + - run: | + cd Tests/A+/JavaScript + npm ci + npm run build + if: ${{ matrix.platform == 'macOS' }} + - uses: mxcl/xcodebuild@v1 with: - project: PromiseKit.xcodeproj - scheme: PromiseKit - destination: ${{ matrix.dst }} - action: test - enable-code-coverage: true + swift: ${{ matrix.swift }} + platform: ${{ matrix.platform }} + code-coverage: true + warnings-as-errors: true - uses: codecov/codecov-action@v1 - carthage: - runs-on: macos-latest - strategy: - matrix: - xcode: [^10, ^11, ^12] + windows: + runs-on: windows-latest steps: - - uses: maxim-lobanov/setup-xcode@v1 - with: - xcode-version: ${{ matrix.xcode }} - - uses: actions/checkout@v2 - - - uses: mingjun97/file-regex-replace@v1 - with: - regex: SWIFT_TREAT_WARNINGS_AS_ERRORS = NO - replacement: SWIFT_TREAT_WARNINGS_AS_ERRORS = YES - include: project.pbxproj - - - run: | - if [ ${{ matrix.xcode }} == ^12 ]; then - echo "CARTHAGE_ARGS=--use-xcframeworks" >> $GITHUB_ENV - fi - - run: carthage build --no-skip-current --no-use-binaries $CARTHAGE_ARGS + - uses: seanmiddleditch/gha-setup-vsdevenv@v3 + - run: | + Install-Binary -Url "https://swift.org/builds/swift-5.4.1-release/windows10/swift-5.4.1-RELEASE/swift-5.4.1-RELEASE-windows10.exe" -Name "installer.exe" -ArgumentList ("-q") + - run: | + echo "SDKROOT=C:\Library\Developer\Platforms\Windows.platform\Developer\SDKs\Windows.sdk" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append + echo "DEVELOPER_DIR=C:\Library\Developer" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append + - run: | + echo "C:\Library\Swift-development\bin;C:\Library\icu-67\usr\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append + echo "C:\Library\Developer\Toolchains\unknown-Asserts-development.xctoolchain\usr\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append + - run: | + Copy-Item "$env:SDKROOT\usr\share\ucrt.modulemap" -destination "$env:UniversalCRTSdkDir\Include\$env:UCRTVersion\ucrt\module.modulemap" + Copy-Item "$env:SDKROOT\usr\share\visualc.modulemap" -destination "$env:VCToolsInstallDir\include\module.modulemap" + Copy-Item "$env:SDKROOT\usr\share\visualc.apinotes" -destination "$env:VCToolsInstallDir\include\visualc.apinotes" + Copy-Item "$env:SDKROOT\usr\share\winsdk.modulemap" -destination "$env:UniversalCRTSdkDir\Include\$env:UCRTVersion\um\module.modulemap" + - uses: actions/checkout@v2 + - run: swift test --parallel diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index e4ea2c75e..21f6c6d92 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -3,71 +3,44 @@ on: workflow_dispatch: inputs: version: - description: Version to publish + description: Version 🚀 required: true jobs: - ci: + build: runs-on: ubuntu-latest + strategy: + matrix: + swift: + - 5.3 + - 5.4 + container: + image: swift:${{ matrix.swift }} steps: - - uses: aurelien-baudet/workflow-dispatch@v2 - with: - workflow: CI - token: ${{ secrets.JAZZY_PAT }} - wait-for-completion: true + - uses: actions/checkout@v2 + - run: swift build lint: - runs-on: macos-10.15 + runs-on: macos-latest strategy: matrix: xcode: - - ^10 - - ^11 - - ^12 + - '12.0' + - '12.4' steps: - uses: maxim-lobanov/setup-xcode@v1 with: xcode-version: ${{ matrix.xcode }} - uses: actions/checkout@v2 - with: - submodules: true - run: pod lib lint --fail-fast create-release: runs-on: ubuntu-latest - needs: [ci, lint] - env: - v: ${{ github.event.inputs.version }} + needs: [lint, build] steps: - uses: actions/checkout@v2 - with: - fetch-depth: 0 # zero means “all” (or push fails) - - name: Update committed versions - run: | - ruby -i -pe "sub(/CURRENT_PROJECT_VERSION = [0-9.]+/, 'CURRENT_PROJECT_VERSION = $v')" PromiseKit.xcodeproj/project.pbxproj - ruby -i -pe "sub(/s.version = '[0-9.]+'/, 's.version = \'$v\'')" PromiseKit.podspec - - run: | - ! (git diff --quiet) - - name: Commit - run: | - git config user.name github-actions - git config user.email github-actions@github.com - git commit -am "PromiseKit $v" - git push - uses: softprops/action-gh-release@v1 env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITHUB_TOKEN: ${{ secrets.JAZZY_PAT }} with: tag_name: ${{ github.event.inputs.version }} name: ${{ github.event.inputs.version }} - - cd: - needs: create-release - runs-on: ubuntu-latest - steps: - - uses: aurelien-baudet/workflow-dispatch@v2 - with: - workflow: CD - token: ${{ secrets.JAZZY_PAT }} - inputs: "{\"version\": \"${{ github.event.inputs.version }}\"}" - ref: master # or doesn’t use our new commit above - wait-for-completion: true diff --git a/.github/workflows/trigger-cd.yml b/.github/workflows/trigger-cd.yml new file mode 100644 index 000000000..1702f8699 --- /dev/null +++ b/.github/workflows/trigger-cd.yml @@ -0,0 +1,13 @@ +on: + release: + types: published +jobs: + cd: + runs-on: ubuntu-latest + steps: + - uses: aurelien-baudet/workflow-dispatch@v2 + with: + workflow: CD + token: ${{ secrets.JAZZY_PAT }} + inputs: "{\"version\": \"${{ github.event.release.tag_name }}\"}" + wait-for-completion: false diff --git a/.gitignore b/.gitignore index 6d14149ac..f699dd53e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,7 @@ -*.xcodeproj/**/xcuserdata/ -*.xcscmblueprint +/PromiseKit.xcodeproj /Carthage /.build .DS_Store -DerivedData -/Extensions/Carthage -/Tests/JS-A+/build +/build +/Tests/A+/JavaScript/build +/.swiftpm diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 9a18709e2..000000000 --- a/.gitmodules +++ /dev/null @@ -1,69 +0,0 @@ -[submodule "Extensions/Foundation"] - path = Extensions/Foundation - url = https://github.com/PromiseKit/Foundation.git -[submodule "Extensions/UIKit"] - path = Extensions/UIKit - url = https://github.com/PromiseKit/UIKit.git -[submodule "Extensions/Accounts"] - path = Extensions/Accounts - url = https://github.com/PromiseKit/Accounts.git -[submodule "Extensions/MessagesUI"] - path = Extensions/MessagesUI - url = https://github.com/PromiseKit/MessagesUI.git -[submodule "Extensions/WatchConnectivity"] - path = Extensions/WatchConnectivity - url = https://github.com/PromiseKit/WatchConnectivity.git -[submodule "Extensions/Photos"] - path = Extensions/Photos - url = https://github.com/PromiseKit/Photos.git -[submodule "Extensions/MapKit"] - path = Extensions/MapKit - url = https://github.com/PromiseKit/MapKit.git -[submodule "Extensions/CloudKit"] - path = Extensions/CloudKit - url = https://github.com/PromiseKit/CloudKit.git -[submodule "Extensions/AddressBook"] - path = Extensions/AddressBook - url = https://github.com/PromiseKit/AddressBook.git -[submodule "Extensions/AssetsLibrary"] - path = Extensions/AssetsLibrary - url = https://github.com/PromiseKit/AssetsLibrary.git -[submodule "Extensions/CoreLocation"] - path = Extensions/CoreLocation - url = https://github.com/PromiseKit/CoreLocation.git -[submodule "Extensions/QuartzCore"] - path = Extensions/QuartzCore - url = https://github.com/PromiseKit/QuartzCore.git -[submodule "Extensions/Social"] - path = Extensions/Social - url = https://github.com/PromiseKit/Social.git -[submodule "Extensions/StoreKit"] - path = Extensions/StoreKit - url = https://github.com/PromiseKit/StoreKit.git -[submodule "Extensions/Bolts"] - path = Extensions/Bolts - url = https://github.com/PromiseKit/Bolts.git -[submodule "Extensions/CoreBluetooth"] - path = Extensions/CoreBluetooth - url = https://github.com/PromiseKit/CoreBluetooth.git -[submodule "Extensions/EventKit"] - path = Extensions/EventKit - url = https://github.com/PromiseKit/EventKit.git -[submodule "Extensions/SystemConfiguration"] - path = Extensions/SystemConfiguration - url = https://github.com/PromiseKit/SystemConfiguration -[submodule "Extensions/Alamofire"] - path = Extensions/Alamofire - url = https://github.com/PromiseKit/Alamofire -[submodule "Extensions/OMGHTTPURLRQ"] - path = Extensions/OMGHTTPURLRQ - url = https://github.com/PromiseKit/OMGHTTPURLRQ -[submodule "Extensions/AVFoundation"] - path = Extensions/AVFoundation - url = https://github.com/PromiseKit/AVFoundation -[submodule "Extensions/HomeKit"] - path = Extensions/HomeKit - url = https://github.com/PromiseKit/HomeKit.git -[submodule "Extensions/HealthKit"] - path = Extensions/HealthKit - url = https://github.com/PromiseKit/PMKHealthKit diff --git a/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata b/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 919434a62..000000000 --- a/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 16223f286..000000000 --- a/.travis.yml +++ /dev/null @@ -1,30 +0,0 @@ -os: osx -language: swift -osx_image: xcode9.4 - -if: tag =~ /^[0-9]+\.[0-9]+\.[0-9]+/ - -stages: - - swiftpm - - carthage - -jobs: - include: - - &swiftpm - stage: swiftpm - osx_image: xcode9.4 - script: swift build - - <<: *swiftpm - osx_image: xcode10.3 - - <<: *swiftpm - osx_image: xcode11.6 - - - &carthage - stage: carthage - osx_image: xcode9.4 - install: sed -i '' "s/SWIFT_TREAT_WARNINGS_AS_ERRORS = NO;/SWIFT_TREAT_WARNINGS_AS_ERRORS = YES;/" *.xcodeproj/project.pbxproj - script: carthage build --no-skip-current - - <<: *carthage - osx_image: xcode10.3 - - <<: *carthage - osx_image: xcode11.6 diff --git a/Documentation/Installation.md b/Documentation/Installation.md deleted file mode 100644 index e0078ee1e..000000000 --- a/Documentation/Installation.md +++ /dev/null @@ -1,222 +0,0 @@ -# Xcode 8.3, 9.x or 10.x / Swift 3 or 4 - -We recommend Carthage over CocoaPods, but both installation methods are supported. - -## CocoaPods - -```ruby -use_frameworks! - -target "Change Me!" do - pod "PromiseKit", "~> 6.8" -end -``` - -If the generated Xcode project gives you a warning that PromiseKit needs to be upgraded to -Swift 4.0 or Swift 4.2, then add the following: - -```ruby -post_install do |installer| - installer.pods_project.targets.each do |target| - if target.name == 'PromiseKit' - target.build_configurations.each do |config| - config.build_settings['SWIFT_VERSION'] = '4.2' - end - end - end -end -``` - -Adjust the value for `SWIFT_VERSION` as needed. - -CocoaPods are aware of this [issue](https://github.com/CocoaPods/CocoaPods/issues/7134). - -## Carthage - -```ruby -github "mxcl/PromiseKit" ~> 6.8 -``` - -> Please note, since PromiseKit 6.8.1 our Carthage support has transitioned to -> Swift 4 and above only. Strictly we *do* still support Swift 3.1 for Carthage, -> and if you like you could edit the PromiseKit `project.pbxproj` file during -> `carthage bootstrap` to make this possible. This change was involuntary and due -> to Xcode 10.2 dropping support for Swift 3. - -From Xcode 12, you will likely need to build using `--use-xcframeworks`, eg: - - carthage build --use-xcframeworks - -## Accio - -Add the following to your Package.swift: - -```swift -.package(url: "https://github.com/mxcl/PromiseKit.git", .upToNextMajor(from: "6.8.4")), -``` - -Next, add `PromiseKit` to your App targets dependencies like so: - -```swift -.target( - name: "App", - dependencies: [ - "PromiseKit", - ] -), -``` - -Then run `accio update`. - -## SwiftPM - -```swift -package.dependencies.append( - .package(url: "https://github.com/mxcl/PromiseKit", from: "6.8.0") -) -``` - -## Manually - -You can just drop `PromiseKit.xcodeproj` into your project and then add -`PromiseKit.framework` to your app’s embedded frameworks. - - -# PromiseKit vs. Xcode - -PromiseKit contains Swift, so there have been rev-lock issues with Xcode: - -| PromiseKit | Swift | Xcode | CI Status | Release Notes | -| ---------- | ----------------------- | -------- | ------------ | ----------------- | -| 6 | 3.2, 3.3, 4.x, 5.x | 8.3, 9.x, 10.x | ![ci-master] | [2018/02][news-6] | -| 5 | 3.1, 3.2, 3.3, 4.x | 8.3, 9.x, 10.1 | *Deprecated* | *n/a* | -| 4 | 3.0, 3.1, 3.2, 3.3, 4.x | 8.x, 9.x, 10.1 | ![ci-master] | [2016/09][news-4] | -| 3 | 2.x | 7.x, 8.0 | ![ci-swift2] | [2015/10][news-3] | -| 2 | 1.x | 7.x | *Deprecated* | [2015/10][news-3] | -| 1† | *N/A* | * | ![ci-legacy] | – | - -† PromiseKit 1 is pure Objective-C and thus can be used with any Xcode, it is -also your only choice if you need to support iOS 7 or below. - ---- - -We also maintain a series of branches to aid migration for PromiseKit 2: - -| Xcode | Swift | PromiseKit | Branch | CI Status | -| ----- | ----- | -----------| --------------------------- | --------- | -| 8.0 | 2.3 | 2 | [swift-2.3-minimal-changes] | ![ci-23] | -| 7.3 | 2.2 | 2 | [swift-2.2-minimal-changes] | ![ci-22] | -| 7.2 | 2.2 | 2 | [swift-2.2-minimal-changes] | ![ci-22] | -| 7.1 | 2.1 | 2 | [swift-2.0-minimal-changes] | ![ci-20] | -| 7.0 | 2.0 | 2 | [swift-2.0-minimal-changes] | ![ci-20] | - -We do **not** usually backport fixes to these branches, but pull requests are welcome. - - -## Xcode 8 / Swift 2.3 or Xcode 7 - -```ruby -# CocoaPods -swift_version = "2.3" -pod "PromiseKit", "~> 3.5" - -# Carthage -github "mxcl/PromiseKit" ~> 3.5 -``` - - -[travis]: https://travis-ci.org/mxcl/PromiseKit -[ci-master]: https://travis-ci.org/mxcl/PromiseKit.svg?branch=master -[ci-legacy]: https://travis-ci.org/mxcl/PromiseKit.svg?branch=legacy-1.x -[ci-swift2]: https://travis-ci.org/mxcl/PromiseKit.svg?branch=swift-2.x -[ci-23]: https://travis-ci.org/mxcl/PromiseKit.svg?branch=swift-2.3-minimal-changes -[ci-22]: https://travis-ci.org/mxcl/PromiseKit.svg?branch=swift-2.2-minimal-changes -[ci-20]: https://travis-ci.org/mxcl/PromiseKit.svg?branch=swift-2.0-minimal-changes -[news-2]: http://mxcl.dev/PromiseKit/news/2015/05/PromiseKit-2.0-Released/ -[news-3]: https://github.com/mxcl/PromiseKit/blob/212f31f41864d1e3ec54f5dd529bd8e1e5697024/CHANGELOG.markdown#300-oct-1st-2015 -[news-4]: http://mxcl.dev/PromiseKit/news/2016/09/PromiseKit-4.0-Released/ -[news-6]: http://mxcl.dev/PromiseKit/news/2018/02/PromiseKit-6.0-Released/ -[swift-2.3-minimal-changes]: https://github.com/mxcl/PromiseKit/tree/swift-2.3-minimal-changes -[swift-2.2-minimal-changes]: https://github.com/mxcl/PromiseKit/tree/swift-2.2-minimal-changes -[swift-2.0-minimal-changes]: https://github.com/mxcl/PromiseKit/tree/swift-2.0-minimal-changes - - -# Using Git Submodules for PromiseKit’s Extensions - -> *Note*: This is a more advanced technique. - -If you use CocoaPods and a few PromiseKit extensions, then importing PromiseKit -causes that module to import all the extension frameworks. Thus, if you have an -app and a few app extensions (e.g., iOS app, iOS watch extension, iOS Today -extension) then all your final products that use PromiseKit will have forced -dependencies on all the Apple frameworks that PromiseKit provides extensions -for. - -This isn’t that bad, but every framework that loads entails overhead and -lengthens startup time. - -It’s both better and worse with Carthage. We build individual micro-frameworks -for each PromiseKit extension, so your final products link -against only the Apple frameworks that they actually need. However, Apple has -advised that apps link only against “about 12” frameworks for performance -reasons. So with Carthage, we are worse off on this metric. - -The solution is to instead import only CorePromise: - -```ruby -# CocoaPods -pod "PromiseKit/CorePromise" - -# Carthage -github "mxcl/PromiseKit" -# ^^ for Carthage *only* have this -``` - -And to use the extensions you need via `git submodules`: - -``` -git submodule init -git submodule add https://github.com/PromiseKit/UIKit Submodules/PMKUIKit -``` - -Then in Xcode you can add these sources to your targets on a per-target basis. - -Then when you `pod update`, ensure that you also update your submodules: - - pod update && git submodule update --recursive --remote - - - -# Release History - -## [6.0](https://github.com/mxcl/PromiseKit/releases/tag/6.0.0) Feb 13th, 2018 - -* [PromiseKit 6 announcement post][news-6]. - -## [4.0](https://github.com/mxcl/PromiseKit/releases/tag/4.0.0) - -* [PromiseKit 4 announcement post][news-4]. - -## [3.0](https://github.com/mxcl/PromiseKit/releases/tag/3.0.0) Oct 1st, 2015 - -In Swift 2.0 `catch` and `defer` became reserved keywords mandating we rename -our functions with these names. This forced a major semantic version change on -PromiseKit and thus we took the opportunity to make other minor (source -compatibility breaking) improvements. - -Thus if you cannot afford to adapt to PromiseKit 3 but still want to use -Xcode-7.0/Swift-2.0 we provide a [minimal changes branch] where `catch` and -`defer` are renamed `catch_` and `defer_` and all other changes are the bare -minimum to make PromiseKit 2 compile against Swift 2. - -If you still are using Xcode 6 and Swift 1.2 then use PromiseKit 2. - -[minimal changes branch]: https://github.com/mxcl/PromiseKit/tree/swift-2.0-minimal-changes - -## [2.0](https://github.com/mxcl/PromiseKit/releases/tag/2.0.0) May 14th, 2015 - -[PromiseKit 2 announcement post](http://mxcl.dev/PromiseKit/news/2015/05/PromiseKit-2.0-Released/). - -## [1.5](https://github.com/mxcl/PromiseKit/releases/tag/1.5.0) - -Swift 1.2 support. Xcode 6.3 required. diff --git a/Documentation/ObjectiveC.md b/Documentation/ObjectiveC.md deleted file mode 100644 index 5d8c6827e..000000000 --- a/Documentation/ObjectiveC.md +++ /dev/null @@ -1,219 +0,0 @@ -# Objective-C - -PromiseKit has two promise classes: - -* `Promise` (Swift) -* `AnyPromise` (Objective-C) - -Each is designed to be an appropriate promise implementation for the strong points of its language: - -* `Promise` is strict, defined and precise. -* `AnyPromise` is loose and dynamic. - -Unlike most libraries, we have extensive bridging support, you can use PromiseKit -in mixed projects with mixed language targets and mixed language libraries. - - -# Using PromiseKit with Objective-C - -`AnyPromise` is our promise class for Objective-C. It behaves almost identically to `Promise`, our Swift promise class. - -```objc -myPromise.then(^(NSString *bar){ - return anotherPromise; -}).then(^{ - //… -}).catch(^(NSError *error){ - //… -}); -``` - -You make new promises using `promiseWithResolverBlock`: - -```objc -- (AnyPromise *)myPromise { - return [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve){ - resolve(foo); // if foo is an NSError, rejects, else, resolves - }]; -} -``` - ---- - -You reject promises by throwing errors: - -```objc -myPromise.then(^{ - @throw [NSError errorWithDomain:domain code:code userInfo:nil]; -}).catch(^(NSError *error){ - //… -}); -``` - -One important feature is the syntactic flexibility of your handlers: - -```objc -myPromise.then(^{ - // no parameters is fine -}); - -myPromise.then(^(id foo){ - // one parameter is fine -}); - -myPromise.then(^(id a, id b, id c){ - // up to three parameter is fine, no crash! -}); - -myPromise.then(^{ - return @1; // return anything or nothing, it's fine, no crash -}); -``` - -We do runtime inspection of the block you pass to achieve this magic. - ---- - -Another important distinction is that the equivalent function to Swift’s `recover` is combined with `AnyPromise`’s `catch`. This is typical to other “dynamic” promise implementations and thus achieves our goal that `AnyPromise` is loose and dynamic while `Promise` is strict and specific. - -A sometimes unexpected consequence of this fact is that returning nothing from a `catch` *resolves* the returned promise: - -```objc -myPromise.catch(^{ - [UIAlertView …]; -}).then(^{ - // always executes! -}); -``` - ---- - -Another important distinction is that the `value` property returns even if the promise is rejected; in that case, it returns the `NSError` object with which the promise was rejected. - - -# Bridging Between Objective-C & Swift - -Let’s say you have: - -```objc -@interface Foo -- (AnyPromise *)myPromise; -@end -``` - -Ensure that this interface is included in your bridging header. You can now use the -following pattern in your Swift code: - -```swift -let foo = Foo() -foo.myPromise.then { (obj: AnyObject?) -> Int in - // it is not necessary to specify the type of `obj` - // we just do that for demonstrative purposes -} -``` - ---- - -Let’s say you have: - -```swift -@objc class Foo: NSObject { - func stringPromise() -> Promise - func barPromise() -> Promise -} - -@objc class Bar: NSObject { /*…*/ } -``` - -Ensure that your project is generating a `…-Swift.h` header so that Objective-C can see your Swift code. - -If you built this project and opened the `…-Swift.h` header, you would only see this: - -```objc -@interface Foo -@end - -@interface Bar -@end -``` - -That's because Objective-C cannot import Swift objects that are generic. So we need to write some stubs: - -```swift -@objc class Foo: NSObject { - @objc func stringPromise() -> AnyPromise { - return AnyPromise(stringPromise()) - } - @objc func barPromise() -> AnyPromise { - return AnyPromise(barPromise()) - } -} -``` - -If we built this and opened our generated header, we would now see: - -```objc -@interface Foo -- (AnyPromise *)stringPromise; -- (AnyPromise *)barPromise; -@end - -@interface Bar -@end -``` - -Perfect. - -Note that AnyPromise can only bridge objects that conform to `AnyObject` or derive from `NSObject`. This is a limitation of Objective-C. - -# Using ObjC AnyPromises from Swift - -Simply use them, the type of your handler parameter is `Any`: - -```objective-c -- (AnyPromise *)fetchThings { - return [AnyPromise promiseWithValue:@[@"a", @"b", @"c"]]; -} -``` - -Since ObjC is not type-safe and Swift is, you will (probably) need to cast the `Any` to whatever it is you actually are feeding: - -```swift -Foo.fetchThings().done { any in - let bar = any as! [String] -} -``` - -## :warning: Caution: - -ARC in Objective-C, unlike in Objective-C++, is not exception-safe by default. -So, throwing an error will result in keeping a strong reference to the closure -that contains the throw statement. -This pattern will consequently result in memory leaks if you're not careful. - -> *Note:* Only having a strong reference to the closure would result in memory leaks. -> In our case, PromiseKit automatically keeps a strong reference to the closure until it's released. - -__Workarounds:__ - -1. Return a Promise with value NSError\ -Instead of throwing a normal error, you can return a Promise with value NSError instead. - -```objc -myPromise.then(^{ - return [AnyPromise promiseWithValue:[NSError myCustomError]]; -}).catch(^(NSError *error){ - if ([error isEqual:[NSError myCustomError]]) { - // In case, same error as the one we thrown - return; - } - //… -}); -``` -2. Enable ARC for exceptions in Objective-C (not recommended)\ -You can add this ```-fobjc-arc-exceptions to your``` to your compiler flags to enable ARC for exceptions. -This is not recommended unless you've read the Apple documentation and are comfortable with the caveats. - -For more details on ARC and exceptions: -https://clang.llvm.org/docs/AutomaticReferenceCounting.html#exceptions - diff --git a/Documentation/Appendix.md b/Documents/Appendix.md similarity index 69% rename from Documentation/Appendix.md rename to Documents/Appendix.md index d3797f4d9..cf67c2504 100644 --- a/Documentation/Appendix.md +++ b/Documents/Appendix.md @@ -209,3 +209,45 @@ its work on a background thread. Promises abstract asynchronicity, so exploit and support that model. Design your APIs so that consumers don’t have to care what queue your functions run on. + +## `Dispatcher` Objects + +Some issues are best addressed at the level of dispatching. For example, you may need +to perform a series of HTTP transactions on a server that allows only a certain number of +API calls per minute. Or, you might want to allow only a certain number of memory-hungry +background tasks to run at once. These aren't really promise-level concerns; they just have +to do with the details of how closures are invoked once they become eligible to run. + +Unfortunately, `DispatchQueue`s don't directly support these types of restrictions, and because +of the way `DispatchQueue` is implemented, you can't create your own subclasses. PromiseKit 7 +adds an abstract `Dispatcher` protocol that generalizes the idea of a dispatch queue and allows for +alternate implementations: + +```swift +public protocol Dispatcher { + func dispatch(_ body: @escaping () -> Void) +} +``` + +Anywhere in PromiseKit that you can use a `DispatchQueue`, you're free to substitute a `Dispatcher`. + +PromiseKit doesn't care how you implement `dispatch()`. You can run the provided closure synchronously or +asynchronously, now or at some point in the future, on any thread you wish. Of course, your own code +must have a thread safety strategy and not create deadlocks. + +If you're setting a default dispatcher, assign your dispatcher to `PromiseKit.conf.D` rather than `PromiseKit.conf.Q`; the latter +accepts only `DispatchQueue`s. + +**FIXME: Check locations and availability of Dispatcher implementations before release** + +A few handy `Dispatcher` types are available in the `Dispatchers` extension library: + +* `RateLimitedDispatcher` implements general dispatch rate limits with an approximate "token bucket" strategy. +* `StrictRateLimitedDispatcher` is an exact and optimal "sliding window" rate limiter, but requires O(n) space (n = # of events/time) +* `ConcurrencyLimitedDispatcher` allows only *n* asynchronous closures to run at once. +* `CoreDataDispatcher` lets you dispatch onto threads associated with `NSManagedObjectContext`s. + +A couple of `Dispatcher`s are also included in the PromiseKit core: + +* `CurrentThreadDispatcher` runs closures immediately, on the current thread. +* `DispatchQueueDispatcher` forwards to a `DispatchQueue`, applying a static `DispatchGroup`, quality of service, and flag set. diff --git a/Documents/Cancel.md b/Documents/Cancel.md new file mode 100644 index 000000000..3ee4943cb --- /dev/null +++ b/Documents/Cancel.md @@ -0,0 +1,469 @@ +# Cancelling Promises + +PromiseKit 7 adds clear and concise cancellation abilities to promises and to the [PromiseKit extensions](#extensions-pane). Cancelling promises and their associated tasks is now simple and straightforward. Promises and promise chains can safely and efficiently be cancelled from any thread at any time. + +```swift +UIApplication.shared.isNetworkActivityIndicatorVisible = true + +let fetchImage = URLSession.shared.dataTask(.promise, with: url) + .cancellize() + .compactMap{ UIImage(data: $0.data) } +let fetchLocation = CLLocationManager.requestLocation().cancellize().lastValue + +let finalizer = firstly { + when(fulfilled: fetchImage, fetchLocation) +}.done { image, location in + self.imageView.image = image + self.label.text = "\(location)" +}.ensure { + UIApplication.shared.isNetworkActivityIndicatorVisible = false +}.catch(policy: .allErrors) { error in + // `catch` will be invoked with `PMKError.cancelled` when cancel is called + // on the context. Use the default policy of `.allErrorsExceptCancellation` + // to ignore cancellation errors. + self.show(UIAlertController(for: error), sender: self) +} + +//… + +// Cancel currently active tasks and reject all cancellable promises +// with 'PMKError.cancelled'. `cancel()` can be called from any thread +// at any time. +finalizer.cancel() + +// `finalizer` here refers to the `CancellableFinalizer` for the chain. +// Calling 'cancel' on any promise in the chain or on the finalizer +// cancels the entire chain. Therefore calling `cancel` on the finalizer +// cancels everything. +``` + +# Cancel Chains + +Promises can be cancelled using a `CancellablePromise`. The `cancellize()` method on `Promise` is used to convert a `Promise` into a `CancellablePromise`. If a promise chain is initialized with a `CancellablePromise`, then the entire chain is cancellable. Calling `cancel()` on any promise in the chain cancels the entire chain. + +Creating a chain where the entire chain can be cancelled is the recommended usage for cancellable promises. + +The `CancellablePromise` contains a `CancelContext` that keeps track of the tasks and promises for the chain. Promise chains can be cancelled either by calling the `cancel()` method on any `CancellablePromise` in the chain, or by calling `cancel()` on the `CancelContext` for the chain. It may be desirable to hold on to the `CancelContext` directly rather than a promise so that the promise can be deallocated by ARC when it is resolved. + +For example: + +```swift +let context = firstly { + login() + /* The 'Thenable.cancellize' method initiates a cancellable promise chain by + returning a 'CancellablePromise'. */ +}.cancellize().then { creds in + fetch(avatar: creds.user) +}.done { image in + self.imageView = image +}.catch(policy: .allErrors) { error in + if error.isCancelled { + // the chain has been cancelled! + } +}.cancelContext + +// … + +/* Note: Promises can be cancelled using the 'cancel()' method on the 'CancellablePromise'. + However, it may be desirable to hold on to the 'CancelContext' directly rather than a + promise so that the promise can be deallocated by ARC when it is resolved. */ +context.cancel() +``` + +### Creating a partially cancellable chain + +A `CancellablePromise` can be placed at the start of a chain, but it cannot be embedded directly in the middle of a standard (non-cancellable) promise chain. Instead, a partially cancellable promise chain can be used. A partially cancellable chain is not the recommended way to use cancellable promises, although there may be cases where this is useful. + +**Convert a cancellable chain to a standard chain** + +`CancellablePromise` wraps a delegate `Promise`, which can be accessed with the `promise` property. The above example can be modified as follows so that once `login()` completes, the chain can no longer be cancelled: + +```swift +/* Here, by calling 'promise.then' rather than 'then' the chain is converted from a cancellable + promise chain to a standard promise chain. In this example, calling 'cancel()' during 'login' + will cancel the chain but calling 'cancel()' during the 'fetch' operation will have no effect: */ +let cancellablePromise = firstly { + login().cancellize() +} +cancellablePromise.promise.then { + fetch(avatar: creds.user) +}.done { image in + self.imageView = image +}.catch(policy: .allErrors) { error in + if error.isCancelled { + // the chain has been cancelled! + } +} + +// … + +/* This will cancel the 'login' but will not cancel the 'fetch'. So whether or not the + chain is cancelled depends on how far the chain has progressed. */ +cancellablePromise.cancel() +``` + +**Convert a standard chain to a cancellable chain** + +A non-cancellable chain can be converted to a cancellable chain in the middle of the chain as follows: + +```swift +/* In this example, calling 'cancel()' during 'login' will not cancel the login. However, + the chain will be cancelled immediately, and the 'fetch' will not be executed. If 'cancel()' + is called during the 'fetch' then both the 'fetch' itself and the promise chain will be + cancelled immediately. */ +let promise = firstly { + login() +}.then { + fetch(avatar: creds.user).cancellize() +}.done { image in + self.imageView = image +}.catch(policy: .allErrors) { error in + if error.isCancelled { + // the chain has been cancelled! + } +} + +// … + +promise.cancel() +``` + +# Core Cancellable PromiseKit API + +The following classes, methods and functions have been added to PromiseKit to support cancellation. Existing functions or methods with underlying tasks that can be cancelled are indicated by being appended with '.cancellize()'. + +
Thenable
+    cancellize(_:)                 - Converts the Promise or Guarantee (Thenable) into a
+                                     CancellablePromise, which is a cancellable variant of the given
+                                     Promise or Guarantee (Thenable)
+
+Global functions
+    after(seconds:).cancellize()   - 'after' with seconds can be cancelled
+    after(_:).cancellize           - 'after' with interval can be cancelled
+
+    firstly(execute:)               - Accepts body returning Promise or CancellablePromise
+    hang(_:)                        - Accepts Promise and CancellablePromise
+    race(_:)                        - Accepts [Promise] and [CancellablePromise]
+    when(fulfilled:)                - Accepts [Promise] and [CancellablePromise]
+    when(fulfilled:concurrently:)   - Accepts iterator of type Promise or CancellablePromise
+    when(resolved:)                 - Accepts [Promise] and [CancellablePromise]
+
+CancellablePromise properties and methods
+    promise                         - Delegate Promise for this CancellablePromise
+    result                          - The current Result
+
+    init(_ bridge:cancelContext:)   - Initialize a new cancellable promise bound to the provided Thenable
+    init(cancellable:resolver body:).  - Initialize a new cancellable promise that can be resolved with
+                                       the provided '(Resolver) throws -> Void' body
+    init(cancellable:promise:resolver:)  - Initialize a new cancellable promise using the given Promise
+                                       and its Resolver
+    init(cancellable:error:)          - Initialize a new rejected cancellable promise
+    init(cancellable:)                - Initializes a new cancellable promise fulfilled with Void
+
+    pending() -> (promise:resolver:)  - Returns a tuple of a new cancellable pending promise and its
+                                        Resolver
+
+CancellableThenable properties and methods
+    thenable                        - Delegate Thenable for this CancellableThenable
+
+    cancel(error:)                  - Cancels all members of the promise chain
+    cancelContext                   - The CancelContext associated with this CancellableThenable
+    cancelItemList                  - Tracks the cancel items for this CancellableThenable
+    isCancelled                     - True if all members of the promise chain have been successfully
+                                      cancelled, false otherwise
+    cancelAttempted                 - True if 'cancel' has been called on the promise chain associated
+                                      with this CancellableThenable, false otherwise
+    cancelledError                  - The error generated when the promise is cancelled
+    appendCancellable(cancellable:reject:)  - Append the Cancellable task to our cancel context
+    appendCancelContext(from:)      - Append the cancel context associated with 'from' to our
+                                      CancelContext
+
+    then(on:flags:_ body:)           - Accepts body returning CancellableThenable
+    cancellableThen(on:flags:_ body:)  - Accepts body returning Thenable
+    map(on:flags:_ transform:)
+    compactMap(on:flags:_ transform:)
+    done(on:flags:_ body:)
+    get(on:flags:_ body:)
+    tap(on:flags:_ body:)
+    asVoid()
+
+    error
+    isPending
+    isResolved
+    isFulfilled
+    isRejected
+    value
+
+    mapValues(on:flags:_ transform:)
+    flatMapValues(on:flags:_ transform:)
+    compactMapValues(on:flags:_ transform:)
+    thenMap(on:flags:_ transform:)                 - Accepts transform returning CancellableThenable
+    cancellableThenMap(on:flags:_ transform:)      - Accepts transform returning Thenable
+    thenFlatMap(on:flags:_ transform:)             - Accepts transform returning CancellableThenable
+    cancellableThenFlatMap(on:flags:_ transform:)  - Accepts transform returning Thenable
+    filterValues(on:flags:_ isIncluded:)
+    firstValue
+    lastValue
+    sortedValues(on:flags:)
+
+CancellableCatchable properties and methods
+    catchable                                      - Delegate Catchable for this CancellableCatchable
+    catch(on:flags:policy::_ body:)                - Accepts body returning Void
+    recover(on:flags:policy::_ body:)              - Accepts body returning CancellableThenable
+    cancellableRecover(on:flags:policy::_ body:)   - Accepts body returning Thenable
+    ensure(on:flags:_ body:)                       - Accepts body returning Void
+    ensureThen(on:flags:_ body:)                   - Accepts body returning CancellablePromise
+    finally(_ body:)
+    cauterize()
+
+ +# Extensions + +Cancellation support has been added to the PromiseKit extensions, but only where the underlying asynchronous tasks can be cancelled. This example Podfile lists the PromiseKit extensions that support cancellation along with a usage example: + +
pod "PromiseKit/Alamofire"
+# Alamofire.request("http://example.com", method: .get).responseDecodable(DecodableObject.self).cancellize()
+
+pod "PromiseKit/Bolts"
+# CancellablePromise(…).then() { _ -> BFTask in /*…*/ }  // Returns CancellablePromise
+
+pod "PromiseKit/CoreLocation"
+# CLLocationManager.requestLocation().cancellize().then { /*…*/ }
+
+pod "PromiseKit/Foundation"
+# URLSession.shared.dataTask(.promise, with: request).cancellize().then { /*…*/ }
+
+pod "PromiseKit/MapKit"
+# MKDirections(…).calculate().cancellize().then { /*…*/ }
+
+pod "PromiseKit/OMGHTTPURLRQ"
+# URLSession.shared.GET("http://example.com").cancellize().then { /*…*/ }
+
+pod "PromiseKit/StoreKit"
+# SKProductsRequest(…).start(.promise).cancellize().then { /*…*/ }
+
+pod "PromiseKit/SystemConfiguration"
+# SCNetworkReachability.promise().cancellize().then { /*…*/ }
+
+pod "PromiseKit/UIKit"
+# UIViewPropertyAnimator(…).startAnimation(.promise).cancellize().then { /*…*/ }
+
+ +Here is a complete list of PromiseKit extension methods that support cancellation: + +[Alamofire](http://github.com/PromiseKit/Alamofire-) + +
Alamofire.DataRequest
+    response(_:queue:).cancellize()
+    responseData(queue:).cancellize()
+    responseString(queue:).cancellize()
+    responseJSON(queue:options:).cancellize()
+    responsePropertyList(queue:options:).cancellize()
+    responseDecodable(queue::decoder:).cancellize()
+    responseDecodable(_ type:queue:decoder:).cancellize()
+
+Alamofire.DownloadRequest
+    response(_:queue:).cancellize()
+    responseData(queue:).cancellize()
+
+ +[Bolts](http://github.com/PromiseKit/Bolts) + +
CancellablePromise<T>
+    then<U>(on: DispatchQueue?, body: (T) -> BFTask<U>) -> CancellablePromise
+
+ +[CoreLocation](http://github.com/PromiseKit/CoreLocation) + +
CLLocationManager
+    requestLocation(authorizationType:satisfying:).cancellize()
+    requestAuthorization(type requestedAuthorizationType:).cancellize()
+
+ +[Foundation](http://github.com/PromiseKit/Foundation) + +
NotificationCenter:
+    observe(once:object:).cancellize()
+
+NSObject
+    observe(_:keyPath:).cancellize()
+
+Process
+    launch(_:).cancellize()
+
+URLSession
+    dataTask(_:with:).cancellize()
+    uploadTask(_:with:from:).cancellize()
+    uploadTask(_:with:fromFile:).cancellize()
+    downloadTask(_:with:to:).cancellize()
+
+CancellablePromise
+    validate()
+
+ +[HomeKit](http://github.com/PromiseKit/HomeKit) + +
HMPromiseAccessoryBrowser
+    start(scanInterval:).cancellize()
+
+HMHomeManager
+    homes().cancellize()
+
+ +[MapKit](http://github.com/PromiseKit/MapKit) + +
MKDirections
+    calculate().cancellize()
+    calculateETA().cancellize()
+
+MKMapSnapshotter
+    start().cancellize()
+
+ +[StoreKit](http://github.com/PromiseKit/StoreKit) + +
SKProductsRequest
+    start(_:).cancellize()
+
+SKReceiptRefreshRequest
+    promise().cancellize()
+
+ +[SystemConfiguration](http://github.com/PromiseKit/SystemConfiguration) + +
SCNetworkReachability
+    promise().cancellize()
+
+ +[UIKit](http://github.com/PromiseKit/UIKit) + +
UIViewPropertyAnimator
+    startAnimation(_:).cancellize()
+
+ +## Choose Your Networking Library + +All the networking library extensions supported by PromiseKit are now simple to cancel! + +[Alamofire](http://github.com/PromiseKit/Alamofire-) + +```swift +// pod 'PromiseKit/Alamofire' +// # https://github.com/PromiseKit/Alamofire + +let context = firstly { + Alamofire + .request("http://example.com", method: .post, parameters: params) + .responseDecodable(Foo.self) +}.cancellize().done { foo in + //… +}.catch { error in + //… +}.cancelContext + +//… + +context.cancel() +``` + +And (of course) plain `URLSession` from [Foundation](http://github.com/PromiseKit/Foundation): + +```swift +// pod 'PromiseKit/Foundation' +// # https://github.com/PromiseKit/Foundation + +let context = firstly { + URLSession.shared.dataTask(.promise, with: try makeUrlRequest()) +}.cancellize().map { + try JSONDecoder().decode(Foo.self, with: $0.data) +}.done { foo in + //… +}.catch { error in + //… +}.cancelContext + +//… + +context.cancel() + +func makeUrlRequest() throws -> URLRequest { + var rq = URLRequest(url: url) + rq.httpMethod = "POST" + rq.addValue("application/json", forHTTPHeaderField: "Content-Type") + rq.addValue("application/json", forHTTPHeaderField: "Accept") + rq.httpBody = try JSONSerialization.jsonData(with: obj) + return rq +} +``` + +# Cancellability Goals + +* Provide a streamlined way to cancel a promise chain, which rejects all associated promises and cancels all associated tasks. For example: + +```swift +let promise = firstly { + login() +}.cancellize().then { creds in // Use the 'cancellize' function to initiate a cancellable promise chain + fetch(avatar: creds.user) +}.done { image in + self.imageView = image +}.catch(policy: .allErrors) { error in + if error.isCancelled { + // the chain has been cancelled! + } +} +//… +promise.cancel() +``` + +* Ensure that subsequent code blocks in a promise chain are _never_ called after the chain has been cancelled + +* Fully support concurrency, where all code is thread-safe. Cancellable promises and promise chains can safely and efficiently be cancelled from any thread at any time. + +* Provide cancellable support for all PromiseKit extensions whose native tasks can be cancelled (e.g. Alamofire, Bolts, CoreLocation, Foundation, HealthKit, HomeKit, MapKit, StoreKit, SystemConfiguration, UIKit) + +* Support cancellation for all PromiseKit primitives such as 'after', 'firstly', 'when', 'race' + +* Provide a simple way to make new types of cancellable promises + +* Ensure promise branches are properly cancelled. For example: + +```swift +import Alamofire +import PromiseKit + +func updateWeather(forCity searchName: String) { + refreshButton.startAnimating() + let context = firstly { + getForecast(forCity: searchName) + }.cancellize().done { response in + updateUI(forecast: response) + }.ensure { + refreshButton.stopAnimating() + }.catch { error in + // Cancellation errors are ignored by default + showAlert(error: error) + }.cancelContext + + //… + + /* **** Cancels EVERYTHING (except... the 'ensure' block always executes regardless) + Note: non-cancellable tasks cannot be interrupted. For example: if 'cancel()' is + called in the middle of 'updateUI()' then the chain will immediately be rejected, + however the 'updateUI' call will complete normally because it is not cancellable. + Its return value (if any) will be discarded. */ + context.cancel() +} + +func getForecast(forCity name: String) -> CancellablePromise { + return firstly { + Alamofire.request("https://autocomplete.weather.com/\(name)") + .responseDecodable(AutoCompleteCity.self) + }.cancellize().then { city in + Alamofire.request("https://forecast.weather.com/\(city.name)") + .responseDecodable(WeatherResponse.self).cancellize() + }.map { response in + format(response) + } +} +``` diff --git a/Documentation/CommonPatterns.md b/Documents/CommonPatterns.md similarity index 85% rename from Documentation/CommonPatterns.md rename to Documents/CommonPatterns.md index 937a425f4..bcb0ff71a 100644 --- a/Documentation/CommonPatterns.md +++ b/Documents/CommonPatterns.md @@ -82,8 +82,10 @@ class MyRestAPI { } ``` -All PromiseKit handlers take an `on` parameter that lets you designate the dispatch queue -on which to run the handler. The default is always the main queue. +All PromiseKit handlers take an `on` parameter that lets you designate a `Dispatcher` that +will run the handler. Usually, the dispatcher is just a plain-vanilla `DispatchQueue`, but you +can write your own if you like. The default is always `DispatchQueue.main`, which is a +serial (nonconcurrent) queue. PromiseKit is *entirely* thread safe. @@ -212,22 +214,42 @@ one promise at a time if you need to. ```swift let fetches: [Promise] = makeFetches() -let timeout = after(seconds: 4) -race(when(fulfilled: fetches).asVoid(), timeout).then { +race(when(fulfilled: fetches).asVoid(), timeout(seconds: 4)).then { //… +}.catch(policy: .allErrors) { + // Rejects with 'PMKError.timedOut' if the timeout is exceeded } ``` `race` continues as soon as one of the promises it is watching finishes. +`timeout(seconds: TimeInterval)` returns a promise that throws +`PMKError.timedOut` when the time interval is exceeded. Note that `PMKError.timedOut` +is a cancellation error therefore the `.allErrors` catch policy must be specified +to handle this exception. + Make sure the promises you pass to `race` are all of the same type. The easiest way to ensure this is to use `asVoid()`. Note that if any component promise rejects, the `race` will reject, too. +When used with cancellable promises, all promises will be cancelled if either the timeout is +exceeded or if any promise rejects. + +```swift +let fetches: [Promise] = makeFetches() +let cancellableFetches: [CancellablePromise] = fetches.map { return $0.cancellize() } + +// All promises are automatically cancelled if any of them reject. +race(when(fulfilled: cancellableFetches).asVoid(), timeout(seconds: 4).cancellize()).then { + //… +}.catch(policy: .allErrors) { + // Rejects with 'PMKError.timedOut' if the timeout is exceeded. +} +``` -# Minimum Duration +## Minimum Duration Sometimes you need a task to take *at least* a certain amount of time. (For example, you want to show a progress spinner, but if it shows for less than 0.3 seconds, the UI @@ -245,61 +267,22 @@ firstly { } ``` -The code above works because we create the delay *before* we do work in `foo()`. By the +The code above works because we create the delay *before* we do work in `foo()`. By the time we get to waiting on that promise, either it will have already timed out or we will wait for whatever remains of the 0.3 seconds before continuing the chain. ## Cancellation -Promises don’t have a `cancel` function, but they do support cancellation through a -special error type that conforms to the `CancellableError` protocol. - -```swift -func foo() -> (Promise, cancel: () -> Void) { - let task = Task(…) - var cancelme = false - - let promise = Promise { seal in - task.completion = { value in - guard !cancelme else { return reject(PMKError.cancelled) } - seal.fulfill(value) - } - task.start() - } - - let cancel = { - cancelme = true - task.cancel() - } - - return (promise, cancel) -} -``` - -Promises don’t have a `cancel` function because you don’t want code outside of -your control to be able to cancel your operations--*unless*, of course, you explicitly -want to enable that behavior. In cases where you do want cancellation, the exact way -that it should work will vary depending on how the underlying task supports cancellation. -PromiseKit provides cancellation primitives but no concrete API. - -Cancelled chains do not call `catch` handlers by default. However you can -intercept cancellation if you like: +Starting with version 7, PromiseKit explicitly supports cancellation of promises and +promise chains. There is a new class called `CancellablePromise` that defines a `cancel` +method. Use the `cancellize` method on `Thenable` to obtain a `CancellablePromise` from a +`Promise` or `Guarantee`. -```swift -foo.then { - //… -}.catch(policy: .allErrors) { - // cancelled errors are handled *as well* -} -``` - -**Important**: Canceling a promise chain is *not* the same as canceling the underlying -asynchronous task. Promises are wrappers around asynchronicity, but they have no -control over the underlying tasks. If you need to cancel an underlying task, you -need to cancel the underlying task! +Invoking `cancel` will both reject the promise with `PMKError.cancelled` and cancel any +underlying asynchronous task(s). -> The library [CancellablePromiseKit](https://github.com/johannesd/CancellablePromiseKit) extends the concept of Promises to fully cover cancellable tasks. +For full details see [Cancelling Promises](Cancel.md). ## Retry / Polling @@ -483,7 +466,7 @@ Use `when(resolved:)`: ```swift when(resolved: a, b).done { (results: [Result]) in - // `Result` is an enum of `.fulfilled` or `.rejected` + //… } // ^^ cannot call `catch` as `when(resolved:)` returns a `Guarantee` diff --git a/Documentation/Examples/ImageCache.md b/Documents/Examples/ImageCache.md similarity index 100% rename from Documentation/Examples/ImageCache.md rename to Documents/Examples/ImageCache.md diff --git a/Documentation/Examples/URLSession+BadResponseErrors.swift b/Documents/Examples/URLSession+BadResponseErrors.swift similarity index 100% rename from Documentation/Examples/URLSession+BadResponseErrors.swift rename to Documents/Examples/URLSession+BadResponseErrors.swift diff --git a/Documentation/Examples/detweet.swift b/Documents/Examples/detweet.swift similarity index 100% rename from Documentation/Examples/detweet.swift rename to Documents/Examples/detweet.swift diff --git a/Documentation/FAQ.md b/Documents/FAQ.md similarity index 85% rename from Documentation/FAQ.md rename to Documents/FAQ.md index decd7ba3d..a6222cf91 100644 --- a/Documentation/FAQ.md +++ b/Documents/FAQ.md @@ -8,7 +8,7 @@ * Do you want a library that has been maintained continuously and passionately for 6 years? Then pick PromiseKit. * Do you want a library that the community has chosen to be their №1 Promises/Futures library? Then pick PromiseKit. * Do you want to be able to use Promises with Apple’s SDKs rather than having to do all the work of writing the Promise implementations yourself? Then pick PromiseKit. -* Do you want to be able to use Promises with Swift 3.x, Swift 4.x, ObjC, iOS, tvOS, watchOS, macOS, Android & Linux? Then pick PromiseKit. +* Do you want to be able to use Promises with Swift, ObjC, iOS, tvOS, watchOS, macOS, Android & Linux? Then pick PromiseKit. * PromiseKit verifies its correctness by testing against the entire [Promises/A+ test suite](https://github.com/promises-aplus/promises-tests). ## How do I create a fulfilled `Void` promise? @@ -229,8 +229,8 @@ So, RxSwift tries hard to supply every operator you might ever want to use right hundreds. PromiseKit supplies a few utilities to help with specific scenarios, but because it's trivial to write your own chain elements, there's no need for all this extra code in the library. -* PromiseKit dispatches the execution of every block. RxSwift dispatches only when told to do so. Moreover, the -current dispatching state is an attribute of the chain, not the specific block, as it is in PromiseKit. +* PromiseKit dispatches the execution of every block. RxSwift dispatches only when told to do so. Moreover, +in RxSwift, the current dispatching state is an attribute of the chain, not the specific block, as it is in PromiseKit. The RxSwift system is more powerful but more complex. PromiseKit is simple, predictable and safe. * In PromiseKit, both sides of a branched chain refer back to their shared common ancestors. In RxSwift, @@ -317,36 +317,56 @@ feature because it gives you guarantees about the flow of your chains. ## How do I change the default queues that handlers run on? -You can change the values of `PromiseKit.conf.Q`. There are two variables that -change the default queues that the two kinds of handler run on. A typical -pattern is to change all your `then`-type handlers to run on a background queue +You can change the values of `PromiseKit.conf.Q` or `PromiseKit.conf.D`. These +variables both access the same underlying state. However, `conf.Q` presents it in terms of +`DispatchQueue`s, while `conf.D` presents it in terms of the more general +`Dispatcher`-protocol objects that PromiseKit uses internally. (`DispatchQueue`s are +just one possible implementation of `Dispatcher`, although they are the ones that account +for nearly all actual use.) + +Each of these configuration variables is a two-tuple that identifies two separate dispatchers named `map` and `return`. + +```swift +public var Q: (map: DispatchQueue?, return: DispatchQueue?) +public var D: (map: Dispatcher, return: Dispatcher) +``` + +The `return` dispatcher is the default for chain-finalizing methods such as `done` +and `catch`. The `map` dispatcher is the default for everything else. A +typical pattern is to change all your `then`-type handlers to run on a background queue and to have all your “finalizers” run on the main queue: ``` PromiseKit.conf.Q.map = .global() -PromiseKit.conf.Q.return = .main //NOTE this is the default +PromiseKit.conf.Q.return = .main ``` -Be very careful about setting either of these queues to `nil`. It has the -effect of running *immediately*, and this is not what you usually want to do in -your application. This is, however, useful when you are running specs and want -your promises to resolve immediately. (This is basically the same idea as "stubbing" -an HTTP request.) +Note that `DispatchQueue.main` is the default for _both_ dispatchers. + +Be very careful about setting either part of `conf.Q` to `nil`. It has the +effect of running closures *immediately*, and this is not what you usually want to do in +your application. It is useful, however, when you are running specs and want +your promises to resolve immediately. (It's basically the same idea as "stubbing" +HTTP requests.) ```swift // in your test suite setup code -PromiseKit.conf.Q.map = nil -PromiseKit.conf.Q.return = nil +PromiseKit.conf.Q = (map: nil, return: nil) ``` ## How do I use PromiseKit on the server side? If your server framework requires that the main queue remain unused (e.g., Kitura), -then you must use PromiseKit 6 and you must tell PromiseKit not to dispatch to the -main queue by default. This is easy enough: +then you must tell PromiseKit not to dispatch there by default. This is easy enough: + +```swift +PromiseKit.conf.Q = (map: .global(), return: .global()) +``` +If you want to emulate the serializing behavior of `DispatchQueue.main`, just create and label +a new `DispatchQueue`. It'll be serial by default. ```swift -PromiseKit.conf.Q = (map: DispatchQueue.global(), return: DispatchQueue.global()) +PromiseKit.conf.Q.return = DispatchQueue(label: "virtual main queue") ``` > Note, we recommend using your own queue rather than `.global()`, we've seen better performance this way. @@ -382,12 +402,12 @@ Kitura.run() ## How do I control console output? -By default PromiseKit emits console messages when certain events occur. These events include: +By default, PromiseKit emits warning messages on the console when certain events occur. These events include: - A promise or guarantee has blocked the main thread - A promise has been deallocated without being fulfilled - An error which occurred while fulfilling a promise was swallowed using cauterize -You may turn off or redirect this output by setting a thread safe closure in [PMKConfiguration](https://github.com/mxcl/PromiseKit/blob/master/Sources/Configuration.swift) **before** processing any promises. For example, to turn off console output: +You may turn off or redirect this output by setting a thread-safe closure in [PMKConfiguration](https://github.com/mxcl/PromiseKit/blob/master/Sources/Configuration.swift) **before** processing any promises. For example, to turn off console output: ```swift conf.logHandler = { event in } diff --git a/Documentation/GettingStarted.md b/Documents/GettingStarted.md similarity index 91% rename from Documentation/GettingStarted.md rename to Documents/GettingStarted.md index 8f6af48dc..2e5bb61c4 100644 --- a/Documentation/GettingStarted.md +++ b/Documents/GettingStarted.md @@ -32,7 +32,7 @@ readability. The promise chain above is easy to scan and understand: one asynchr operation leads into the other, line by line. It's as close to procedural code as we can easily come given the current state of Swift. -`done` is the same as `then` but you cannot return a promise. It is +`done` is the same as `then` but you cannot return a promise. It is typically the end of the “success” part of the chain. Above, you can see that we receive the final image in our `done` and use it to set up the UI. @@ -40,15 +40,15 @@ Let’s compare the signatures of the two login methods: ```swift func login() -> Promise - + // Compared with: func login(completion: (Creds?, Error?) -> Void) // ^^ ugh. Optionals. Double optionals. ``` -The distinction is that with promises, your functions return *promises* instead -of accepting and running callbacks. Each handler in a chain returns a promise. +The distinction is that with promises, your functions return *promises* instead +of accepting and running callbacks. Each handler in a chain returns a promise. `Promise` objects define the `then` method, which waits for the completion of the promise before continuing the chain. Chains resolve procedurally, one promise at a time. @@ -58,9 +58,9 @@ that represents the type of object it wraps. For example, in the example above, `login` is a function that returns a `Promise` that *will* represent an instance of `Creds`. -> *Note*: `done` is new to PromiseKit 5. We previously defined a variant of `then` that +> *Note*: `done` was introduced in PromiseKit 5. We previously defined a variant of `then` that did not require you to return a promise. Unfortunately, this convention often confused -Swift and led to odd and hard-to-debug error messages. It also made using PromiseKit +Swift and led to odd and hard-to-debug error messages. It also made using PromiseKit more painful. The introduction of `done` lets you type out promise chains that compile without additional qualification to help the compiler figure out type information. @@ -158,9 +158,9 @@ login { creds, error in } ``` -It would be very easy for someone to amend this code and forget to unset +It would be very easy for someone to amend this code and forget to unset the activity indicator, leading to a bug. With promises, this type of error is -almost impossible: the Swift compiler resists your supplementing the chain without +almost impossible: the Swift compiler resists your supplementing the chain without using promises. You almost won’t need to review the pull requests. > *Note*: PromiseKit has perhaps capriciously switched between the names `always` @@ -234,7 +234,7 @@ As with any promise chain, if any of the component promises fail, the chain call # PromiseKit Extensions -When we made PromiseKit, we understood that we wanted to use *only* promises to implement +When we made PromiseKit, we understood that we wanted to use *only* promises to implement asynchronous behavior. So wherever possible, we offer extensions to Apple’s APIs that reframe the API in terms of promises. For example: @@ -256,12 +256,7 @@ pod "PromiseKit/CoreLocation" pod "PromiseKit/MapKit" ``` -All of these extensions are available at the [PromiseKit organization](https://github.com/PromiseKit). -Go there to see what's available and to read the source code and documentation. Every file and function -has been copiously documented. - -> We also provide extensions for common libraries such as [Alamofire](https://github.com/PromiseKit/Alamofire-). - +To see what is available, check our [sources](https://github.com/mxcl/PromiseKit/tree/master/Sources). # Making Promises @@ -296,9 +291,9 @@ func fetch() -> Promise { } ``` -The `seal` object that the `Promise` initializer provides to you defines -many methods for handling garden-variety completion handlers. It even -covers a variety of rarer situations, thus making it easy for you to add +The `seal` object that the `Promise` initializer provides to you defines +many methods for handling garden-variety completion handlers. It even +covers a variety of rarer situations, thus making it easy for you to add promises to an existing codebase. > *Note*: We tried to make it so that you could just do `Promise(fetch)`, but we @@ -311,10 +306,10 @@ extra disambiguation for the Swift compiler. Sorry; we tried. typically just pass completion handler parameters to `resolve` and let Swift figure out which variant to apply to your particular case (as shown in the example above). -> *Note* `Guarantees` (below) have a slightly different initializer (since they -cannot error) so the parameter to the initializer closure is just a closure. Not -a `Resolver` object. Thus do `seal(value)` rather than `seal.fulfill(value)`. This -is because there is no variations in what guarantees can be sealed with, they can +> *Note*: `Guarantee`s (below) have a slightly different initializer since they +cannot error, so the parameter to the initializer closure is just a closure. Not +a `Resolver` object. Just do `seal(value)` rather than `seal.fulfill(value)`. It's +different because there is only one way to seal guarantees; they can *only* fulfill. # `Guarantee` @@ -333,8 +328,8 @@ firstly { ``` Swift warns you if you don’t terminate a regular `Promise` chain (i.e., not -a `Guarantee` chain). You're expected to silence this warning by supplying -either a `catch` or a `return`. (In the latter case, you will then have to `catch` +a `Guarantee` chain). You're expected to silence this warning by supplying +either a `catch` or a `return`. (In the latter case, you will then have to `catch` at the point where you receive that promise.) Use `Guarantee`s wherever possible so that your code has error handling where @@ -346,7 +341,7 @@ if you find an issue. --- -If you are creating your own guarantees the syntax is simpler than that of promises; +If you are creating your own guarantees the syntax is simpler than that of promises: ```swift func fetch() -> Promise { @@ -471,12 +466,12 @@ Here is a key understanding: `login()` returns a `Promise`, and all `Promise`s h `when` is one of PromiseKit’s more useful functions, and so we offer several variants. * The default `when`, and the one you should typically use, is `when(fulfilled:)`. This variant -waits on all its component promises, but if any fail, `when` fails too, and thus the chain *rejects*. +waits on all its component promises, but if any fail, `when` fails too, and thus the chain *rejects*. It's important to note that all promises in the `when` *continue*. Promises have *no* control over the tasks they represent. Promises are just wrappers around tasks. * `when(resolved:)` waits even if one or more of its component promises fails. The value produced -by this variant of `when` is an array of `Result`. Consequently, this variant requires all its +by this variant of `when` is an array of `Result`. Consequently, this variant requires all its component promises to have the same generic type. See our advanced patterns guide for work-arounds for this limitation. @@ -507,7 +502,7 @@ However, this shorthand is both a blessing and a curse. You may find that the Sw often fails to infer return types properly. See our [Troubleshooting Guide](Troubleshooting.md) if you require further assistance. -> By adding `done` to PromiseKit 5, we have managed to avoid many of these common +> By adding `done` to PromiseKit 5, we were able to blunt many of these common pain points in using PromiseKit and Swift. @@ -527,9 +522,9 @@ Here are some recent articles that document PromiseKit 5+: * [Using Promises - Agostini.tech](https://agostini.tech/2018/10/08/using-promisekit) -Careful with general online references, many of them refer to PMK < 5 which has a subtly -different API (sorry about that, but Swift has changed a lot over the years and thus -we had to too). +Be careful when consulting general online references, as many of them refer to PMK < 5, which has a subtly +different API. (Sorry about that, but Swift has changed a lot over the years and thus +we had to as well.) -[API Reference]: https://mxcl.dev/PromiseKit/reference/v6/Classes/Promise.html +[API Reference]: https://mxcl.dev/PromiseKit/reference/v7/Classes/Promise.html diff --git a/Documents/Installation.md b/Documents/Installation.md new file mode 100644 index 000000000..8f51add0b --- /dev/null +++ b/Documents/Installation.md @@ -0,0 +1,38 @@ +# Installing PromiseKit + +We support [SwiftPM]: + +```swift +package.dependencies.append( + .package(url: "https://github.com/mxcl/PromiseKit", from: "7.0.0-rc1") +) + +package.targets.append( + .target(name: "…", dependencies: [ + .product(name: "PromiseKit", package: "PromiseKit"), + .product(name: "PMKFoundation", package: "PromiseKit"), + .product(name: "PMKMapKit", package: "PromiseKit"), + ]) +) +``` + +And CocoaPods: + +> Please note, we have not released this CocoaPod yet. You *can* still use it +> but you will need to specify the podspec URL manually, see the Cocoapods docs. + +```ruby +pod "PromiseKit", "~> 7.0.0-rc1" +pod "PromiseKit/Foundation", "~> 7.0.0-rc1" +pod "PromiseKit/MapKit", "~> 7.0.0-rc1" +``` + +## Carthage + +We will support [Carthage] if you can PR an automated solution for generating +the `.xcodeproj` on release. It will need to support all our extensions. + + +[SwiftPM]: https://swift.org/package-manager +[CocoaPods]: https://cocoapods.org +[Carthage]: https://github.com/Carthage/Carthage diff --git a/Documentation/README.md b/Documents/README.md similarity index 76% rename from Documentation/README.md rename to Documents/README.md index a03f4aa42..2560462ee 100644 --- a/Documentation/README.md +++ b/Documents/README.md @@ -4,11 +4,11 @@ * Handbook * [Getting Started](GettingStarted.md) * [Promises: Common Patterns](CommonPatterns.md) + * [Cancelling Promises](Cancel.md) * [Frequently Asked Questions](FAQ.md) * Manual * [Installation Guide](Installation.md) - * [Objective-C Guide](ObjectiveC.md) * [Troubleshooting](Troubleshooting.md) * [Appendix](Appendix.md) * [Examples](Examples) -* [API Reference](https://mxcl.dev/PromiseKit/reference/v6/Classes/Promise.html) +* [API Reference](https://mxcl.dev/PromiseKit/reference/v7/Classes/Promise.html) diff --git a/Documentation/Troubleshooting.md b/Documents/Troubleshooting.md similarity index 63% rename from Documentation/Troubleshooting.md rename to Documents/Troubleshooting.md index 1e38b2676..37cba295a 100644 --- a/Documentation/Troubleshooting.md +++ b/Documents/Troubleshooting.md @@ -24,7 +24,7 @@ What’s the real problem? `then` *must* return a `Promise`, and you're trying t ```swift return firstly { - URLSession.shared.dataTask(.promise, with: url) + URLSession.shared.dataTask(.promise, with: url) }.compactMap { JSONSerialization.jsonObject(with: $0.data) as? [String: Any] }.map { dict in @@ -68,7 +68,7 @@ return firstly { } ``` -We have made great effort to reduce the need for explicit typing in PromiseKit 6, +We have made great effort to reduce the need for explicit typing in PromiseKit, but as with all Swift functions that return a generic type (e.g., `Array.map`), you may need to explicitly tell Swift what a closure returns if the closure's body is longer than one line. @@ -163,6 +163,131 @@ An *inline* function like this is all you need. Here, the problem is that you forgot to mark the last line of the closure with an explicit `return`. It's required here because the closure is longer than one line. +### Cancellable promise embedded in the middle of a standard promise chain + +Error: ***Cannot convert value of type 'Promise<>' to closure result type 'Guarantee<>'***. Fixed by adding `cancellize` to `firstly { login() }`. + +```swift +/// 'login()' returns 'Promise' +/// 'fetch(avatar:)' returns 'CancellablePromise' + +let promise = firstly { + login() /// <-- ERROR: Cannot convert value of type 'Promise' to closure result type 'Guarantee' +}.then { creds in /// CHANGE TO: "}.cancellize().then { creds in" + fetch(avatar: creds.user) /// <-- ERROR: Cannot convert value of type 'CancellablePromise' to + /// closure result type 'Guarantee' +}.done { image in + self.imageView = image +}.catch(policy: .allErrors) { error in + if error.isCancelled { + // the chain has been cancelled! + } +} + +// … + +promise.cancel() +``` + +### The return type for a multi-line closure returning `CancellablePromise` is not explicitly stated + +The Swift compiler cannot (yet) determine the return type of a multi-line closure. + +The following example gives the unhelpful error: ***'()' is not convertible to 'UIImage'***. Many other strange errors can result from not explicitly declaring the return type of a multi-line closure. These kinds of errors are fixed by explicitly declaring the return type, which in the following example is a `CancellablePromise``. + +```swift +/// 'login()' returns 'Promise' +/// 'fetch(avatar:)' returns 'CancellablePromise' + +let promise = firstly { + login() +}.cancellize().then { creds in /// CHANGE TO: "}.cancellize().then { creds -> CancellablePromise in" + let f = fetch(avatar: creds.user) + return f +}.done { image in + self.imageView = image /// <-- ERROR: '()' is not convertible to 'UIImage' +}.catch(policy: .allErrors) { error in + if error.isCancelled { + // the chain has been cancelled! + } +} + +// … + +promise.cancel() +``` + +### Trying to cancel a standard promise chain + +Error: ***Value of type `PMKFinalizer` has no member `cancel`***. Fixed by using cancellable promises instead of standard promises. + +```swift +/// 'login()' returns 'Promise' +/// 'fetch(avatar:)' returns 'CancellablePromise' + +let promise = firstly { + login() +}.then { creds in /// CHANGE TO: "}.cancellize().then { creds in" + fetch(avatar: creds.user).promise /// CHANGE TO: fetch(avatar: creds.user) +}.done { image in + self.imageView = image +}.catch(policy: .allErrors) { error in + if error.isCancelled { + // the chain has been cancelled! + } +} + +// … + +promise.cancel() /// <-- ERROR: Value of type 'PMKFinalizer' has no member 'cancel' +``` + +### Compilation for long chains is very slow or times out, especially with cancellable promises + +If a cancellable promise chain has more than a few (> 3) calls to `thenMap` and +`thenFlatMap` or has an extensive number of calls in the chain (> 6), you +may need to specify the return types for all closures in the chain. Standard +(non-cancellable) promise chains typically only see this problem if they are +extremely long (> 15 calls). + +And if compilation with promises is generally sluggish, the time may be greatly +improved by specifying return types for all closures. + +For example: + +```swift +/// Compilation timeout error: +Promise.value([42, 52]).cancellize().then { + Promise.value($0) +}.then { + Promise.value($0) +}.thenMap { + Promise.value($0 + 10).cancellize() +}.thenMap { + Promise.value($0 + 10) +}.thenFlatMap { + Promise.value([$0 + 10]).cancellize() +}.thenFlatMap { /// <-- Error: The compiler is unable to type-check this expression + /// in reasonable time; try breaking up the expression + /// into distinct sub-expressions + Promise.value([$0 + 10]) +} + +/// Compiles very quickly: +Promise.value([42, 52]).cancellize().then { v -> Promise<[Int]> in + Promise.value(v) +}.then { v -> Promise<[Int]> in + Promise.value(v) +}.thenMap { v -> CancellablePromise in + Promise.value(v + 10).cancellize() +}.thenMap { v -> Promise in + Promise.value(v + 10) +}.thenFlatMap { v -> CancellablePromise<[Int]> in + Promise.value([v + 10]).cancellize() +}.thenFlatMap { v -> Promise<[Int]> in + Promise.value([v + 10]) +} +``` ## You copied code off the Internet that doesn’t work @@ -175,17 +300,17 @@ All PromiseKit functions are documented and provide examples. You have a `then`; you want a `done`. -## "Missing argument for parameter #1 in call" +## "Missing argument for parameter #1 in call" "Unable to infer closure type in the current context" This is part of Swift 4’s “tuplegate”. -You must specify your `Void` parameter: +You must fulfill a `Promise` with an explicit `Void` parameter: ```swift seal.fulfill(()) ``` -Yes: we hope they revert this change in Swift 5 too. +This wart remains in Swift 5, too. It's probably not going to change. ## "Ambiguous reference to 'firstly(execute:)'" diff --git a/Extensions/AVFoundation b/Extensions/AVFoundation deleted file mode 160000 index 911b25778..000000000 --- a/Extensions/AVFoundation +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 911b257783efc0aa705481d556c8ecdfcdc055a9 diff --git a/Extensions/Accounts b/Extensions/Accounts deleted file mode 160000 index 6c01f5719..000000000 --- a/Extensions/Accounts +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 6c01f5719ff08bbbf81d42b7e20c5188cab4a81d diff --git a/Extensions/AddressBook b/Extensions/AddressBook deleted file mode 160000 index c694fa062..000000000 --- a/Extensions/AddressBook +++ /dev/null @@ -1 +0,0 @@ -Subproject commit c694fa0628a96951c6e2db113dc4eb6dd4e47ebc diff --git a/Extensions/Alamofire b/Extensions/Alamofire deleted file mode 160000 index a41a97d3d..000000000 --- a/Extensions/Alamofire +++ /dev/null @@ -1 +0,0 @@ -Subproject commit a41a97d3d3aa6efb575d0f42f3b8aeec5a756ead diff --git a/Extensions/AssetsLibrary b/Extensions/AssetsLibrary deleted file mode 160000 index e4317d527..000000000 --- a/Extensions/AssetsLibrary +++ /dev/null @@ -1 +0,0 @@ -Subproject commit e4317d5279db7ecfc5bc565e1dd88fcabc02c352 diff --git a/Extensions/Bolts b/Extensions/Bolts deleted file mode 160000 index fbc994121..000000000 --- a/Extensions/Bolts +++ /dev/null @@ -1 +0,0 @@ -Subproject commit fbc9941219c9bbdfe6d664ca6b8d10b5e2f8fb70 diff --git a/Extensions/CloudKit b/Extensions/CloudKit deleted file mode 160000 index 9586f3c06..000000000 --- a/Extensions/CloudKit +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 9586f3c06c4934e776c2b96c128f332a168c2c91 diff --git a/Extensions/CoreBluetooth b/Extensions/CoreBluetooth deleted file mode 160000 index 8e0bc9579..000000000 --- a/Extensions/CoreBluetooth +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 8e0bc957996daad5c49f8809839f8699883ed364 diff --git a/Extensions/CoreLocation b/Extensions/CoreLocation deleted file mode 160000 index c4ea4dba6..000000000 --- a/Extensions/CoreLocation +++ /dev/null @@ -1 +0,0 @@ -Subproject commit c4ea4dba6e0516986b3cb1d93c86f6991ce46861 diff --git a/Extensions/EventKit b/Extensions/EventKit deleted file mode 160000 index 1f90d6753..000000000 --- a/Extensions/EventKit +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 1f90d67538047087428d82550976c2e43aba0961 diff --git a/Extensions/Foundation b/Extensions/Foundation deleted file mode 160000 index 1a276e598..000000000 --- a/Extensions/Foundation +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 1a276e598dac59489ed904887e0740fa75e571e0 diff --git a/Extensions/HealthKit b/Extensions/HealthKit deleted file mode 160000 index b185822cb..000000000 --- a/Extensions/HealthKit +++ /dev/null @@ -1 +0,0 @@ -Subproject commit b185822cb1fcf5297347498b783b4e21b2e55282 diff --git a/Extensions/HomeKit b/Extensions/HomeKit deleted file mode 160000 index 668abe78a..000000000 --- a/Extensions/HomeKit +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 668abe78a52a23bd276c8924dba91592ac0ca45a diff --git a/Extensions/MapKit b/Extensions/MapKit deleted file mode 160000 index d1d4ebdd6..000000000 --- a/Extensions/MapKit +++ /dev/null @@ -1 +0,0 @@ -Subproject commit d1d4ebdd6ceac78d734e2ae27e8ab429906d6929 diff --git a/Extensions/MessagesUI b/Extensions/MessagesUI deleted file mode 160000 index 2a93ce737..000000000 --- a/Extensions/MessagesUI +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 2a93ce737502e13a3eaedc444b9ecb5abb28ec79 diff --git a/Extensions/OMGHTTPURLRQ b/Extensions/OMGHTTPURLRQ deleted file mode 160000 index 5ec40a68f..000000000 --- a/Extensions/OMGHTTPURLRQ +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 5ec40a68f168255dcc339b9620e2dcf62079ae6b diff --git a/Extensions/Photos b/Extensions/Photos deleted file mode 160000 index 48f801454..000000000 --- a/Extensions/Photos +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 48f801454b01c69a1553873cb1d95e90ae2ec4cc diff --git a/Extensions/QuartzCore b/Extensions/QuartzCore deleted file mode 160000 index b22f187b6..000000000 --- a/Extensions/QuartzCore +++ /dev/null @@ -1 +0,0 @@ -Subproject commit b22f187b6b3f82f102aa309b256bf24570a73d1f diff --git a/Extensions/Social b/Extensions/Social deleted file mode 160000 index 378912a47..000000000 --- a/Extensions/Social +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 378912a47a206183b931d2008e0f396e9fc390e8 diff --git a/Extensions/StoreKit b/Extensions/StoreKit deleted file mode 160000 index e26f6a559..000000000 --- a/Extensions/StoreKit +++ /dev/null @@ -1 +0,0 @@ -Subproject commit e26f6a55921ea671855093754686991b08ef97cc diff --git a/Extensions/SystemConfiguration b/Extensions/SystemConfiguration deleted file mode 160000 index 6b009f906..000000000 --- a/Extensions/SystemConfiguration +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 6b009f906fc489346a73759b5668b263a320c51c diff --git a/Extensions/UIKit b/Extensions/UIKit deleted file mode 160000 index baf104ba2..000000000 --- a/Extensions/UIKit +++ /dev/null @@ -1 +0,0 @@ -Subproject commit baf104ba29ff94d9d41e90e8ec557a56b87fecd4 diff --git a/Extensions/WatchConnectivity b/Extensions/WatchConnectivity deleted file mode 160000 index b5b3fca95..000000000 --- a/Extensions/WatchConnectivity +++ /dev/null @@ -1 +0,0 @@ -Subproject commit b5b3fca958a7296f71313b6c172584bc91d6da8b diff --git a/Package.resolved b/Package.resolved new file mode 100644 index 000000000..3e3af447c --- /dev/null +++ b/Package.resolved @@ -0,0 +1,16 @@ +{ + "object": { + "pins": [ + { + "package": "OHHTTPStubs", + "repositoryURL": "https://github.com/AliSoftware/OHHTTPStubs", + "state": { + "branch": null, + "revision": "12f19662426d0434d6c330c6974d53e2eb10ecd9", + "version": "9.1.0" + } + } + ] + }, + "version": 1 +} diff --git a/Package.swift b/Package.swift index d96717491..4159af2b3 100644 --- a/Package.swift +++ b/Package.swift @@ -1,30 +1,65 @@ -// swift-tools-version:4.0 +// swift-tools-version:5.3 import PackageDescription let pkg = Package(name: "PromiseKit") -pkg.products = [ - .library(name: "PromiseKit", targets: ["PromiseKit"]), +pkg.platforms = [ + .macOS(.v10_10), + .iOS(.v10), //FIXME strictly 8.0, but Tests require 10 + .tvOS(.v10), //FIXME strictly 9.0, but Tests require 10 + .watchOS(.v3) ] +pkg.swiftLanguageVersions = [.v5] -let pmk: Target = .target(name: "PromiseKit") -pmk.path = "Sources" -pmk.exclude = [ - "AnyPromise.swift", - "AnyPromise.m", - "PMKCallVariadicBlock.m", - "dispatch_promise.m", - "join.m", - "when.m", - "NSMethodSignatureForBlock.m", - "after.m", - "hang.m", - "race.m", - "Deprecations.swift" +#if !os(Linux) && !os(Windows) +pkg.dependencies = [ + .package(url: "https://github.com/AliSoftware/OHHTTPStubs", from: "9.1.0") ] -pkg.swiftLanguageVersions = [3, 4, 5] -pkg.targets = [ - pmk, - .testTarget(name: "APlus", dependencies: ["PromiseKit"], path: "Tests/A+"), - .testTarget(name: "CorePromise", dependencies: ["PromiseKit"], path: "Tests/CorePromise"), +#endif + +func dependencies(for name: String) -> [Target.Dependency] { + switch name { + case "PromiseKit": + return [] + default: + return [.target(name: "PromiseKit")] + } +} + +func has(tests name: String) -> Target? { + switch name { + case "PMKFoundation": + var deps = [Target.Dependency.target(name: "PMKFoundation")] + #if !os(Linux) && !os(Windows) + deps.append(.product(name: "OHHTTPStubsSwift", package: "OHHTTPStubs")) + #endif + return .testTarget(name: "\(name)Tests", dependencies: deps, path: "Tests/\(name)") + case "PMKHomeKit", "PMKMapKit", "PMKCoreLocation": + return .testTarget(name: "\(name)Tests", dependencies: [.target(name: name)], path: "Tests/\(name)") + default: + return nil + } +} + +for name in ["PMKCloudKit", "PMKCoreLocation", "PMKFoundation", "PMKHealthKit", "PMKHomeKit", "PMKMapKit", "PMKPhotos", "PMKStoreKit", "PromiseKit"] { + + #if os(Linux) || os(Windows) + guard name == "PromiseKit" || name == "PMKFoundation" else { continue } + #endif + + pkg.targets.append(.target(name: name, dependencies: dependencies(for: name))) + pkg.products.append(.library(name: name, targets: [name])) + + if let testTarget = has(tests: name) { + pkg.targets.append(testTarget) + } +} + +pkg.targets += [ + .testTarget(name: "Core", dependencies: ["PromiseKit"]), + .testTarget(name: "Cancel", dependencies: ["PromiseKit"]), + .testTarget(name: "APlusSwiftTests", dependencies: ["PromiseKit"], path: "Tests/A+/Swift"), + .testTarget(name: "APlusJSTests", dependencies: ["PromiseKit"], path: "Tests/A+/JavaScript", exclude: [ + "index.js", "package-lock.json", "package.json", "README.md", "webpack.config.js", "build", "node_modules" + ]), ] diff --git a/Package@swift-4.2.swift b/Package@swift-4.2.swift deleted file mode 100644 index 571ea6b28..000000000 --- a/Package@swift-4.2.swift +++ /dev/null @@ -1,30 +0,0 @@ -// swift-tools-version:4.2 - -import PackageDescription - -let pkg = Package(name: "PromiseKit") -pkg.products = [ - .library(name: "PromiseKit", targets: ["PromiseKit"]), -] - -let pmk: Target = .target(name: "PromiseKit") -pmk.path = "Sources" -pmk.exclude = [ - "AnyPromise.swift", - "AnyPromise.m", - "PMKCallVariadicBlock.m", - "dispatch_promise.m", - "join.m", - "when.m", - "NSMethodSignatureForBlock.m", - "after.m", - "hang.m", - "race.m", - "Deprecations.swift" -] -pkg.swiftLanguageVersions = [.v3, .v4, .v4_2] -pkg.targets = [ - pmk, - .testTarget(name: "APlus", dependencies: ["PromiseKit"], path: "Tests/A+"), - .testTarget(name: "CorePromise", dependencies: ["PromiseKit"], path: "Tests/CorePromise"), -] diff --git a/Package@swift-5.0.swift b/Package@swift-5.0.swift deleted file mode 100644 index 5d1ea438f..000000000 --- a/Package@swift-5.0.swift +++ /dev/null @@ -1,33 +0,0 @@ -// swift-tools-version:5.0 - -import PackageDescription - -let pkg = Package(name: "PromiseKit") -pkg.platforms = [ - .macOS(.v10_10), .iOS(.v8), .tvOS(.v9), .watchOS(.v2) -] -pkg.products = [ - .library(name: "PromiseKit", targets: ["PromiseKit"]), -] - -let pmk: Target = .target(name: "PromiseKit") -pmk.path = "Sources" -pmk.exclude = [ - "AnyPromise.swift", - "AnyPromise.m", - "PMKCallVariadicBlock.m", - "dispatch_promise.m", - "join.m", - "when.m", - "NSMethodSignatureForBlock.m", - "after.m", - "hang.m", - "race.m", - "Deprecations.swift" -] -pkg.swiftLanguageVersions = [.v4, .v4_2, .v5] -pkg.targets = [ - pmk, - .testTarget(name: "APlus", dependencies: ["PromiseKit"], path: "Tests/A+"), - .testTarget(name: "CorePromise", dependencies: ["PromiseKit"], path: "Tests/CorePromise"), -] diff --git a/Package@swift-5.3.swift b/Package@swift-5.3.swift deleted file mode 100644 index 0c4bf4d24..000000000 --- a/Package@swift-5.3.swift +++ /dev/null @@ -1,34 +0,0 @@ -// swift-tools-version:5.3 - -import PackageDescription - -let pkg = Package(name: "PromiseKit") -pkg.platforms = [ - .macOS(.v10_10), .iOS(.v9), .tvOS(.v9), .watchOS(.v2) -] -pkg.products = [ - .library(name: "PromiseKit", targets: ["PromiseKit"]), -] - -let pmk: Target = .target(name: "PromiseKit") -pmk.path = "Sources" -pmk.exclude = [ - "AnyPromise.swift", - "AnyPromise.m", - "PMKCallVariadicBlock.m", - "dispatch_promise.m", - "join.m", - "when.m", - "NSMethodSignatureForBlock.m", - "after.m", - "hang.m", - "race.m", - "Deprecations.swift", - "Info.plist" -] -pkg.swiftLanguageVersions = [.v4, .v4_2, .v5] -pkg.targets = [ - pmk, - .testTarget(name: "APlus", dependencies: ["PromiseKit"], path: "Tests/A+", exclude: ["README.md"]), - .testTarget(name: "CorePromise", dependencies: ["PromiseKit"], path: "Tests/CorePromise"), -] diff --git a/PromiseKit.playground/Contents.swift b/PromiseKit.playground/Contents.swift deleted file mode 100644 index 3ade47e96..000000000 --- a/PromiseKit.playground/Contents.swift +++ /dev/null @@ -1,27 +0,0 @@ -import PlaygroundSupport - -// Is this erroring? If so open the `.xcodeproj` and build the -// framework for a macOS target (usually labeled: “My Mac”). -// Then select `PromiseKit.playground` from inside Xcode. -import PromiseKit - - -func promise3() -> Promise { - return after(.seconds(1)).map{ 3 } -} - -firstly { - Promise.value(1) -}.map { _ in - 2 -}.then { _ in - promise3() -}.done { - print($0) // => 3 -}.catch { error in - // only happens for errors -}.finally { - PlaygroundPage.current.finishExecution() -} - -PlaygroundPage.current.needsIndefiniteExecution = true diff --git a/PromiseKit.playground/contents.xcplayground b/PromiseKit.playground/contents.xcplayground deleted file mode 100644 index e6f503930..000000000 --- a/PromiseKit.playground/contents.xcplayground +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/PromiseKit.playground/playground.xcworkspace/contents.xcworkspacedata b/PromiseKit.playground/playground.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 919434a62..000000000 --- a/PromiseKit.playground/playground.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/PromiseKit.podspec b/PromiseKit.podspec index 7873a82c7..544dc0412 100644 --- a/PromiseKit.podspec +++ b/PromiseKit.podspec @@ -1,12 +1,15 @@ Pod::Spec.new do |s| s.name = "PromiseKit" - s.version = '6.15.3' + s.version = ENV['PMKVersion'] || '7.999.0' s.source = { :git => "https://github.com/mxcl/#{s.name}.git", - :tag => s.version, - :submodules => true + :tag => s.version + } + + s.pod_target_xcconfig = { + 'OTHER_SWIFT_FLAGS' => '-DPMKCocoaPods', } s.license = 'MIT' @@ -15,75 +18,19 @@ Pod::Spec.new do |s| s.description = 'A thoughtful and complete implementation of promises for iOS, macOS, watchOS and tvOS with first-class support for both Objective-C and Swift.' s.social_media_url = 'https://twitter.com/mxcl' s.authors = { 'Max Howell' => 'mxcl@me.com' } - s.documentation_url = 'http://mxcl.dev/PromiseKit/reference/v6/Classes/Promise.html' - s.default_subspecs = 'CorePromise', 'UIKit', 'Foundation' + s.documentation_url = 'http://mxcl.dev/PromiseKit/reference/v7/Classes/Promise.html' + s.default_subspecs = 'CorePromise', 'Foundation' s.requires_arc = true - s.swift_versions = ['3.2', '3.3', '3.4', '4.0', '4.1', '4.2', '4.3', '4.4', '5.0', '5.1', '5.2', '5.3', '5.4'] + s.swift_versions = ['5.3', '5.4'] - # CocoaPods requires us to specify the root deployment targets - # even though for us it is nonsense. Our root spec has no - # sources. - s.ios.deployment_target = '8.0' + s.ios.deployment_target = '9.0' s.osx.deployment_target = '10.10' - s.watchos.deployment_target = '2.0' + s.watchos.deployment_target = '3.0' s.tvos.deployment_target = '9.0' - s.pod_target_xcconfig = { - 'OTHER_SWIFT_FLAGS' => '-DPMKCocoaPods', - } - - s.subspec 'Accounts' do |ss| - ss.ios.source_files = ss.osx.source_files = 'Extensions/Accounts/Sources/*' - ss.ios.frameworks = ss.osx.frameworks = 'Accounts' - ss.dependency 'PromiseKit/CorePromise' - ss.ios.deployment_target = '8.0' - ss.osx.deployment_target = '10.10' - end - - s.subspec 'Alamofire' do |ss| - ss.source_files = 'Extensions/Alamofire/Sources/*' - ss.dependency 'Alamofire', '~> 4.0' - ss.dependency 'PromiseKit/CorePromise' - ss.ios.deployment_target = '8.0' - ss.osx.deployment_target = '10.11' - ss.watchos.deployment_target = '2.0' - ss.tvos.deployment_target = '9.0' - end - - s.subspec 'AddressBook' do |ss| - ss.ios.source_files = 'Extensions/AddressBook/Sources/*' - ss.ios.frameworks = 'AddressBook' - ss.dependency 'PromiseKit/CorePromise' - ss.ios.deployment_target = '8.0' - end - - s.subspec 'AssetsLibrary' do |ss| - ss.ios.source_files = 'Extensions/AssetsLibrary/Sources/*' - ss.ios.frameworks = 'AssetsLibrary' - ss.dependency 'PromiseKit/CorePromise' - ss.ios.deployment_target = '8.0' - end - - s.subspec 'AVFoundation' do |ss| - ss.ios.source_files = 'Extensions/AVFoundation/Sources/*' - ss.ios.frameworks = 'AVFoundation' - ss.dependency 'PromiseKit/CorePromise' - ss.ios.deployment_target = '8.0' - end - - s.subspec 'Bolts' do |ss| - ss.source_files = 'Extensions/Bolts/Sources/*' - ss.dependency 'PromiseKit/CorePromise' - ss.dependency 'Bolts', '~> 1.9.0' - ss.ios.deployment_target = '8.0' - ss.osx.deployment_target = '10.10' - ss.watchos.deployment_target = '2.0' - ss.tvos.deployment_target = '9.0' - end - s.subspec 'CloudKit' do |ss| - ss.source_files = 'Extensions/CloudKit/Sources/*' + ss.source_files = 'Sources/PMKCloudKit/*' ss.frameworks = 'CloudKit' ss.dependency 'PromiseKit/CorePromise' ss.ios.deployment_target = '10.0' @@ -92,27 +39,9 @@ Pod::Spec.new do |s| ss.watchos.deployment_target = '3.0' end - s.subspec 'CoreBluetooth' do |ss| - ss.ios.source_files = ss.osx.source_files = ss.tvos.source_files = 'Extensions/CoreBluetooth/Sources/*' - ss.ios.frameworks = ss.osx.frameworks = ss.tvos.frameworks = 'CoreBluetooth' - ss.dependency 'PromiseKit/CorePromise' - ss.ios.deployment_target = '8.0' - ss.osx.deployment_target = '10.10' - ss.tvos.deployment_target = '9.0' - end - s.subspec 'CorePromise' do |ss| - hh = Dir['Sources/*.h'] - Dir['Sources/*+Private.h'] - - cc = Dir['Sources/*.swift'] - ['Sources/SwiftPM.swift'] - cc << 'Sources/{after,AnyPromise,GlobalState,dispatch_promise,hang,join,PMKPromise,when,race}.m' - cc += hh - - ss.source_files = cc - ss.public_header_files = hh - ss.preserve_paths = 'Sources/AnyPromise+Private.h', 'Sources/PMKCallVariadicBlock.m', 'Sources/NSMethodSignatureForBlock.m' + ss.source_files = 'Sources/PromiseKit/**/*' ss.frameworks = 'Foundation' - ss.ios.deployment_target = '8.0' ss.osx.deployment_target = '10.10' ss.watchos.deployment_target = '2.0' @@ -120,8 +49,7 @@ Pod::Spec.new do |s| end s.subspec 'CoreLocation' do |ss| - ss.source_files = 'Extensions/CoreLocation/Sources/*' - ss.watchos.source_files = 'Extensions/CoreLocation/Sources/CLGeocoder*' + ss.source_files = 'Sources/PMKCoreLocation/*' ss.dependency 'PromiseKit/CorePromise' ss.frameworks = 'CoreLocation' @@ -131,18 +59,8 @@ Pod::Spec.new do |s| ss.tvos.deployment_target = '9.0' end - s.subspec 'EventKit' do |ss| - ss.ios.source_files = ss.osx.source_files = ss.watchos.source_files = 'Extensions/EventKit/Sources/*' - ss.ios.frameworks = ss.osx.frameworks = ss.watchos.frameworks = 'EventKit' - ss.dependency 'PromiseKit/CorePromise' - - ss.ios.deployment_target = '8.0' - ss.osx.deployment_target = '10.10' - ss.watchos.deployment_target = '2.0' - end - s.subspec 'Foundation' do |ss| - ss.source_files = Dir['Extensions/Foundation/Sources/*'] + ss.source_files = 'Sources/PMKFoundation/*' ss.dependency 'PromiseKit/CorePromise' ss.frameworks = 'Foundation' ss.ios.deployment_target = '8.0' @@ -152,7 +70,7 @@ Pod::Spec.new do |s| end s.subspec 'HealthKit' do |ss| - ss.source_files = Dir['Extensions/HealthKit/Sources/*'] + ss.source_files = 'Sources/PMKHealthKit/*' ss.dependency 'PromiseKit/CorePromise' ss.frameworks = 'HealthKit' ss.ios.deployment_target = '9.0' @@ -160,7 +78,7 @@ Pod::Spec.new do |s| end s.subspec 'HomeKit' do |ss| - ss.source_files = Dir['Extensions/HomeKit/Sources/*'] + ss.source_files = 'Sources/PMKHomeKit/*' ss.dependency 'PromiseKit/CorePromise' ss.frameworks = 'HomeKit' ss.ios.deployment_target = '8.0' @@ -169,7 +87,7 @@ Pod::Spec.new do |s| end s.subspec 'MapKit' do |ss| - ss.ios.source_files = ss.osx.source_files = ss.tvos.source_files = 'Extensions/MapKit/Sources/*' + ss.ios.source_files = ss.osx.source_files = ss.tvos.source_files = 'Sources/PMKMapKit/*' ss.ios.frameworks = ss.osx.frameworks = ss.tvos.frameworks = 'MapKit' ss.dependency 'PromiseKit/CorePromise' ss.ios.deployment_target = '8.0' @@ -178,100 +96,21 @@ Pod::Spec.new do |s| ss.tvos.deployment_target = '9.2' end - s.subspec 'MessageUI' do |ss| - ss.ios.source_files = 'Extensions/MessagesUI/Sources/*' - ss.ios.frameworks = 'MessageUI' - ss.dependency 'PromiseKit/CorePromise' - ss.ios.deployment_target = '8.0' - end - - s.subspec 'OMGHTTPURLRQ' do |ss| - ss.source_files = 'Extensions/OMGHTTPURLRQ/Sources/*' - ss.dependency 'PromiseKit/Foundation' - ss.dependency 'OMGHTTPURLRQ', '~> 3.2' - ss.ios.deployment_target = '8.0' - ss.osx.deployment_target = '10.10' - ss.watchos.deployment_target = '2.0' - ss.tvos.deployment_target = '9.0' - end - s.subspec 'Photos' do |ss| - ss.ios.source_files = ss.tvos.source_files = ss.osx.source_files = 'Extensions/Photos/Sources/*' + ss.ios.source_files = ss.tvos.source_files = ss.osx.source_files = 'Sources/PMKPhotos/*' ss.ios.frameworks = ss.tvos.frameworks = ss.osx.frameworks = 'Photos' ss.dependency 'PromiseKit/CorePromise' - ss.ios.deployment_target = '8.0' ss.osx.deployment_target = '10.13' ss.tvos.deployment_target = '10.0' end - s.subspec 'QuartzCore' do |ss| - ss.osx.source_files = ss.ios.source_files = ss.tvos.source_files = 'Extensions/QuartzCore/Sources/*' - ss.osx.frameworks = ss.ios.frameworks = ss.tvos.frameworks = 'QuartzCore' - ss.dependency 'PromiseKit/CorePromise' - ss.ios.deployment_target = '8.0' - ss.osx.deployment_target = '10.10' - ss.tvos.deployment_target = '9.0' - end - - s.subspec 'Social' do |ss| - ss.ios.source_files = 'Extensions/Social/Sources/*' - ss.osx.source_files = Dir['Extensions/Social/Sources/*'] - ['Categories/Social/Sources/*SLComposeViewController+Promise.swift'] - ss.ios.frameworks = ss.osx.frameworks = 'Social' - ss.dependency 'PromiseKit/Foundation' - ss.ios.deployment_target = '8.0' - ss.osx.deployment_target = '10.10' - end - s.subspec 'StoreKit' do |ss| - ss.ios.source_files = ss.osx.source_files = ss.tvos.source_files = 'Extensions/StoreKit/Sources/*' + ss.ios.source_files = ss.osx.source_files = ss.tvos.source_files = 'Sources/PMKStoreKit/*' ss.ios.frameworks = ss.osx.frameworks = ss.tvos.frameworks = 'StoreKit' ss.dependency 'PromiseKit/CorePromise' ss.ios.deployment_target = '8.0' ss.osx.deployment_target = '10.10' ss.tvos.deployment_target = '9.0' end - - s.subspec 'SystemConfiguration' do |ss| - ss.ios.source_files = ss.osx.source_files = ss.tvos.source_files = 'Extensions/SystemConfiguration/Sources/*' - ss.ios.frameworks = ss.osx.frameworks = ss.tvos.frameworks = 'SystemConfiguration' - ss.dependency 'PromiseKit/CorePromise' - ss.ios.deployment_target = '8.0' - ss.osx.deployment_target = '10.10' - ss.tvos.deployment_target = '9.0' - end - - picker_cc = 'Extensions/UIKit/Sources/UIImagePickerController+Promise.swift' - - s.subspec 'UIKit' do |ss| - ss.ios.source_files = ss.tvos.source_files = Dir['Extensions/UIKit/Sources/*'] - [picker_cc] - ss.tvos.frameworks = ss.ios.frameworks = 'UIKit' - ss.dependency 'PromiseKit/CorePromise' - ss.ios.deployment_target = '8.0' - ss.tvos.deployment_target = '9.0' - end - - s.subspec 'UIImagePickerController' do |ss| - # Since iOS 10, App Store submissions that contain references to - # UIImagePickerController (even if unused in 3rd party libraries) - # are rejected unless an Info.plist key is specified, thus we - # moved this code to a sub-subspec. - # - # This *was* a subspec of UIKit, but bizarrely CocoaPods would - # include this when specifying *just* UIKit…! - - ss.ios.source_files = picker_cc - ss.ios.frameworks = 'UIKit' - ss.ios.xcconfig = { "GCC_PREPROCESSOR_DEFINITIONS" => '$(inherited) PMKImagePickerController=1' } - ss.dependency 'PromiseKit/UIKit' - ss.ios.deployment_target = '8.0' - end - - s.subspec 'WatchConnectivity' do |ss| - ss.ios.source_files = ss.watchos.source_files = 'Extensions/WatchConnectivity/Sources/*' - ss.ios.frameworks = ss.watchos.frameworks = 'WatchConnectivity' - ss.dependency 'PromiseKit/CorePromise' - ss.ios.deployment_target = '8.0' - ss.watchos.deployment_target = '2.0' - end end diff --git a/PromiseKit.xcodeproj/project.pbxproj b/PromiseKit.xcodeproj/project.pbxproj deleted file mode 100644 index eeeecf1d4..000000000 --- a/PromiseKit.xcodeproj/project.pbxproj +++ /dev/null @@ -1,1230 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - 085B96B321A6359500E5E22F /* LoggingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 085B96B121A6358900E5E22F /* LoggingTests.swift */; }; - 085B96BF21A9B37C00E5E22F /* LogEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 085B96BE21A9B37C00E5E22F /* LogEvent.swift */; }; - 0C42F31B1FCF86320051309C /* HangTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C42F3191FCF86240051309C /* HangTests.swift */; }; - 0CC3AF2B1FCF84F7000E98C9 /* hang.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CC3AF2A1FCF84F7000E98C9 /* hang.swift */; }; - 49A5584D1DC5185900E4D01B /* ResolverTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49A5584B1DC5172F00E4D01B /* ResolverTests.swift */; }; - 630A8056203CEF6800D25F23 /* AnyPromiseTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 630A8051203CEF6800D25F23 /* AnyPromiseTests.m */; settings = {COMPILER_FLAGS = "-fobjc-arc-exceptions"; }; }; - 630A8057203CEF6800D25F23 /* PMKManifoldTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 630A8052203CEF6800D25F23 /* PMKManifoldTests.m */; }; - 630A8058203CEF6800D25F23 /* JoinTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 630A8053203CEF6800D25F23 /* JoinTests.m */; }; - 630A8059203CEF6800D25F23 /* HangTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 630A8054203CEF6800D25F23 /* HangTests.m */; }; - 630A805A203CEF6800D25F23 /* WhenTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 630A8055203CEF6800D25F23 /* WhenTests.m */; }; - 630A805B203CF67800D25F23 /* DefaultDispatchQueueTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 635D641B1D59635300BC0AF5 /* DefaultDispatchQueueTests.swift */; }; - 631411381D59795700E24B9E /* PromiseKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 63B0AC571D595E1B00FA21D9 /* PromiseKit.framework */; }; - 631411431D59797100E24B9E /* BridgingTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 6314113E1D59797100E24B9E /* BridgingTests.m */; }; - 631411441D59797100E24B9E /* BridgingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6314113F1D59797100E24B9E /* BridgingTests.swift */; }; - 631411451D59797100E24B9E /* Infrastructure.m in Sources */ = {isa = PBXBuildFile; fileRef = 631411411D59797100E24B9E /* Infrastructure.m */; }; - 631411461D59797100E24B9E /* Infrastructure.swift in Sources */ = {isa = PBXBuildFile; fileRef = 631411421D59797100E24B9E /* Infrastructure.swift */; }; - 631751A41D59766500A9DDDC /* PromiseKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 63B0AC571D595E1B00FA21D9 /* PromiseKit.framework */; }; - 631751B71D59768200A9DDDC /* 0.0.0.swift in Sources */ = {isa = PBXBuildFile; fileRef = 631751AB1D59768200A9DDDC /* 0.0.0.swift */; }; - 631751B81D59768200A9DDDC /* 2.1.2.swift in Sources */ = {isa = PBXBuildFile; fileRef = 631751AC1D59768200A9DDDC /* 2.1.2.swift */; }; - 631751B91D59768200A9DDDC /* 2.1.3.swift in Sources */ = {isa = PBXBuildFile; fileRef = 631751AD1D59768200A9DDDC /* 2.1.3.swift */; }; - 631751BA1D59768200A9DDDC /* 2.2.2.swift in Sources */ = {isa = PBXBuildFile; fileRef = 631751AE1D59768200A9DDDC /* 2.2.2.swift */; }; - 631751BB1D59768200A9DDDC /* 2.2.3.swift in Sources */ = {isa = PBXBuildFile; fileRef = 631751AF1D59768200A9DDDC /* 2.2.3.swift */; }; - 631751BC1D59768200A9DDDC /* 2.2.4.swift in Sources */ = {isa = PBXBuildFile; fileRef = 631751B01D59768200A9DDDC /* 2.2.4.swift */; }; - 631751BD1D59768200A9DDDC /* 2.2.6.swift in Sources */ = {isa = PBXBuildFile; fileRef = 631751B11D59768200A9DDDC /* 2.2.6.swift */; }; - 631751BE1D59768200A9DDDC /* 2.2.7.swift in Sources */ = {isa = PBXBuildFile; fileRef = 631751B21D59768200A9DDDC /* 2.2.7.swift */; }; - 631751BF1D59768200A9DDDC /* 2.3.1.swift in Sources */ = {isa = PBXBuildFile; fileRef = 631751B31D59768200A9DDDC /* 2.3.1.swift */; }; - 631751C01D59768200A9DDDC /* 2.3.2.swift in Sources */ = {isa = PBXBuildFile; fileRef = 631751B41D59768200A9DDDC /* 2.3.2.swift */; }; - 631751C11D59768200A9DDDC /* 2.3.4.swift in Sources */ = {isa = PBXBuildFile; fileRef = 631751B51D59768200A9DDDC /* 2.3.4.swift */; }; - 632FBBE31F33B273008F8FBB /* Catchable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 632FBBE21F33B273008F8FBB /* Catchable.swift */; }; - 632FBBE51F33B338008F8FBB /* CatchableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 632FBBE41F33B338008F8FBB /* CatchableTests.swift */; }; - 633027E6203CC0060037E136 /* PromiseKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 63B0AC571D595E1B00FA21D9 /* PromiseKit.framework */; }; - 6330B5E11F2E991200D60528 /* Configuration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6330B5E01F2E991200D60528 /* Configuration.swift */; }; - 634AAD2B1EAE517C00B17855 /* fwd.h in Headers */ = {isa = PBXBuildFile; fileRef = 634AAD2A1EAE517C00B17855 /* fwd.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 635D641D1D59635300BC0AF5 /* PromiseTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 635D64081D59635300BC0AF5 /* PromiseTests.swift */; }; - 635D641E1D59635300BC0AF5 /* CancellableErrorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 635D64091D59635300BC0AF5 /* CancellableErrorTests.swift */; }; - 635D64221D59635300BC0AF5 /* ZalgoTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 635D640D1D59635300BC0AF5 /* ZalgoTests.swift */; }; - 635D64231D59635300BC0AF5 /* AfterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 635D640E1D59635300BC0AF5 /* AfterTests.swift */; }; - 635D64261D59635300BC0AF5 /* WhenResolvedTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 635D64111D59635300BC0AF5 /* WhenResolvedTests.swift */; }; - 635D64271D59635300BC0AF5 /* RaceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 635D64121D59635300BC0AF5 /* RaceTests.swift */; }; - 635D64281D59635300BC0AF5 /* WhenConcurrentTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 635D64131D59635300BC0AF5 /* WhenConcurrentTests.swift */; }; - 635D642A1D59635300BC0AF5 /* WhenTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 635D64151D59635300BC0AF5 /* WhenTests.swift */; }; - 635D642B1D59635300BC0AF5 /* StressTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 635D64161D59635300BC0AF5 /* StressTests.swift */; }; - 635D642C1D59635300BC0AF5 /* RegressionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 635D64171D59635300BC0AF5 /* RegressionTests.swift */; }; - 635D64301D596E8500BC0AF5 /* PromiseKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 63B0AC571D595E1B00FA21D9 /* PromiseKit.framework */; }; - 636A291A1F1C156B001229C2 /* Promise.swift in Sources */ = {isa = PBXBuildFile; fileRef = 636A29191F1C156B001229C2 /* Promise.swift */; }; - 636A291F1F1C16FF001229C2 /* Box.swift in Sources */ = {isa = PBXBuildFile; fileRef = 636A291E1F1C16FF001229C2 /* Box.swift */; }; - 636A29211F1C1716001229C2 /* Thenable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 636A29201F1C1716001229C2 /* Thenable.swift */; }; - 636A29231F1C17A6001229C2 /* Guarantee.swift in Sources */ = {isa = PBXBuildFile; fileRef = 636A29221F1C17A6001229C2 /* Guarantee.swift */; }; - 636A29251F1C3089001229C2 /* race.swift in Sources */ = {isa = PBXBuildFile; fileRef = 636A29241F1C3089001229C2 /* race.swift */; }; - 636A29271F1C3927001229C2 /* Resolver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 636A29261F1C3927001229C2 /* Resolver.swift */; }; - 639BF757203DF03100FA577B /* Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = 639BF755203DF02C00FA577B /* Utilities.swift */; }; - 63B0AC7F1D595E6300FA21D9 /* after.m in Sources */ = {isa = PBXBuildFile; fileRef = 63B0AC611D595E6300FA21D9 /* after.m */; }; - 63B0AC801D595E6300FA21D9 /* after.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63B0AC621D595E6300FA21D9 /* after.swift */; }; - 63B0AC811D595E6300FA21D9 /* AnyPromise.h in Headers */ = {isa = PBXBuildFile; fileRef = 63B0AC631D595E6300FA21D9 /* AnyPromise.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 63B0AC821D595E6300FA21D9 /* AnyPromise.m in Sources */ = {isa = PBXBuildFile; fileRef = 63B0AC641D595E6300FA21D9 /* AnyPromise.m */; }; - 63B0AC831D595E6300FA21D9 /* AnyPromise.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63B0AC651D595E6300FA21D9 /* AnyPromise.swift */; }; - 63B0AC841D595E6300FA21D9 /* AnyPromise+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 63B0AC661D595E6300FA21D9 /* AnyPromise+Private.h */; settings = {ATTRIBUTES = (Private, ); }; }; - 63B0AC851D595E6300FA21D9 /* dispatch_promise.m in Sources */ = {isa = PBXBuildFile; fileRef = 63B0AC671D595E6300FA21D9 /* dispatch_promise.m */; }; - 63B0AC871D595E6300FA21D9 /* Error.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63B0AC691D595E6300FA21D9 /* Error.swift */; }; - 63B0AC891D595E6300FA21D9 /* hang.m in Sources */ = {isa = PBXBuildFile; fileRef = 63B0AC6B1D595E6300FA21D9 /* hang.m */; }; - 63B0AC8B1D595E6300FA21D9 /* join.m in Sources */ = {isa = PBXBuildFile; fileRef = 63B0AC6D1D595E6300FA21D9 /* join.m */; }; - 63B0AC931D595E6300FA21D9 /* PromiseKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 63B0AC761D595E6300FA21D9 /* PromiseKit.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 63B0AC991D595E6300FA21D9 /* when.m in Sources */ = {isa = PBXBuildFile; fileRef = 63B0AC7C1D595E6300FA21D9 /* when.m */; }; - 63B0AC9A1D595E6300FA21D9 /* when.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63B0AC7D1D595E6300FA21D9 /* when.swift */; }; - 63B18AEC1F2D205C00B79E37 /* CustomStringConvertible.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63B18AEB1F2D205C00B79E37 /* CustomStringConvertible.swift */; }; - 63B7C94B203E2B8200FBEC00 /* AnyPromiseTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63B7C94A203E2B8200FBEC00 /* AnyPromiseTests.swift */; }; - 63B912AA1F1D7B1300D49110 /* firstly.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63B912A91F1D7B1300D49110 /* firstly.swift */; }; - 63CF6D7A203CC66000EC8927 /* ErrorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63CF6D79203CC66000EC8927 /* ErrorTests.swift */; }; - 63CF6D7C203CCDAB00EC8927 /* GuaranteeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63CF6D7B203CCDAB00EC8927 /* GuaranteeTests.swift */; }; - 63CF6D7E203CD12700EC8927 /* DeprecationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63648C94203CB97400EBA011 /* DeprecationTests.swift */; }; - 63CF6D80203CD19200EC8927 /* ThenableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63CF6D7F203CD19200EC8927 /* ThenableTests.swift */; }; - 63D9B2EF203385FD0075C00B /* race.m in Sources */ = {isa = PBXBuildFile; fileRef = 63D9B2EE203385FD0075C00B /* race.m */; }; - 63D9B2F120338D5D0075C00B /* Deprecations.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63D9B2F020338D5D0075C00B /* Deprecations.swift */; }; - C013F7382048E3B6006B57B1 /* MockNodeEnvironment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C013F7372048E3B6006B57B1 /* MockNodeEnvironment.swift */; }; - C013F73A2049076A006B57B1 /* JSPromise.swift in Sources */ = {isa = PBXBuildFile; fileRef = C013F7392049076A006B57B1 /* JSPromise.swift */; }; - C013F73C20494291006B57B1 /* JSAdapter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C013F73B20494291006B57B1 /* JSAdapter.swift */; }; - C013F740204E5064006B57B1 /* JSUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = C013F73F204E5063006B57B1 /* JSUtils.swift */; }; - C0244E5E2047A6CB00ACB4AC /* PromiseKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 63B0AC571D595E1B00FA21D9 /* PromiseKit.framework */; }; - C0244E692047AC9F00ACB4AC /* AllTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0244E682047AC9F00ACB4AC /* AllTests.swift */; }; -/* End PBXBuildFile section */ - -/* Begin PBXContainerItemProxy section */ - 631411341D59795700E24B9E /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 6399A3721D595D9100D65233 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 63B0AC561D595E1B00FA21D9; - remoteInfo = PromiseKit; - }; - 6317518D1D59766500A9DDDC /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 6399A3721D595D9100D65233 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 63B0AC561D595E1B00FA21D9; - remoteInfo = PromiseKit; - }; - 633027E2203CC0060037E136 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 6399A3721D595D9100D65233 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 63B0AC561D595E1B00FA21D9; - remoteInfo = PromiseKit; - }; - 635D64041D5962F900BC0AF5 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 6399A3721D595D9100D65233 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 63B0AC561D595E1B00FA21D9; - remoteInfo = PromiseKit; - }; - C0244E502047A6CB00ACB4AC /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 6399A3721D595D9100D65233 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 63B0AC561D595E1B00FA21D9; - remoteInfo = PromiseKit; - }; -/* End PBXContainerItemProxy section */ - -/* Begin PBXCopyFilesBuildPhase section */ - C0244E6E2047AF0B00ACB4AC /* CopyFiles */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 7; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - -/* Begin PBXFileReference section */ - 085B96B121A6358900E5E22F /* LoggingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoggingTests.swift; sourceTree = ""; }; - 085B96BE21A9B37C00E5E22F /* LogEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = LogEvent.swift; path = Sources/LogEvent.swift; sourceTree = ""; }; - 0C42F3191FCF86240051309C /* HangTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HangTests.swift; sourceTree = ""; }; - 0CC3AF2A1FCF84F7000E98C9 /* hang.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = hang.swift; path = Sources/hang.swift; sourceTree = ""; }; - 49A5584B1DC5172F00E4D01B /* ResolverTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ResolverTests.swift; sourceTree = ""; }; - 630019221D596292003B4E30 /* PMKCoreTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = PMKCoreTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 630A8051203CEF6800D25F23 /* AnyPromiseTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AnyPromiseTests.m; sourceTree = ""; }; - 630A8052203CEF6800D25F23 /* PMKManifoldTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PMKManifoldTests.m; sourceTree = ""; }; - 630A8053203CEF6800D25F23 /* JoinTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JoinTests.m; sourceTree = ""; }; - 630A8054203CEF6800D25F23 /* HangTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HangTests.m; sourceTree = ""; }; - 630A8055203CEF6800D25F23 /* WhenTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WhenTests.m; sourceTree = ""; }; - 6314113C1D59795700E24B9E /* PMKBridgeTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = PMKBridgeTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 6314113E1D59797100E24B9E /* BridgingTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BridgingTests.m; sourceTree = ""; }; - 6314113F1D59797100E24B9E /* BridgingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BridgingTests.swift; sourceTree = ""; }; - 631411401D59797100E24B9E /* Infrastructure.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Infrastructure.h; sourceTree = ""; }; - 631411411D59797100E24B9E /* Infrastructure.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Infrastructure.m; sourceTree = ""; }; - 631411421D59797100E24B9E /* Infrastructure.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Infrastructure.swift; sourceTree = ""; }; - 631751A81D59766500A9DDDC /* PMKA+Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "PMKA+Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; - 631751AB1D59768200A9DDDC /* 0.0.0.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = 0.0.0.swift; sourceTree = ""; }; - 631751AC1D59768200A9DDDC /* 2.1.2.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = 2.1.2.swift; sourceTree = ""; }; - 631751AD1D59768200A9DDDC /* 2.1.3.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = 2.1.3.swift; sourceTree = ""; }; - 631751AE1D59768200A9DDDC /* 2.2.2.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = 2.2.2.swift; sourceTree = ""; }; - 631751AF1D59768200A9DDDC /* 2.2.3.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = 2.2.3.swift; sourceTree = ""; }; - 631751B01D59768200A9DDDC /* 2.2.4.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = 2.2.4.swift; sourceTree = ""; }; - 631751B11D59768200A9DDDC /* 2.2.6.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = 2.2.6.swift; sourceTree = ""; }; - 631751B21D59768200A9DDDC /* 2.2.7.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = 2.2.7.swift; sourceTree = ""; }; - 631751B31D59768200A9DDDC /* 2.3.1.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = 2.3.1.swift; sourceTree = ""; }; - 631751B41D59768200A9DDDC /* 2.3.2.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = 2.3.2.swift; sourceTree = ""; }; - 631751B51D59768200A9DDDC /* 2.3.4.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = 2.3.4.swift; sourceTree = ""; }; - 631751B61D59768200A9DDDC /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; - 632FBBE21F33B273008F8FBB /* Catchable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Catchable.swift; path = Sources/Catchable.swift; sourceTree = ""; }; - 632FBBE41F33B338008F8FBB /* CatchableTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CatchableTests.swift; sourceTree = ""; }; - 633027EA203CC0060037E136 /* PMKDeprecatedTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = PMKDeprecatedTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 6330B5E01F2E991200D60528 /* Configuration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Configuration.swift; path = Sources/Configuration.swift; sourceTree = ""; }; - 634AAD2A1EAE517C00B17855 /* fwd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = fwd.h; path = Sources/fwd.h; sourceTree = ""; }; - 635893921D5BE4E000F14B55 /* PromiseKit.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = PromiseKit.playground; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; - 635893941D5BE4F900F14B55 /* LICENSE */ = {isa = PBXFileReference; lastKnownFileType = text; path = LICENSE; sourceTree = ""; }; - 635893951D5BE4F900F14B55 /* Package.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Package.swift; sourceTree = ""; }; - 635893961D5BE4F900F14B55 /* PromiseKit.podspec */ = {isa = PBXFileReference; lastKnownFileType = text; name = PromiseKit.podspec; path = .github/PromiseKit.podspec; sourceTree = ""; }; - 635893971D5BE4F900F14B55 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; - 635D64081D59635300BC0AF5 /* PromiseTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PromiseTests.swift; sourceTree = ""; }; - 635D64091D59635300BC0AF5 /* CancellableErrorTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CancellableErrorTests.swift; sourceTree = ""; }; - 635D640D1D59635300BC0AF5 /* ZalgoTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ZalgoTests.swift; sourceTree = ""; }; - 635D640E1D59635300BC0AF5 /* AfterTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AfterTests.swift; sourceTree = ""; }; - 635D64111D59635300BC0AF5 /* WhenResolvedTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WhenResolvedTests.swift; sourceTree = ""; }; - 635D64121D59635300BC0AF5 /* RaceTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RaceTests.swift; sourceTree = ""; }; - 635D64131D59635300BC0AF5 /* WhenConcurrentTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WhenConcurrentTests.swift; sourceTree = ""; }; - 635D64151D59635300BC0AF5 /* WhenTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WhenTests.swift; sourceTree = ""; }; - 635D64161D59635300BC0AF5 /* StressTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StressTests.swift; sourceTree = ""; }; - 635D64171D59635300BC0AF5 /* RegressionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RegressionTests.swift; sourceTree = ""; }; - 635D641B1D59635300BC0AF5 /* DefaultDispatchQueueTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DefaultDispatchQueueTests.swift; sourceTree = ""; }; - 63648C94203CB97400EBA011 /* DeprecationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = DeprecationTests.swift; path = Tests/DeprecationTests.swift; sourceTree = ""; }; - 636A29191F1C156B001229C2 /* Promise.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Promise.swift; path = Sources/Promise.swift; sourceTree = ""; }; - 636A291E1F1C16FF001229C2 /* Box.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Box.swift; path = Sources/Box.swift; sourceTree = ""; }; - 636A29201F1C1716001229C2 /* Thenable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Thenable.swift; path = Sources/Thenable.swift; sourceTree = ""; }; - 636A29221F1C17A6001229C2 /* Guarantee.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Guarantee.swift; path = Sources/Guarantee.swift; sourceTree = ""; }; - 636A29241F1C3089001229C2 /* race.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = race.swift; path = Sources/race.swift; sourceTree = ""; }; - 636A29261F1C3927001229C2 /* Resolver.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Resolver.swift; path = Sources/Resolver.swift; sourceTree = ""; }; - 639BF755203DF02C00FA577B /* Utilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Utilities.swift; sourceTree = ""; }; - 63B0AC571D595E1B00FA21D9 /* PromiseKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = PromiseKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 63B0AC611D595E6300FA21D9 /* after.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = after.m; path = Sources/after.m; sourceTree = ""; }; - 63B0AC621D595E6300FA21D9 /* after.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = after.swift; path = Sources/after.swift; sourceTree = ""; }; - 63B0AC631D595E6300FA21D9 /* AnyPromise.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AnyPromise.h; path = Sources/AnyPromise.h; sourceTree = ""; }; - 63B0AC641D595E6300FA21D9 /* AnyPromise.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AnyPromise.m; path = Sources/AnyPromise.m; sourceTree = ""; }; - 63B0AC651D595E6300FA21D9 /* AnyPromise.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AnyPromise.swift; path = Sources/AnyPromise.swift; sourceTree = ""; }; - 63B0AC661D595E6300FA21D9 /* AnyPromise+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "AnyPromise+Private.h"; path = "Sources/AnyPromise+Private.h"; sourceTree = ""; }; - 63B0AC671D595E6300FA21D9 /* dispatch_promise.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = dispatch_promise.m; path = Sources/dispatch_promise.m; sourceTree = ""; }; - 63B0AC691D595E6300FA21D9 /* Error.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Error.swift; path = Sources/Error.swift; sourceTree = ""; }; - 63B0AC6B1D595E6300FA21D9 /* hang.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = hang.m; path = Sources/hang.m; sourceTree = ""; }; - 63B0AC6C1D595E6300FA21D9 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = Sources/Info.plist; sourceTree = ""; }; - 63B0AC6D1D595E6300FA21D9 /* join.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = join.m; path = Sources/join.m; sourceTree = ""; }; - 63B0AC6F1D595E6300FA21D9 /* NSMethodSignatureForBlock.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = NSMethodSignatureForBlock.m; path = Sources/NSMethodSignatureForBlock.m; sourceTree = ""; }; - 63B0AC711D595E6300FA21D9 /* PMKCallVariadicBlock.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = PMKCallVariadicBlock.m; path = Sources/PMKCallVariadicBlock.m; sourceTree = ""; }; - 63B0AC761D595E6300FA21D9 /* PromiseKit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PromiseKit.h; path = Sources/PromiseKit.h; sourceTree = ""; }; - 63B0AC7C1D595E6300FA21D9 /* when.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = when.m; path = Sources/when.m; sourceTree = ""; }; - 63B0AC7D1D595E6300FA21D9 /* when.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = when.swift; path = Sources/when.swift; sourceTree = ""; }; - 63B18AEB1F2D205C00B79E37 /* CustomStringConvertible.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CustomStringConvertible.swift; path = Sources/CustomStringConvertible.swift; sourceTree = ""; }; - 63B7C94A203E2B8200FBEC00 /* AnyPromiseTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnyPromiseTests.swift; sourceTree = ""; }; - 63B912A91F1D7B1300D49110 /* firstly.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = firstly.swift; path = Sources/firstly.swift; sourceTree = ""; }; - 63CF6D79203CC66000EC8927 /* ErrorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorTests.swift; sourceTree = ""; }; - 63CF6D7B203CCDAB00EC8927 /* GuaranteeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GuaranteeTests.swift; sourceTree = ""; }; - 63CF6D7F203CD19200EC8927 /* ThenableTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThenableTests.swift; sourceTree = ""; }; - 63D9B2EE203385FD0075C00B /* race.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = race.m; path = Sources/race.m; sourceTree = ""; }; - 63D9B2F020338D5D0075C00B /* Deprecations.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = Deprecations.swift; path = Sources/Deprecations.swift; sourceTree = ""; }; - C013F7372048E3B6006B57B1 /* MockNodeEnvironment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MockNodeEnvironment.swift; path = "Tests/JS-A+/MockNodeEnvironment.swift"; sourceTree = ""; }; - C013F7392049076A006B57B1 /* JSPromise.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = JSPromise.swift; path = "Tests/JS-A+/JSPromise.swift"; sourceTree = ""; }; - C013F73B20494291006B57B1 /* JSAdapter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = JSAdapter.swift; path = "Tests/JS-A+/JSAdapter.swift"; sourceTree = ""; }; - C013F73F204E5063006B57B1 /* JSUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = JSUtils.swift; path = "Tests/JS-A+/JSUtils.swift"; sourceTree = ""; }; - C0244E622047A6CB00ACB4AC /* PMKJSA+Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "PMKJSA+Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; - C0244E682047AC9F00ACB4AC /* AllTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AllTests.swift; path = "Tests/JS-A+/AllTests.swift"; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 630019181D596292003B4E30 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 635D64301D596E8500BC0AF5 /* PromiseKit.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 631411371D59795700E24B9E /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 631411381D59795700E24B9E /* PromiseKit.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 631751A31D59766500A9DDDC /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 631751A41D59766500A9DDDC /* PromiseKit.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 633027E5203CC0060037E136 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 633027E6203CC0060037E136 /* PromiseKit.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 63B0AC531D595E1B00FA21D9 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - C0244E5D2047A6CB00ACB4AC /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - C0244E5E2047A6CB00ACB4AC /* PromiseKit.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 630A8050203CEF6800D25F23 /* CoreObjC */ = { - isa = PBXGroup; - children = ( - 630A8051203CEF6800D25F23 /* AnyPromiseTests.m */, - 63B7C94A203E2B8200FBEC00 /* AnyPromiseTests.swift */, - 630A8052203CEF6800D25F23 /* PMKManifoldTests.m */, - 630A8053203CEF6800D25F23 /* JoinTests.m */, - 630A8054203CEF6800D25F23 /* HangTests.m */, - 630A8055203CEF6800D25F23 /* WhenTests.m */, - ); - name = CoreObjC; - path = Tests/CoreObjC; - sourceTree = ""; - }; - 630B60BF1F2F739E00A1AEFE /* Features */ = { - isa = PBXGroup; - children = ( - 63B0AC611D595E6300FA21D9 /* after.m */, - 63B0AC6B1D595E6300FA21D9 /* hang.m */, - 63B0AC6D1D595E6300FA21D9 /* join.m */, - 63B0AC7C1D595E6300FA21D9 /* when.m */, - 63D9B2EE203385FD0075C00B /* race.m */, - ); - name = Features; - sourceTree = ""; - }; - 630B60C01F2F73B000A1AEFE /* Headers */ = { - isa = PBXGroup; - children = ( - 634AAD2A1EAE517C00B17855 /* fwd.h */, - 63B0AC631D595E6300FA21D9 /* AnyPromise.h */, - ); - name = Headers; - sourceTree = ""; - }; - 6314113D1D59797100E24B9E /* Bridging */ = { - isa = PBXGroup; - children = ( - 6314113E1D59797100E24B9E /* BridgingTests.m */, - 6314113F1D59797100E24B9E /* BridgingTests.swift */, - 631411401D59797100E24B9E /* Infrastructure.h */, - 631411411D59797100E24B9E /* Infrastructure.m */, - 631411421D59797100E24B9E /* Infrastructure.swift */, - ); - name = Bridging; - path = Tests/Bridging; - sourceTree = ""; - }; - 6317518A1D59765700A9DDDC /* Core */ = { - isa = PBXGroup; - children = ( - 63CF6D7F203CD19200EC8927 /* ThenableTests.swift */, - 632FBBE41F33B338008F8FBB /* CatchableTests.swift */, - 635D64081D59635300BC0AF5 /* PromiseTests.swift */, - 49A5584B1DC5172F00E4D01B /* ResolverTests.swift */, - 63CF6D7B203CCDAB00EC8927 /* GuaranteeTests.swift */, - 635D64091D59635300BC0AF5 /* CancellableErrorTests.swift */, - 63CF6D79203CC66000EC8927 /* ErrorTests.swift */, - 635D64151D59635300BC0AF5 /* WhenTests.swift */, - 635D64131D59635300BC0AF5 /* WhenConcurrentTests.swift */, - 635D64111D59635300BC0AF5 /* WhenResolvedTests.swift */, - 635D640E1D59635300BC0AF5 /* AfterTests.swift */, - 0C42F3191FCF86240051309C /* HangTests.swift */, - 635D64121D59635300BC0AF5 /* RaceTests.swift */, - 635D641B1D59635300BC0AF5 /* DefaultDispatchQueueTests.swift */, - 635D64171D59635300BC0AF5 /* RegressionTests.swift */, - 635D64161D59635300BC0AF5 /* StressTests.swift */, - 635D640D1D59635300BC0AF5 /* ZalgoTests.swift */, - 639BF755203DF02C00FA577B /* Utilities.swift */, - 085B96B121A6358900E5E22F /* LoggingTests.swift */, - ); - name = Core; - path = Tests/CorePromise; - sourceTree = ""; - }; - 631751AA1D59768200A9DDDC /* A+ */ = { - isa = PBXGroup; - children = ( - 631751AB1D59768200A9DDDC /* 0.0.0.swift */, - 631751AC1D59768200A9DDDC /* 2.1.2.swift */, - 631751AD1D59768200A9DDDC /* 2.1.3.swift */, - 631751AE1D59768200A9DDDC /* 2.2.2.swift */, - 631751AF1D59768200A9DDDC /* 2.2.3.swift */, - 631751B01D59768200A9DDDC /* 2.2.4.swift */, - 631751B11D59768200A9DDDC /* 2.2.6.swift */, - 631751B21D59768200A9DDDC /* 2.2.7.swift */, - 631751B31D59768200A9DDDC /* 2.3.1.swift */, - 631751B41D59768200A9DDDC /* 2.3.2.swift */, - 631751B51D59768200A9DDDC /* 2.3.4.swift */, - 631751B61D59768200A9DDDC /* README.md */, - ); - name = "A+"; - path = "Tests/A+"; - sourceTree = ""; - }; - 635893991D5BE51700F14B55 /* … */ = { - isa = PBXGroup; - children = ( - 63B0AC581D595E1B00FA21D9 /* Products */, - 63B0AC6C1D595E6300FA21D9 /* Info.plist */, - 635893941D5BE4F900F14B55 /* LICENSE */, - 635893951D5BE4F900F14B55 /* Package.swift */, - 635893961D5BE4F900F14B55 /* PromiseKit.podspec */, - ); - name = "…"; - sourceTree = ""; - }; - 635D64061D59630200BC0AF5 /* Tests */ = { - isa = PBXGroup; - children = ( - C0244E6B2047ACAF00ACB4AC /* JS/A+ */, - 631751AA1D59768200A9DDDC /* A+ */, - 6314113D1D59797100E24B9E /* Bridging */, - 6317518A1D59765700A9DDDC /* Core */, - 630A8050203CEF6800D25F23 /* CoreObjC */, - 63648C94203CB97400EBA011 /* DeprecationTests.swift */, - ); - name = Tests; - sourceTree = ""; - }; - 6399A3711D595D9100D65233 = { - isa = PBXGroup; - children = ( - 635893971D5BE4F900F14B55 /* README.md */, - 635893921D5BE4E000F14B55 /* PromiseKit.playground */, - 63B0AC761D595E6300FA21D9 /* PromiseKit.h */, - 63B0AC601D595E4C00FA21D9 /* Sources.swift */, - 63B912AB1F1E657400D49110 /* Sources.objc */, - 635D64061D59630200BC0AF5 /* Tests */, - 635893991D5BE51700F14B55 /* … */, - ); - sourceTree = ""; - }; - 63B0AC581D595E1B00FA21D9 /* Products */ = { - isa = PBXGroup; - children = ( - 63B0AC571D595E1B00FA21D9 /* PromiseKit.framework */, - 630019221D596292003B4E30 /* PMKCoreTests.xctest */, - 631751A81D59766500A9DDDC /* PMKA+Tests.xctest */, - 6314113C1D59795700E24B9E /* PMKBridgeTests.xctest */, - 633027EA203CC0060037E136 /* PMKDeprecatedTests.xctest */, - C0244E622047A6CB00ACB4AC /* PMKJSA+Tests.xctest */, - ); - name = Products; - sourceTree = ""; - }; - 63B0AC601D595E4C00FA21D9 /* Sources.swift */ = { - isa = PBXGroup; - children = ( - 636A29191F1C156B001229C2 /* Promise.swift */, - 636A29221F1C17A6001229C2 /* Guarantee.swift */, - 636A29201F1C1716001229C2 /* Thenable.swift */, - 632FBBE21F33B273008F8FBB /* Catchable.swift */, - 63B912AC1F1E663E00D49110 /* Features */, - 63B0AC691D595E6300FA21D9 /* Error.swift */, - 636A29261F1C3927001229C2 /* Resolver.swift */, - 636A291E1F1C16FF001229C2 /* Box.swift */, - 6330B5E01F2E991200D60528 /* Configuration.swift */, - 63B18AEB1F2D205C00B79E37 /* CustomStringConvertible.swift */, - 63D9B2F020338D5D0075C00B /* Deprecations.swift */, - 085B96BE21A9B37C00E5E22F /* LogEvent.swift */, - ); - name = Sources.swift; - sourceTree = ""; - }; - 63B0AC9D1D595E6E00FA21D9 /* Internal Utilities */ = { - isa = PBXGroup; - children = ( - 63B0AC661D595E6300FA21D9 /* AnyPromise+Private.h */, - 63B0AC6F1D595E6300FA21D9 /* NSMethodSignatureForBlock.m */, - 63B0AC711D595E6300FA21D9 /* PMKCallVariadicBlock.m */, - ); - name = "Internal Utilities"; - sourceTree = ""; - }; - 63B912AB1F1E657400D49110 /* Sources.objc */ = { - isa = PBXGroup; - children = ( - 63B0AC641D595E6300FA21D9 /* AnyPromise.m */, - 63B0AC651D595E6300FA21D9 /* AnyPromise.swift */, - 63B0AC671D595E6300FA21D9 /* dispatch_promise.m */, - 630B60C01F2F73B000A1AEFE /* Headers */, - 630B60BF1F2F739E00A1AEFE /* Features */, - 63B0AC9D1D595E6E00FA21D9 /* Internal Utilities */, - ); - name = Sources.objc; - sourceTree = ""; - }; - 63B912AC1F1E663E00D49110 /* Features */ = { - isa = PBXGroup; - children = ( - 0CC3AF2A1FCF84F7000E98C9 /* hang.swift */, - 63B0AC621D595E6300FA21D9 /* after.swift */, - 63B912A91F1D7B1300D49110 /* firstly.swift */, - 636A29241F1C3089001229C2 /* race.swift */, - 63B0AC7D1D595E6300FA21D9 /* when.swift */, - ); - name = Features; - sourceTree = ""; - }; - C0244E6B2047ACAF00ACB4AC /* JS/A+ */ = { - isa = PBXGroup; - children = ( - C0244E682047AC9F00ACB4AC /* AllTests.swift */, - C013F7372048E3B6006B57B1 /* MockNodeEnvironment.swift */, - C013F7392049076A006B57B1 /* JSPromise.swift */, - C013F73B20494291006B57B1 /* JSAdapter.swift */, - C013F73F204E5063006B57B1 /* JSUtils.swift */, - ); - name = "JS/A+"; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXHeadersBuildPhase section */ - 63B0AC541D595E1B00FA21D9 /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - 63B0AC931D595E6300FA21D9 /* PromiseKit.h in Headers */, - 634AAD2B1EAE517C00B17855 /* fwd.h in Headers */, - 63B0AC811D595E6300FA21D9 /* AnyPromise.h in Headers */, - 63B0AC841D595E6300FA21D9 /* AnyPromise+Private.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXHeadersBuildPhase section */ - -/* Begin PBXNativeTarget section */ - 630019011D596292003B4E30 /* PMKCoreTests */ = { - isa = PBXNativeTarget; - buildConfigurationList = 6300191F1D596292003B4E30 /* Build configuration list for PBXNativeTarget "PMKCoreTests" */; - buildPhases = ( - 630019021D596292003B4E30 /* Sources */, - 630019181D596292003B4E30 /* Frameworks */, - ); - buildRules = ( - ); - dependencies = ( - 635D64051D5962F900BC0AF5 /* PBXTargetDependency */, - ); - name = PMKCoreTests; - productName = PromiseKit; - productReference = 630019221D596292003B4E30 /* PMKCoreTests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; - 631411321D59795700E24B9E /* PMKBridgeTests */ = { - isa = PBXNativeTarget; - buildConfigurationList = 631411391D59795700E24B9E /* Build configuration list for PBXNativeTarget "PMKBridgeTests" */; - buildPhases = ( - 631411351D59795700E24B9E /* Sources */, - 631411371D59795700E24B9E /* Frameworks */, - ); - buildRules = ( - ); - dependencies = ( - 631411331D59795700E24B9E /* PBXTargetDependency */, - ); - name = PMKBridgeTests; - productName = PromiseKit; - productReference = 6314113C1D59795700E24B9E /* PMKBridgeTests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; - 6317518B1D59766500A9DDDC /* PMKA+Tests */ = { - isa = PBXNativeTarget; - buildConfigurationList = 631751A51D59766500A9DDDC /* Build configuration list for PBXNativeTarget "PMKA+Tests" */; - buildPhases = ( - 6317518E1D59766500A9DDDC /* Sources */, - 631751A31D59766500A9DDDC /* Frameworks */, - ); - buildRules = ( - ); - dependencies = ( - 6317518C1D59766500A9DDDC /* PBXTargetDependency */, - ); - name = "PMKA+Tests"; - productName = PromiseKit; - productReference = 631751A81D59766500A9DDDC /* PMKA+Tests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; - 633027E0203CC0060037E136 /* PMKDeprecatedTests */ = { - isa = PBXNativeTarget; - buildConfigurationList = 633027E7203CC0060037E136 /* Build configuration list for PBXNativeTarget "PMKDeprecatedTests" */; - buildPhases = ( - 633027E3203CC0060037E136 /* Sources */, - 633027E5203CC0060037E136 /* Frameworks */, - ); - buildRules = ( - ); - dependencies = ( - 633027E1203CC0060037E136 /* PBXTargetDependency */, - ); - name = PMKDeprecatedTests; - productName = PromiseKit; - productReference = 633027EA203CC0060037E136 /* PMKDeprecatedTests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; - 63B0AC561D595E1B00FA21D9 /* PromiseKit */ = { - isa = PBXNativeTarget; - buildConfigurationList = 63B0AC5F1D595E1B00FA21D9 /* Build configuration list for PBXNativeTarget "PromiseKit" */; - buildPhases = ( - 63B0AC521D595E1B00FA21D9 /* Sources */, - 63B0AC531D595E1B00FA21D9 /* Frameworks */, - 63B0AC541D595E1B00FA21D9 /* Headers */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = PromiseKit; - productName = PromiseKit; - productReference = 63B0AC571D595E1B00FA21D9 /* PromiseKit.framework */; - productType = "com.apple.product-type.framework"; - }; - C0244E4E2047A6CB00ACB4AC /* PMKJSA+Tests */ = { - isa = PBXNativeTarget; - buildConfigurationList = C0244E5F2047A6CB00ACB4AC /* Build configuration list for PBXNativeTarget "PMKJSA+Tests" */; - buildPhases = ( - C0244E512047A6CB00ACB4AC /* Sources */, - C0244E5D2047A6CB00ACB4AC /* Frameworks */, - C0244E6E2047AF0B00ACB4AC /* CopyFiles */, - ); - buildRules = ( - ); - dependencies = ( - C0244E4F2047A6CB00ACB4AC /* PBXTargetDependency */, - ); - name = "PMKJSA+Tests"; - productName = PromiseKit; - productReference = C0244E622047A6CB00ACB4AC /* PMKJSA+Tests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 6399A3721D595D9100D65233 /* Project object */ = { - isa = PBXProject; - attributes = { - LastUpgradeCheck = 1250; - TargetAttributes = { - 630019011D596292003B4E30 = { - LastSwiftMigration = 1100; - }; - 631411321D59795700E24B9E = { - LastSwiftMigration = 1100; - }; - 6317518B1D59766500A9DDDC = { - LastSwiftMigration = 1100; - }; - 633027E0203CC0060037E136 = { - LastSwiftMigration = 1100; - }; - 63B0AC561D595E1B00FA21D9 = { - CreatedOnToolsVersion = 8.0; - LastSwiftMigration = 1100; - ProvisioningStyle = Automatic; - }; - C0244E4E2047A6CB00ACB4AC = { - LastSwiftMigration = 1100; - }; - }; - }; - buildConfigurationList = 6399A3751D595D9100D65233 /* Build configuration list for PBXProject "PromiseKit" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 6399A3711D595D9100D65233; - productRefGroup = 63B0AC581D595E1B00FA21D9 /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 63B0AC561D595E1B00FA21D9 /* PromiseKit */, - 6317518B1D59766500A9DDDC /* PMKA+Tests */, - 631411321D59795700E24B9E /* PMKBridgeTests */, - 630019011D596292003B4E30 /* PMKCoreTests */, - 633027E0203CC0060037E136 /* PMKDeprecatedTests */, - C0244E4E2047A6CB00ACB4AC /* PMKJSA+Tests */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXSourcesBuildPhase section */ - 630019021D596292003B4E30 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 0C42F31B1FCF86320051309C /* HangTests.swift in Sources */, - 635D641E1D59635300BC0AF5 /* CancellableErrorTests.swift in Sources */, - 630A8056203CEF6800D25F23 /* AnyPromiseTests.m in Sources */, - 635D64221D59635300BC0AF5 /* ZalgoTests.swift in Sources */, - 635D64271D59635300BC0AF5 /* RaceTests.swift in Sources */, - 632FBBE51F33B338008F8FBB /* CatchableTests.swift in Sources */, - 63CF6D80203CD19200EC8927 /* ThenableTests.swift in Sources */, - 635D642B1D59635300BC0AF5 /* StressTests.swift in Sources */, - 630A805A203CEF6800D25F23 /* WhenTests.m in Sources */, - 630A805B203CF67800D25F23 /* DefaultDispatchQueueTests.swift in Sources */, - 635D641D1D59635300BC0AF5 /* PromiseTests.swift in Sources */, - 63CF6D7C203CCDAB00EC8927 /* GuaranteeTests.swift in Sources */, - 639BF757203DF03100FA577B /* Utilities.swift in Sources */, - 635D64261D59635300BC0AF5 /* WhenResolvedTests.swift in Sources */, - 635D64231D59635300BC0AF5 /* AfterTests.swift in Sources */, - 63CF6D7A203CC66000EC8927 /* ErrorTests.swift in Sources */, - 49A5584D1DC5185900E4D01B /* ResolverTests.swift in Sources */, - 630A8057203CEF6800D25F23 /* PMKManifoldTests.m in Sources */, - 085B96B321A6359500E5E22F /* LoggingTests.swift in Sources */, - 63B7C94B203E2B8200FBEC00 /* AnyPromiseTests.swift in Sources */, - 630A8059203CEF6800D25F23 /* HangTests.m in Sources */, - 635D642A1D59635300BC0AF5 /* WhenTests.swift in Sources */, - 630A8058203CEF6800D25F23 /* JoinTests.m in Sources */, - 635D64281D59635300BC0AF5 /* WhenConcurrentTests.swift in Sources */, - 635D642C1D59635300BC0AF5 /* RegressionTests.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 631411351D59795700E24B9E /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 631411461D59797100E24B9E /* Infrastructure.swift in Sources */, - 631411431D59797100E24B9E /* BridgingTests.m in Sources */, - 631411441D59797100E24B9E /* BridgingTests.swift in Sources */, - 631411451D59797100E24B9E /* Infrastructure.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 6317518E1D59766500A9DDDC /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 631751C11D59768200A9DDDC /* 2.3.4.swift in Sources */, - 631751BA1D59768200A9DDDC /* 2.2.2.swift in Sources */, - 631751BF1D59768200A9DDDC /* 2.3.1.swift in Sources */, - 631751B91D59768200A9DDDC /* 2.1.3.swift in Sources */, - 631751BD1D59768200A9DDDC /* 2.2.6.swift in Sources */, - 631751B71D59768200A9DDDC /* 0.0.0.swift in Sources */, - 631751C01D59768200A9DDDC /* 2.3.2.swift in Sources */, - 631751B81D59768200A9DDDC /* 2.1.2.swift in Sources */, - 631751BE1D59768200A9DDDC /* 2.2.7.swift in Sources */, - 631751BC1D59768200A9DDDC /* 2.2.4.swift in Sources */, - 631751BB1D59768200A9DDDC /* 2.2.3.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 633027E3203CC0060037E136 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 63CF6D7E203CD12700EC8927 /* DeprecationTests.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 63B0AC521D595E1B00FA21D9 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 636A29251F1C3089001229C2 /* race.swift in Sources */, - 63B0AC9A1D595E6300FA21D9 /* when.swift in Sources */, - 636A29271F1C3927001229C2 /* Resolver.swift in Sources */, - 63B0AC991D595E6300FA21D9 /* when.m in Sources */, - 63D9B2EF203385FD0075C00B /* race.m in Sources */, - 63B0AC801D595E6300FA21D9 /* after.swift in Sources */, - 63B18AEC1F2D205C00B79E37 /* CustomStringConvertible.swift in Sources */, - 085B96BF21A9B37C00E5E22F /* LogEvent.swift in Sources */, - 6330B5E11F2E991200D60528 /* Configuration.swift in Sources */, - 63B912AA1F1D7B1300D49110 /* firstly.swift in Sources */, - 636A29211F1C1716001229C2 /* Thenable.swift in Sources */, - 632FBBE31F33B273008F8FBB /* Catchable.swift in Sources */, - 63B0AC851D595E6300FA21D9 /* dispatch_promise.m in Sources */, - 636A291F1F1C16FF001229C2 /* Box.swift in Sources */, - 63B0AC821D595E6300FA21D9 /* AnyPromise.m in Sources */, - 636A29231F1C17A6001229C2 /* Guarantee.swift in Sources */, - 636A291A1F1C156B001229C2 /* Promise.swift in Sources */, - 63B0AC8B1D595E6300FA21D9 /* join.m in Sources */, - 63B0AC891D595E6300FA21D9 /* hang.m in Sources */, - 63B0AC831D595E6300FA21D9 /* AnyPromise.swift in Sources */, - 63D9B2F120338D5D0075C00B /* Deprecations.swift in Sources */, - 63B0AC871D595E6300FA21D9 /* Error.swift in Sources */, - 0CC3AF2B1FCF84F7000E98C9 /* hang.swift in Sources */, - 63B0AC7F1D595E6300FA21D9 /* after.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - C0244E512047A6CB00ACB4AC /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - C013F73C20494291006B57B1 /* JSAdapter.swift in Sources */, - C0244E692047AC9F00ACB4AC /* AllTests.swift in Sources */, - C013F740204E5064006B57B1 /* JSUtils.swift in Sources */, - C013F73A2049076A006B57B1 /* JSPromise.swift in Sources */, - C013F7382048E3B6006B57B1 /* MockNodeEnvironment.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXTargetDependency section */ - 631411331D59795700E24B9E /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 63B0AC561D595E1B00FA21D9 /* PromiseKit */; - targetProxy = 631411341D59795700E24B9E /* PBXContainerItemProxy */; - }; - 6317518C1D59766500A9DDDC /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 63B0AC561D595E1B00FA21D9 /* PromiseKit */; - targetProxy = 6317518D1D59766500A9DDDC /* PBXContainerItemProxy */; - }; - 633027E1203CC0060037E136 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 63B0AC561D595E1B00FA21D9 /* PromiseKit */; - targetProxy = 633027E2203CC0060037E136 /* PBXContainerItemProxy */; - }; - 635D64051D5962F900BC0AF5 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 63B0AC561D595E1B00FA21D9 /* PromiseKit */; - targetProxy = 635D64041D5962F900BC0AF5 /* PBXContainerItemProxy */; - }; - C0244E4F2047A6CB00ACB4AC /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 63B0AC561D595E1B00FA21D9 /* PromiseKit */; - targetProxy = C0244E502047A6CB00ACB4AC /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - -/* Begin XCBuildConfiguration section */ - 630019201D596292003B4E30 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; - MACOSX_DEPLOYMENT_TARGET = 10.12; - SWIFT_INSTALL_OBJC_HEADER = NO; - TVOS_DEPLOYMENT_TARGET = 10.1; - }; - name = Debug; - }; - 630019211D596292003B4E30 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; - MACOSX_DEPLOYMENT_TARGET = 10.12; - SWIFT_INSTALL_OBJC_HEADER = NO; - TVOS_DEPLOYMENT_TARGET = 10.1; - }; - name = Release; - }; - 6314113A1D59795700E24B9E /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; - SWIFT_INSTALL_OBJC_HEADER = NO; - SWIFT_OBJC_BRIDGING_HEADER = Tests/Bridging/Infrastructure.h; - }; - name = Debug; - }; - 6314113B1D59795700E24B9E /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; - SWIFT_INSTALL_OBJC_HEADER = NO; - SWIFT_OBJC_BRIDGING_HEADER = Tests/Bridging/Infrastructure.h; - }; - name = Release; - }; - 631751A61D59766500A9DDDC /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; - SWIFT_INSTALL_OBJC_HEADER = NO; - }; - name = Debug; - }; - 631751A71D59766500A9DDDC /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; - LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks @loader_path/Frameworks"; - "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; - SWIFT_INSTALL_OBJC_HEADER = NO; - }; - name = Release; - }; - 633027E8203CC0060037E136 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_INSTALL_OBJC_HEADER = NO; - SWIFT_SUPPRESS_WARNINGS = YES; - }; - name = Debug; - }; - 633027E9203CC0060037E136 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_INSTALL_OBJC_HEADER = NO; - SWIFT_SUPPRESS_WARNINGS = YES; - }; - name = Release; - }; - 6399A3761D595D9100D65233 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 6.15.3; - DEBUG_INFORMATION_FORMAT = dwarf; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = "DEBUG=1"; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - INFOPLIST_FILE = "$(SRCROOT)/Sources/Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - LD_DYLIB_INSTALL_NAME = "@rpath"; - MACOSX_DEPLOYMENT_TARGET = 10.10; - ONLY_ACTIVE_ARCH = YES; - PRODUCT_BUNDLE_IDENTIFIER = org.promisekit; - PRODUCT_BUNDLE_PACKAGE_TYPE = BNDL; - PRODUCT_NAME = "$(TARGET_NAME)"; - SUPPORTED_PLATFORMS = "macosx appletvsimulator appletvos watchsimulator iphonesimulator watchos iphoneos"; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 4.0; - TVOS_DEPLOYMENT_TARGET = 9.0; - VERSIONING_SYSTEM = "apple-generic"; - WATCHOS_DEPLOYMENT_TARGET = 2.0; - }; - name = Debug; - }; - 6399A3771D595D9100D65233 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 6.15.3; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - INFOPLIST_FILE = "$(SRCROOT)/Sources/Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - LD_DYLIB_INSTALL_NAME = "@rpath"; - MACOSX_DEPLOYMENT_TARGET = 10.10; - PRODUCT_BUNDLE_IDENTIFIER = org.promisekit; - PRODUCT_BUNDLE_PACKAGE_TYPE = BNDL; - PRODUCT_NAME = "$(TARGET_NAME)"; - SUPPORTED_PLATFORMS = "macosx appletvsimulator appletvos watchsimulator iphonesimulator watchos iphoneos"; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_VERSION = 4.0; - TVOS_DEPLOYMENT_TARGET = 9.0; - VERSIONING_SYSTEM = "apple-generic"; - WATCHOS_DEPLOYMENT_TARGET = 2.0; - }; - name = Release; - }; - 63B0AC5D1D595E1B00FA21D9 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - APPLICATION_EXTENSION_API_ONLY = YES; - CLANG_WARN_ASSIGN_ENUM = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_CXX0X_EXTENSIONS = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_OBJC_EXPLICIT_OWNERSHIP_TYPE = YES; - CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_MISSING_PROPERTY_SYNTHESIS = YES; - CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES; - CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES; - CLANG_WARN_UNREACHABLE_CODE = YES_AGGRESSIVE; - CLANG_WARN__EXIT_TIME_DESTRUCTORS = YES; - DEFINES_MODULE = YES; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - ENABLE_TESTABILITY = YES; - GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES; - GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES; - GCC_TREAT_WARNINGS_AS_ERRORS = NO; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES; - GCC_WARN_ABOUT_MISSING_NEWLINE = YES; - GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES; - GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES; - GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES; - GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; - GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES; - GCC_WARN_SIGN_COMPARE = YES; - GCC_WARN_STRICT_SELECTOR_MATCH = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNKNOWN_PRAGMAS = YES; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_LABEL = YES; - GCC_WARN_UNUSED_PARAMETER = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - LD_DYLIB_INSTALL_NAME = "$(DYLIB_INSTALL_NAME_BASE:standardizepath)/$(EXECUTABLE_PATH)"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - PRODUCT_BUNDLE_PACKAGE_TYPE = FMWK; - SKIP_INSTALL = YES; - SWIFT_TREAT_WARNINGS_AS_ERRORS = NO; - TARGETED_DEVICE_FAMILY = "1,2,3,4"; - }; - name = Debug; - }; - 63B0AC5E1D595E1B00FA21D9 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - APPLICATION_EXTENSION_API_ONLY = YES; - BITCODE_GENERATION_MODE = bitcode; - CLANG_WARN_ASSIGN_ENUM = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_CXX0X_EXTENSIONS = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_OBJC_EXPLICIT_OWNERSHIP_TYPE = YES; - CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_MISSING_PROPERTY_SYNTHESIS = YES; - CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES; - CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES; - CLANG_WARN_UNREACHABLE_CODE = YES_AGGRESSIVE; - CLANG_WARN__EXIT_TIME_DESTRUCTORS = YES; - DEFINES_MODULE = YES; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES; - GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES; - GCC_TREAT_WARNINGS_AS_ERRORS = NO; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES; - GCC_WARN_ABOUT_MISSING_NEWLINE = YES; - GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES; - GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES; - GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES; - GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; - GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES; - GCC_WARN_SIGN_COMPARE = YES; - GCC_WARN_STRICT_SELECTOR_MATCH = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNKNOWN_PRAGMAS = YES; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_LABEL = YES; - GCC_WARN_UNUSED_PARAMETER = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - LD_DYLIB_INSTALL_NAME = "$(DYLIB_INSTALL_NAME_BASE:standardizepath)/$(EXECUTABLE_PATH)"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - PRODUCT_BUNDLE_PACKAGE_TYPE = FMWK; - SKIP_INSTALL = YES; - SWIFT_TREAT_WARNINGS_AS_ERRORS = NO; - TARGETED_DEVICE_FAMILY = "1,2,3,4"; - }; - name = Release; - }; - C0244E602047A6CB00ACB4AC /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; - CLANG_ENABLE_MODULES = YES; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_INSTALL_OBJC_HEADER = NO; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - }; - name = Debug; - }; - C0244E612047A6CB00ACB4AC /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; - CLANG_ENABLE_MODULES = YES; - LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks @loader_path/Frameworks"; - "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_INSTALL_OBJC_HEADER = NO; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 6300191F1D596292003B4E30 /* Build configuration list for PBXNativeTarget "PMKCoreTests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 630019201D596292003B4E30 /* Debug */, - 630019211D596292003B4E30 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 631411391D59795700E24B9E /* Build configuration list for PBXNativeTarget "PMKBridgeTests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 6314113A1D59795700E24B9E /* Debug */, - 6314113B1D59795700E24B9E /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 631751A51D59766500A9DDDC /* Build configuration list for PBXNativeTarget "PMKA+Tests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 631751A61D59766500A9DDDC /* Debug */, - 631751A71D59766500A9DDDC /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 633027E7203CC0060037E136 /* Build configuration list for PBXNativeTarget "PMKDeprecatedTests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 633027E8203CC0060037E136 /* Debug */, - 633027E9203CC0060037E136 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 6399A3751D595D9100D65233 /* Build configuration list for PBXProject "PromiseKit" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 6399A3761D595D9100D65233 /* Debug */, - 6399A3771D595D9100D65233 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 63B0AC5F1D595E1B00FA21D9 /* Build configuration list for PBXNativeTarget "PromiseKit" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 63B0AC5D1D595E1B00FA21D9 /* Debug */, - 63B0AC5E1D595E1B00FA21D9 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - C0244E5F2047A6CB00ACB4AC /* Build configuration list for PBXNativeTarget "PMKJSA+Tests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - C0244E602047A6CB00ACB4AC /* Debug */, - C0244E612047A6CB00ACB4AC /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 6399A3721D595D9100D65233 /* Project object */; -} diff --git a/PromiseKit.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/PromiseKit.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 919434a62..000000000 --- a/PromiseKit.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/PromiseKit.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/PromiseKit.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d981003..000000000 --- a/PromiseKit.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/PromiseKit.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/PromiseKit.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings deleted file mode 100644 index 08de0be8d..000000000 --- a/PromiseKit.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded - - - diff --git a/PromiseKit.xcodeproj/xcshareddata/xcschemes/PromiseKit.xcscheme b/PromiseKit.xcodeproj/xcshareddata/xcschemes/PromiseKit.xcscheme deleted file mode 100644 index 288d4a273..000000000 --- a/PromiseKit.xcodeproj/xcshareddata/xcschemes/PromiseKit.xcscheme +++ /dev/null @@ -1,147 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/README.md b/README.md index d4b675d84..ce07db9b4 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ ![PromiseKit](../gh-pages/public/img/logo-tight.png) -[![badge-pod][]][cocoapods] ![badge-languages][] ![badge-pms][] ![badge-platforms][] [![badge-travis][]][travis] +![badge-languages][] ![badge-platforms][] --- @@ -27,43 +27,30 @@ firstly { ``` PromiseKit is a thoughtful and complete implementation of promises for any -platform that has a `swiftc`. It has *excellent* Objective-C bridging and +platform that has a `swiftc`. It has *delightful* specializations for iOS, macOS, tvOS and watchOS. It is a top-100 pod used in many of the most popular apps in the world. [![codecov](https://codecov.io/gh/mxcl/PromiseKit/branch/master/graph/badge.svg)](https://codecov.io/gh/mxcl/PromiseKit) -# PromiseKit 7 Alpha +# Requirements -We are testing PromiseKit 7 alpha, it is Swift 5 only. It is tagged and thus -importable in all package managers. +Xcode >= 12.0 or Swift >= 5.3. -# PromiseKit 6 - -[Release notes and migration guide][PMK6]. +For earlier Swifts, Xcodes or for Objective-C support, use [PromiseKit 6](https://github.com/mxcl/PromiseKit/blob/v6/README.md). # Quick Start -In your [Podfile]: - -```ruby -use_frameworks! +In your `Package.swift`: -target "Change Me!" do - pod "PromiseKit", "~> 6.8" -end +```swift +package.dependencies.append( + .package(url: "https://github.com/mxcl/PromiseKit", from: "7.0.0-rc1") +) ``` -> The above gives an Xcode warning? See our [Installation Guide]. - -PromiseKit 6, 5 and 4 support Xcode 8.3, 9.x and 10.0; Swift 3.1, -3.2, 3.3, 3.4, 4.0, 4.1, 4.2, 4.3 and 5.0 (development snapshots); iOS, macOS, -tvOS, watchOS, Linux and Android; CocoaPods, Carthage and SwiftPM; -([CI Matrix](https://travis-ci.org/mxcl/PromiseKit)). - -For Carthage, SwiftPM, Accio, etc., or for instructions when using older Swifts or Xcodes, see our [Installation Guide]. We recommend -[Carthage](https://github.com/Carthage/Carthage) or -[Accio](https://github.com/JamitLabs/Accio). +For more detailed installation instructions or for other package managers see our +[Installation Guide]. # Professionally Supported PromiseKit is Now Available @@ -74,118 +61,38 @@ tools. [Get Professional Support for PromiseKit with TideLift](https://tidelift.com/subscription/pkg/cocoapods-promisekit?utm_source=cocoapods-promisekit&utm_medium=referral&utm_campaign=readme). -# PromiseKit is Thousands of Hours of Work +## Other Sponsorship -Hey there, I’m Max Howell. I’m a prolific producer of open source software and -probably you already use some of it (I created [`brew`]). I work full-time on -open source and it’s hard; currently *I earn less than minimum wage*. Please -help me continue my work, I appreciate it 🙏🏻 - - - - - -[Other ways to say thanks](http://mxcl.dev/#donate). - -[`brew`]: https://brew.sh +Maintaining this project is work, if your company uses this project please +sponsor it either via Tidelift or GitHub Sponsors. # Documentation * Handbook - * [Getting Started](Documentation/GettingStarted.md) - * [Promises: Common Patterns](Documentation/CommonPatterns.md) - * [Frequently Asked Questions](Documentation/FAQ.md) + * [Getting Started](Documents/GettingStarted.md) + * [Promises: Common Patterns](Documents/CommonPatterns.md) + * [Cancelling Promises](Documents/Cancel.md) + * [Frequently Asked Questions](Documents/FAQ.md) * Manual - * [Installation Guide](Documentation/Installation.md) - * [Objective-C Guide](Documentation/ObjectiveC.md) - * [Troubleshooting](Documentation/Troubleshooting.md) (e.g., solutions to common compile errors) - * [Appendix](Documentation/Appendix.md) -* [API Reference](https://mxcl.dev/PromiseKit/reference/v6/Classes/Promise.html) + * [Installation Guide](Documents/Installation.md) + * [Troubleshooting](Documents/Troubleshooting.md) (e.g., solutions to common compile errors) + * [Appendix](Documents/Appendix.md) +* [API Reference](https://mxcl.dev/PromiseKit/reference/v7/Classes/Promise.html) # Extensions Promises are only as useful as the asynchronous tasks they represent. Thus, we -have converted (almost) all of Apple’s APIs to promises. The default CocoaPod -provides Promises and the extensions for Foundation and UIKit. The other -extensions are available by specifying additional subspecs in your `Podfile`, -e.g.: - -```ruby -pod "PromiseKit/MapKit" # MKDirections().calculate().then { /*…*/ } -pod "PromiseKit/CoreLocation" # CLLocationManager.requestLocation().then { /*…*/ } -``` - -All our extensions are separate repositories at the [PromiseKit organization]. - -## I don't want the extensions! - -Then don’t have them: - -```ruby -pod "PromiseKit/CorePromise", "~> 6.8" -``` - -> *Note:* Carthage installations come with no extensions by default. - -## Choose Your Networking Library - -Promise chains commonly start with a network operation. Thus, we offer -extensions for `URLSession`: - -```swift -// pod 'PromiseKit/Foundation' # https://github.com/PromiseKit/Foundation - -firstly { - URLSession.shared.dataTask(.promise, with: try makeUrlRequest()).validate() - // ^^ we provide `.validate()` so that eg. 404s get converted to errors -}.map { - try JSONDecoder().decode(Foo.self, with: $0.data) -}.done { foo in - //… -}.catch { error in - //… -} - -func makeUrlRequest() throws -> URLRequest { - var rq = URLRequest(url: url) - rq.httpMethod = "POST" - rq.addValue("application/json", forHTTPHeaderField: "Content-Type") - rq.addValue("application/json", forHTTPHeaderField: "Accept") - rq.httpBody = try JSONEncoder().encode(obj) - return rq -} -``` - -And [Alamofire]: - -```swift -// pod 'PromiseKit/Alamofire' # https://github.com/PromiseKit/Alamofire- - -firstly { - Alamofire - .request("http://example.com", method: .post, parameters: params) - .responseDecodable(Foo.self) -}.done { foo in - //… -}.catch { error in - //… -} -``` - -Nowadays, considering that: +have converted (almost) all of Apple’s APIs to promises. You can use the +extensions by adding the appropriate library to your `Package.swift` and then +importing it (eg. `import PMKFoundation`). -* We almost always POST JSON -* We now have `JSONDecoder` -* PromiseKit now has `map` and other functional primitives -* PromiseKit (like Alamofire, but not raw-`URLSession`) also defaults to having - callbacks go to the main thread +See our [Installation Guide](Documents/Installation.md) for usage details. -We recommend vanilla `URLSession`. It uses fewer black boxes and sticks closer to the metal. Alamofire was essential until the three bullet points above -became true, but nowadays it isn’t really necessary. +Browse the `Sources` folder here for a list of available extensions. # Support -Please check our [Troubleshooting Guide](Documentation/Troubleshooting.md), and +Please check our [Troubleshooting Guide](Documents/Troubleshooting.md), and if after that you still have a question, ask at our [Gitter chat channel] or on [our bug tracker]. ## Security & Vulnerability Reporting or Disclosure @@ -195,7 +102,7 @@ https://tidelift.com/security [badge-pod]: https://img.shields.io/cocoapods/v/PromiseKit.svg?label=version [badge-pms]: https://img.shields.io/badge/supports-CocoaPods%20%7C%20Carthage%20%7C%20Accio%20%7C%20SwiftPM-green.svg -[badge-languages]: https://img.shields.io/badge/languages-Swift%20%7C%20ObjC-orange.svg +[badge-languages]: https://img.shields.io/badge/languages-Swift-orange.svg [badge-platforms]: https://img.shields.io/badge/platforms-macOS%20%7C%20iOS%20%7C%20watchOS%20%7C%20tvOS%20%7C%20Linux-lightgrey.svg [badge-mit]: https://img.shields.io/badge/license-MIT-blue.svg [OMGHTTPURLRQ]: https://github.com/PromiseKit/OMGHTTPURLRQ @@ -205,7 +112,7 @@ https://tidelift.com/security [our bug tracker]: https://github.com/mxcl/PromiseKit/issues/new [Podfile]: https://guides.cocoapods.org/syntax/podfile.html [PMK6]: http://mxcl.dev/PromiseKit/news/2018/02/PromiseKit-6.0-Released/ -[Installation Guide]: Documentation/Installation.md +[Installation Guide]: Documents/Installation.md [badge-travis]: https://travis-ci.org/mxcl/PromiseKit.svg?branch=master [travis]: https://travis-ci.org/mxcl/PromiseKit [cocoapods]: https://cocoapods.org/pods/PromiseKit diff --git a/Sources/AnyPromise+Private.h b/Sources/AnyPromise+Private.h deleted file mode 100644 index cd28c4183..000000000 --- a/Sources/AnyPromise+Private.h +++ /dev/null @@ -1,32 +0,0 @@ -@import Foundation.NSError; -@import Foundation.NSPointerArray; - -#if TARGET_OS_IPHONE - #define NSPointerArrayMake(N) ({ \ - NSPointerArray *aa = [NSPointerArray strongObjectsPointerArray]; \ - aa.count = N; \ - aa; \ - }) -#else - static inline NSPointerArray * __nonnull NSPointerArrayMake(NSUInteger count) { - #pragma clang diagnostic push - #pragma clang diagnostic ignored "-Wdeprecated-declarations" - NSPointerArray *aa = [[NSPointerArray class] respondsToSelector:@selector(strongObjectsPointerArray)] - ? [NSPointerArray strongObjectsPointerArray] - : [NSPointerArray pointerArrayWithStrongObjects]; - #pragma clang diagnostic pop - aa.count = count; - return aa; - } -#endif - -#define IsError(o) [o isKindOfClass:[NSError class]] -#define IsPromise(o) [o isKindOfClass:[AnyPromise class]] - -#import "AnyPromise.h" - -@class PMKArray; - -@interface AnyPromise () -- (void)__pipe:(void(^ __nonnull)(__nullable id))block NS_REFINED_FOR_SWIFT; -@end diff --git a/Sources/AnyPromise.h b/Sources/AnyPromise.h deleted file mode 100644 index 75352d55c..000000000 --- a/Sources/AnyPromise.h +++ /dev/null @@ -1,308 +0,0 @@ -#import -#import -#import - -/// INTERNAL DO NOT USE -@class __AnyPromise; - -/// Provided to simplify some usage sites -typedef void (^PMKResolver)(id __nullable) NS_REFINED_FOR_SWIFT; - - -/// An Objective-C implementation of the promise pattern. -@interface AnyPromise: NSObject - -/** - Create a new promise that resolves with the provided block. - - Use this method when wrapping asynchronous code that does *not* use promises so that this code can be used in promise chains. - - If `resolve` is called with an `NSError` object, the promise is rejected, otherwise the promise is fulfilled. - - Don’t use this method if you already have promises! Instead, just return your promise. - - Should you need to fulfill a promise but have no sensical value to use: your promise is a `void` promise: fulfill with `nil`. - - The block you pass is executed immediately on the calling thread. - - - Parameter block: The provided block is immediately executed, inside the block call `resolve` to resolve this promise and cause any attached handlers to execute. If you are wrapping a delegate-based system, we recommend instead to use: initWithResolver: - - Returns: A new promise. - - Warning: Resolving a promise with `nil` fulfills it. - - SeeAlso: https://github.com/mxcl/PromiseKit/blob/master/Documentation/GettingStarted.md#making-promises - - SeeAlso: https://github.com/mxcl/PromiseKit/blob/master/Documentation/CommonPatterns.md#wrapping-delegate-systems - */ -+ (instancetype __nonnull)promiseWithResolverBlock:(void (^ __nonnull)(__nonnull PMKResolver))resolveBlock NS_REFINED_FOR_SWIFT; - - -/// INTERNAL DO NOT USE -- (instancetype __nonnull)initWith__D:(__AnyPromise * __nonnull)d; - -/** - Creates a resolved promise. - - When developing your own promise systems, it is occasionally useful to be able to return an already resolved promise. - - - Parameter value: The value with which to resolve this promise. Passing an `NSError` will cause the promise to be rejected, passing an AnyPromise will return a new AnyPromise bound to that promise, otherwise the promise will be fulfilled with the value passed. - - Returns: A resolved promise. - */ -+ (instancetype __nonnull)promiseWithValue:(__nullable id)value NS_REFINED_FOR_SWIFT; - -/** - The value of the asynchronous task this promise represents. - - A promise has `nil` value if the asynchronous task it represents has not finished. If the value is `nil` the promise is still `pending`. - - - Warning: *Note* Our Swift variant’s value property returns nil if the promise is rejected where AnyPromise will return the error object. This fits with the pattern where AnyPromise is not strictly typed and is more dynamic, but you should be aware of the distinction. - - - Note: If the AnyPromise was fulfilled with a `PMKManifold`, returns only the first fulfillment object. - - - Returns: The value with which this promise was resolved or `nil` if this promise is pending. - */ -@property (nonatomic, readonly) __nullable id value NS_REFINED_FOR_SWIFT; - -/// - Returns: if the promise is pending resolution. -@property (nonatomic, readonly) BOOL pending NS_REFINED_FOR_SWIFT; - -/// - Returns: if the promise is resolved and fulfilled. -@property (nonatomic, readonly) BOOL fulfilled NS_REFINED_FOR_SWIFT; - -/// - Returns: if the promise is resolved and rejected. -@property (nonatomic, readonly) BOOL rejected NS_REFINED_FOR_SWIFT; - - -/** - The provided block is executed when its receiver is fulfilled. - - If you provide a block that takes a parameter, the value of the receiver will be passed as that parameter. - - [NSURLSession GET:url].then(^(NSData *data){ - // do something with data - }); - - @return A new promise that is resolved with the value returned from the provided block. For example: - - [NSURLSession GET:url].then(^(NSData *data){ - return data.length; - }).then(^(NSNumber *number){ - //… - }); - - @warning *Important* The block passed to `then` may take zero, one, two or three arguments, and return an object or return nothing. This flexibility is why the method signature for then is `id`, which means you will not get completion for the block parameter, and must type it yourself. It is safe to type any block syntax here, so to start with try just: `^{}`. - - @warning *Important* If an `NSError` or `NSString` is thrown inside your block, or you return an `NSError` object the next `Promise` will be rejected. See `catch` for documentation on error handling. - - @warning *Important* `then` is always executed on the main queue. - - @see thenOn - @see thenInBackground -*/ -- (AnyPromise * __nonnull (^ __nonnull)(id __nonnull))then NS_REFINED_FOR_SWIFT; - - -/** - The provided block is executed on the default queue when the receiver is fulfilled. - - This method is provided as a convenience for `thenOn`. - - @see then - @see thenOn -*/ -- (AnyPromise * __nonnull(^ __nonnull)(id __nonnull))thenInBackground NS_REFINED_FOR_SWIFT; - -/** - The provided block is executed on the dispatch queue of your choice when the receiver is fulfilled. - - @see then - @see thenInBackground -*/ -- (AnyPromise * __nonnull(^ __nonnull)(dispatch_queue_t __nonnull, id __nonnull))thenOn NS_REFINED_FOR_SWIFT; - -#ifndef __cplusplus -/** - The provided block is executed when the receiver is rejected. - - Provide a block of form `^(NSError *){}` or simply `^{}`. The parameter has type `id` to give you the freedom to choose either. - - The provided block always runs on the main queue. - - @warning *Note* Cancellation errors are not caught. - - @warning *Note* Since catch is a c++ keyword, this method is not available in Objective-C++ files. Instead use catchOn. - - @see catchOn - @see catchInBackground -*/ -- (AnyPromise * __nonnull(^ __nonnull)(id __nonnull))catch NS_REFINED_FOR_SWIFT; -#endif - -/** - The provided block is executed when the receiver is rejected. - - Provide a block of form `^(NSError *){}` or simply `^{}`. The parameter has type `id` to give you the freedom to choose either. - - The provided block always runs on the global background queue. - - @warning *Note* Cancellation errors are not caught. - - @warning *Note* Since catch is a c++ keyword, this method is not available in Objective-C++ files. Instead use catchWithPolicy. - - @see catch - @see catchOn - */ -- (AnyPromise * __nonnull(^ __nonnull)(id __nonnull))catchInBackground NS_REFINED_FOR_SWIFT; - - -/** - The provided block is executed when the receiver is rejected. - - Provide a block of form `^(NSError *){}` or simply `^{}`. The parameter has type `id` to give you the freedom to choose either. - - The provided block always runs on queue provided. - - @warning *Note* Cancellation errors are not caught. - - @see catch - @see catchInBackground - */ -- (AnyPromise * __nonnull(^ __nonnull)(dispatch_queue_t __nonnull, id __nonnull))catchOn NS_REFINED_FOR_SWIFT; - -/** - The provided block is executed when the receiver is resolved. - - The provided block always runs on the main queue. - - @see ensureOn -*/ -- (AnyPromise * __nonnull(^ __nonnull)(dispatch_block_t __nonnull))ensure NS_REFINED_FOR_SWIFT; - -/** - The provided block is executed on the dispatch queue of your choice when the receiver is resolved. - - @see ensure - */ -- (AnyPromise * __nonnull(^ __nonnull)(dispatch_queue_t __nonnull, dispatch_block_t __nonnull))ensureOn NS_REFINED_FOR_SWIFT; - -/** - Wait until the promise is resolved. - - @return Value if fulfilled or error if rejected. - */ -- (id __nullable)wait NS_REFINED_FOR_SWIFT; - -/** - Create a new promise with an associated resolver. - - Use this method when wrapping asynchronous code that does *not* use - promises so that this code can be used in promise chains. Generally, - prefer `promiseWithResolverBlock:` as the resulting code is more elegant. - - PMKResolver resolve; - AnyPromise *promise = [[AnyPromise alloc] initWithResolver:&resolve]; - - // later - resolve(@"foo"); - - @param resolver A reference to a block pointer of PMKResolver type. - You can then call your resolver to resolve this promise. - - @return A new promise. - - @warning *Important* The resolver strongly retains the promise. - - @see promiseWithResolverBlock: -*/ -- (instancetype __nonnull)initWithResolver:(PMKResolver __strong __nonnull * __nonnull)resolver NS_REFINED_FOR_SWIFT; - -/** - Unavailable methods - */ - -- (instancetype __nonnull)init __attribute__((unavailable("It is illegal to create an unresolvable promise."))); -+ (instancetype __nonnull)new __attribute__((unavailable("It is illegal to create an unresolvable promise."))); -- (AnyPromise * __nonnull(^ __nonnull)(dispatch_block_t __nonnull))always __attribute__((unavailable("See -ensure"))); -- (AnyPromise * __nonnull(^ __nonnull)(dispatch_block_t __nonnull))alwaysOn __attribute__((unavailable("See -ensureOn"))); -- (AnyPromise * __nonnull(^ __nonnull)(dispatch_block_t __nonnull))finally __attribute__((unavailable("See -ensure"))); -- (AnyPromise * __nonnull(^ __nonnull)(dispatch_block_t __nonnull, dispatch_block_t __nonnull))finallyOn __attribute__((unavailable("See -ensureOn"))); - -@end - - -typedef void (^PMKAdapter)(id __nullable, NSError * __nullable) NS_REFINED_FOR_SWIFT; -typedef void (^PMKIntegerAdapter)(NSInteger, NSError * __nullable) NS_REFINED_FOR_SWIFT; -typedef void (^PMKBooleanAdapter)(BOOL, NSError * __nullable) NS_REFINED_FOR_SWIFT; - - -@interface AnyPromise (Adapters) - -/** - Create a new promise by adapting an existing asynchronous system. - - The pattern of a completion block that passes two parameters, the first - the result and the second an `NSError` object is so common that we - provide this convenience adapter to make wrapping such systems more - elegant. - - return [PMKPromise promiseWithAdapterBlock:^(PMKAdapter adapter){ - PFQuery *query = [PFQuery …]; - [query findObjectsInBackgroundWithBlock:adapter]; - }]; - - @warning *Important* If both parameters are nil, the promise fulfills, - if both are non-nil the promise rejects. This is per the convention. - - @see https://github.com/mxcl/PromiseKit/blob/master/Documentation/GettingStarted.md#making-promises - */ -+ (instancetype __nonnull)promiseWithAdapterBlock:(void (^ __nonnull)(PMKAdapter __nonnull adapter))block NS_REFINED_FOR_SWIFT; - -/** - Create a new promise by adapting an existing asynchronous system. - - Adapts asynchronous systems that complete with `^(NSInteger, NSError *)`. - NSInteger will cast to enums provided the enum has been wrapped with - `NS_ENUM`. All of Apple’s enums are, so if you find one that hasn’t you - may need to make a pull-request. - - @see promiseWithAdapter - */ -+ (instancetype __nonnull)promiseWithIntegerAdapterBlock:(void (^ __nonnull)(PMKIntegerAdapter __nonnull adapter))block NS_REFINED_FOR_SWIFT; - -/** - Create a new promise by adapting an existing asynchronous system. - - Adapts asynchronous systems that complete with `^(BOOL, NSError *)`. - - @see promiseWithAdapter - */ -+ (instancetype __nonnull)promiseWithBooleanAdapterBlock:(void (^ __nonnull)(PMKBooleanAdapter __nonnull adapter))block NS_REFINED_FOR_SWIFT; - -@end - - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Whenever resolving a promise you may resolve with a tuple, eg. - returning from a `then` or `catch` handler or resolving a new promise. - - Consumers of your Promise are not compelled to consume any arguments and - in fact will often only consume the first parameter. Thus ensure the - order of parameters is: from most-important to least-important. - - Currently PromiseKit limits you to THREE parameters to the manifold. -*/ -#define PMKManifold(...) __PMKManifold(__VA_ARGS__, 3, 2, 1) -#define __PMKManifold(_1, _2, _3, N, ...) __PMKArrayWithCount(N, _1, _2, _3) -extern id __nonnull __PMKArrayWithCount(NSUInteger, ...); - -#ifdef __cplusplus -} // Extern C -#endif - - - - -__attribute__((unavailable("See AnyPromise"))) -@interface PMKPromise -@end diff --git a/Sources/AnyPromise.m b/Sources/AnyPromise.m deleted file mode 100644 index 3725beacd..000000000 --- a/Sources/AnyPromise.m +++ /dev/null @@ -1,179 +0,0 @@ -#if __has_include("PromiseKit-Swift.h") - #import "PromiseKit-Swift.h" -#else - #import -#endif -#import "PMKCallVariadicBlock.m" -#import "AnyPromise+Private.h" -#import "AnyPromise.h" - -NSString *const PMKErrorDomain = @"PMKErrorDomain"; - - -@implementation AnyPromise { - __AnyPromise *d; -} - -- (instancetype)initWith__D:(__AnyPromise *)dd { - self = [super init]; - if (self) self->d = dd; - return self; -} - -- (instancetype)initWithResolver:(PMKResolver __strong *)resolver { - self = [super init]; - if (self) - d = [[__AnyPromise alloc] initWithResolver:^(void (^resolve)(id)) { - *resolver = resolve; - }]; - return self; -} - -+ (instancetype)promiseWithResolverBlock:(void (^)(PMKResolver _Nonnull))resolveBlock { - id d = [[__AnyPromise alloc] initWithResolver:resolveBlock]; - return [[self alloc] initWith__D:d]; -} - -+ (instancetype)promiseWithValue:(id)value { - //TODO provide a more efficient route for sealed promises - id d = [[__AnyPromise alloc] initWithResolver:^(void (^resolve)(id)) { - resolve(value); - }]; - return [[self alloc] initWith__D:d]; -} - -//TODO remove if possible, but used by when.m -- (void)__pipe:(void (^)(id _Nullable))block { - [d __pipe:block]; -} - -//NOTE used by AnyPromise.swift -- (id)__d { - return d; -} - -- (AnyPromise *(^)(id))then { - return ^(id block) { - return [self->d __thenOn:dispatch_get_main_queue() execute:^(id obj) { - return PMKCallVariadicBlock(block, obj); - }]; - }; -} - -- (AnyPromise *(^)(dispatch_queue_t, id))thenOn { - return ^(dispatch_queue_t queue, id block) { - return [self->d __thenOn:queue execute:^(id obj) { - return PMKCallVariadicBlock(block, obj); - }]; - }; -} - -- (AnyPromise *(^)(id))thenInBackground { - return ^(id block) { - return [self->d __thenOn:dispatch_get_global_queue(0, 0) execute:^(id obj) { - return PMKCallVariadicBlock(block, obj); - }]; - }; -} - -- (AnyPromise *(^)(dispatch_queue_t, id))catchOn { - return ^(dispatch_queue_t q, id block) { - return [self->d __catchOn:q execute:^(id obj) { - return PMKCallVariadicBlock(block, obj); - }]; - }; -} - -- (AnyPromise *(^)(id))catch { - return ^(id block) { - return [self->d __catchOn:dispatch_get_main_queue() execute:^(id obj) { - return PMKCallVariadicBlock(block, obj); - }]; - }; -} - -- (AnyPromise *(^)(id))catchInBackground { - return ^(id block) { - return [self->d __catchOn:dispatch_get_global_queue(0, 0) execute:^(id obj) { - return PMKCallVariadicBlock(block, obj); - }]; - }; -} - -- (AnyPromise *(^)(dispatch_block_t))ensure { - return ^(dispatch_block_t block) { - return [self->d __ensureOn:dispatch_get_main_queue() execute:block]; - }; -} - -- (AnyPromise *(^)(dispatch_queue_t, dispatch_block_t))ensureOn { - return ^(dispatch_queue_t queue, dispatch_block_t block) { - return [self->d __ensureOn:queue execute:block]; - }; -} - -- (id)wait { - return [d __wait]; -} - -- (BOOL)pending { - return [[d valueForKey:@"__pending"] boolValue]; -} - -- (BOOL)rejected { - return IsError([d __value]); -} - -- (BOOL)fulfilled { - return !self.rejected; -} - -- (id)value { - id obj = [d __value]; - - if ([obj isKindOfClass:[PMKArray class]]) { - return obj[0]; - } else { - return obj; - } -} - -@end - - - -@implementation AnyPromise (Adapters) - -+ (instancetype)promiseWithAdapterBlock:(void (^)(PMKAdapter))block { - return [self promiseWithResolverBlock:^(PMKResolver resolve) { - block(^(id value, id error){ - resolve(error ?: value); - }); - }]; -} - -+ (instancetype)promiseWithIntegerAdapterBlock:(void (^)(PMKIntegerAdapter))block { - return [self promiseWithResolverBlock:^(PMKResolver resolve) { - block(^(NSInteger value, id error){ - if (error) { - resolve(error); - } else { - resolve(@(value)); - } - }); - }]; -} - -+ (instancetype)promiseWithBooleanAdapterBlock:(void (^)(PMKBooleanAdapter adapter))block { - return [self promiseWithResolverBlock:^(PMKResolver resolve) { - block(^(BOOL value, id error){ - if (error) { - resolve(error); - } else { - resolve(@(value)); - } - }); - }]; -} - -@end diff --git a/Sources/AnyPromise.swift b/Sources/AnyPromise.swift deleted file mode 100644 index d7e575d2d..000000000 --- a/Sources/AnyPromise.swift +++ /dev/null @@ -1,224 +0,0 @@ -import Foundation - -/** - __AnyPromise is an implementation detail. - - Because of how ObjC/Swift compatibility work we have to compose our AnyPromise - with this internal object, however this is still part of the public interface. - Sadly. Please don’t use it. -*/ -@objc(__AnyPromise) public class __AnyPromise: NSObject { - fileprivate let box: Box - - @objc public init(resolver body: (@escaping (Any?) -> Void) -> Void) { - box = EmptyBox() - super.init() - body { - if let p = $0 as? AnyPromise { - p.d.__pipe(self.box.seal) - } else { - self.box.seal($0) - } - } - } - - @objc public func __thenOn(_ q: DispatchQueue, execute: @escaping (Any?) -> Any?) -> AnyPromise { - return AnyPromise(__D: __AnyPromise(resolver: { resolve in - self.__pipe { obj in - if !(obj is NSError) { - q.async { - resolve(execute(obj)) - } - } else { - resolve(obj) - } - } - })) - } - - @objc public func __catchOn(_ q: DispatchQueue, execute: @escaping (Any?) -> Any?) -> AnyPromise { - return AnyPromise(__D: __AnyPromise(resolver: { resolve in - self.__pipe { obj in - if obj is NSError { - q.async { - resolve(execute(obj)) - } - } else { - resolve(obj) - } - } - })) - } - - @objc public func __ensureOn(_ q: DispatchQueue, execute: @escaping () -> Void) -> AnyPromise { - return AnyPromise(__D: __AnyPromise(resolver: { resolve in - self.__pipe { obj in - q.async { - execute() - resolve(obj) - } - } - })) - } - - @objc public func __wait() -> Any? { - if Thread.isMainThread { - conf.logHandler(.waitOnMainThread) - } - - var result = __value - - if result == nil { - let group = DispatchGroup() - group.enter() - self.__pipe { obj in - result = obj - group.leave() - } - group.wait() - } - - return result - } - - /// Internal, do not use! Some behaviors undefined. - @objc public func __pipe(_ to: @escaping (Any?) -> Void) { - let to = { (obj: Any?) -> Void in - if obj is NSError { - to(obj) // or we cannot determine if objects are errors in objc land - } else { - to(obj) - } - } - switch box.inspect() { - case .pending: - box.inspect { - switch $0 { - case .pending(let handlers): - handlers.append { obj in - to(obj) - } - case .resolved(let obj): - to(obj) - } - } - case .resolved(let obj): - to(obj) - } - } - - @objc public var __value: Any? { - switch box.inspect() { - case .resolved(let obj): - return obj - default: - return nil - } - } - - @objc public var __pending: Bool { - switch box.inspect() { - case .pending: - return true - case .resolved: - return false - } - } -} - -extension AnyPromise: Thenable, CatchMixin { - - /// - Returns: A new `AnyPromise` bound to a `Promise`. - public convenience init(_ bridge: U) { - self.init(__D: __AnyPromise(resolver: { resolve in - bridge.pipe { - switch $0 { - case .rejected(let error): - resolve(error as NSError) - case .fulfilled(let value): - resolve(value) - } - } - })) - } - - public func pipe(to body: @escaping (Result) -> Void) { - - func fulfill() { - // calling through to the ObjC `value` property unwraps (any) PMKManifold - // and considering this is the Swift pipe; we want that. - body(.fulfilled(self.value(forKey: "value"))) - } - - switch box.inspect() { - case .pending: - box.inspect { - switch $0 { - case .pending(let handlers): - handlers.append { - if let error = $0 as? Error { - body(.rejected(error)) - } else { - fulfill() - } - } - case .resolved(let error as Error): - body(.rejected(error)) - case .resolved: - fulfill() - } - } - case .resolved(let error as Error): - body(.rejected(error)) - case .resolved: - fulfill() - } - } - - fileprivate var d: __AnyPromise { - return value(forKey: "__d") as! __AnyPromise - } - - var box: Box { - return d.box - } - - public var result: Result? { - guard let value = __value else { - return nil - } - if let error = value as? Error { - return .rejected(error) - } else { - return .fulfilled(value) - } - } - - public typealias T = Any? -} - - -#if swift(>=3.1) -public extension Promise where T == Any? { - convenience init(_ anyPromise: AnyPromise) { - self.init { - anyPromise.pipe(to: $0.resolve) - } - } -} -#else -extension AnyPromise { - public func asPromise() -> Promise { - return Promise(.pending, resolver: { resolve in - pipe { result in - switch result { - case .rejected(let error): - resolve.reject(error) - case .fulfilled(let obj): - resolve.fulfill(obj) - } - } - }) - } -} -#endif diff --git a/Sources/Catchable.swift b/Sources/Catchable.swift deleted file mode 100644 index 596abdcba..000000000 --- a/Sources/Catchable.swift +++ /dev/null @@ -1,256 +0,0 @@ -import Dispatch - -/// Provides `catch` and `recover` to your object that conforms to `Thenable` -public protocol CatchMixin: Thenable -{} - -public extension CatchMixin { - - /** - The provided closure executes when this promise rejects. - - Rejecting a promise cascades: rejecting all subsequent promises (unless - recover is invoked) thus you will typically place your catch at the end - of a chain. Often utility promises will not have a catch, instead - delegating the error handling to the caller. - - - Parameter on: The queue to which the provided closure dispatches. - - Parameter policy: The default policy does not execute your handler for cancellation errors. - - Parameter execute: The handler to execute if this promise is rejected. - - Returns: A promise finalizer. - - SeeAlso: [Cancellation](https://github.com/mxcl/PromiseKit/blob/master/Documentation/CommonPatterns.md#cancellation) - */ - @discardableResult - func `catch`(on: DispatchQueue? = conf.Q.return, flags: DispatchWorkItemFlags? = nil, policy: CatchPolicy = conf.catchPolicy, _ body: @escaping(Error) -> Void) -> PMKFinalizer { - let finalizer = PMKFinalizer() - pipe { - switch $0 { - case .rejected(let error): - guard policy == .allErrors || !error.isCancelled else { - fallthrough - } - on.async(flags: flags) { - body(error) - finalizer.pending.resolve(()) - } - case .fulfilled: - finalizer.pending.resolve(()) - } - } - return finalizer - } -} - -public class PMKFinalizer { - let pending = Guarantee.pending() - - /// `finally` is the same as `ensure`, but it is not chainable - public func finally(on: DispatchQueue? = conf.Q.return, flags: DispatchWorkItemFlags? = nil, _ body: @escaping () -> Void) { - pending.guarantee.done(on: on, flags: flags) { - body() - } - } -} - - -public extension CatchMixin { - - /** - The provided closure executes when this promise rejects. - - Unlike `catch`, `recover` continues the chain. - Use `recover` in circumstances where recovering the chain from certain errors is a possibility. For example: - - firstly { - CLLocationManager.requestLocation() - }.recover { error in - guard error == CLError.unknownLocation else { throw error } - return .value(CLLocation.chicago) - } - - - Parameter on: The queue to which the provided closure dispatches. - - Parameter body: The handler to execute if this promise is rejected. - - SeeAlso: [Cancellation](https://github.com/mxcl/PromiseKit/blob/master/Documentation/CommonPatterns.md#cancellation) - */ - func recover(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, policy: CatchPolicy = conf.catchPolicy, _ body: @escaping(Error) throws -> U) -> Promise where U.T == T { - let rp = Promise(.pending) - pipe { - switch $0 { - case .fulfilled(let value): - rp.box.seal(.fulfilled(value)) - case .rejected(let error): - if policy == .allErrors || !error.isCancelled { - on.async(flags: flags) { - do { - let rv = try body(error) - guard rv !== rp else { throw PMKError.returnedSelf } - rv.pipe(to: rp.box.seal) - } catch { - rp.box.seal(.rejected(error)) - } - } - } else { - rp.box.seal(.rejected(error)) - } - } - } - return rp - } - - /** - The provided closure executes when this promise rejects. - This variant of `recover` requires the handler to return a Guarantee, thus it returns a Guarantee itself and your closure cannot `throw`. - - Note it is logically impossible for this to take a `catchPolicy`, thus `allErrors` are handled. - - Parameter on: The queue to which the provided closure dispatches. - - Parameter body: The handler to execute if this promise is rejected. - - SeeAlso: [Cancellation](https://github.com/mxcl/PromiseKit/blob/master/Documentation/CommonPatterns.md#cancellation) - */ - @discardableResult - func recover(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ body: @escaping(Error) -> Guarantee) -> Guarantee { - let rg = Guarantee(.pending) - pipe { - switch $0 { - case .fulfilled(let value): - rg.box.seal(value) - case .rejected(let error): - on.async(flags: flags) { - body(error).pipe(to: rg.box.seal) - } - } - } - return rg - } - - /** - The provided closure executes when this promise resolves, whether it rejects or not. - - firstly { - UIApplication.shared.networkActivityIndicatorVisible = true - }.done { - //… - }.ensure { - UIApplication.shared.networkActivityIndicatorVisible = false - }.catch { - //… - } - - - Parameter on: The queue to which the provided closure dispatches. - - Parameter body: The closure that executes when this promise resolves. - - Returns: A new promise, resolved with this promise’s resolution. - */ - func ensure(on: DispatchQueue? = conf.Q.return, flags: DispatchWorkItemFlags? = nil, _ body: @escaping () -> Void) -> Promise { - let rp = Promise(.pending) - pipe { result in - on.async(flags: flags) { - body() - rp.box.seal(result) - } - } - return rp - } - - /** - The provided closure executes when this promise resolves, whether it rejects or not. - The chain waits on the returned `Guarantee`. - - firstly { - setup() - }.done { - //… - }.ensureThen { - teardown() // -> Guarante - }.catch { - //… - } - - - Parameter on: The queue to which the provided closure dispatches. - - Parameter body: The closure that executes when this promise resolves. - - Returns: A new promise, resolved with this promise’s resolution. - */ - func ensureThen(on: DispatchQueue? = conf.Q.return, flags: DispatchWorkItemFlags? = nil, _ body: @escaping () -> Guarantee) -> Promise { - let rp = Promise(.pending) - pipe { result in - on.async(flags: flags) { - body().done { - rp.box.seal(result) - } - } - } - return rp - } - - - - /** - Consumes the Swift unused-result warning. - - Note: You should `catch`, but in situations where you know you don’t need a `catch`, `cauterize` makes your intentions clear. - */ - @discardableResult - func cauterize() -> PMKFinalizer { - return self.catch { - conf.logHandler(.cauterized($0)) - } - } -} - - -public extension CatchMixin where T == Void { - - /** - The provided closure executes when this promise rejects. - - This variant of `recover` is specialized for `Void` promises and de-errors your chain returning a `Guarantee`, thus you cannot `throw` and you must handle all errors including cancellation. - - - Parameter on: The queue to which the provided closure dispatches. - - Parameter body: The handler to execute if this promise is rejected. - - SeeAlso: [Cancellation](https://github.com/mxcl/PromiseKit/blob/master/Documentation/CommonPatterns.md#cancellation) - */ - @discardableResult - func recover(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ body: @escaping(Error) -> Void) -> Guarantee { - let rg = Guarantee(.pending) - pipe { - switch $0 { - case .fulfilled: - rg.box.seal(()) - case .rejected(let error): - on.async(flags: flags) { - body(error) - rg.box.seal(()) - } - } - } - return rg - } - - /** - The provided closure executes when this promise rejects. - - This variant of `recover` ensures that no error is thrown from the handler and allows specifying a catch policy. - - - Parameter on: The queue to which the provided closure dispatches. - - Parameter body: The handler to execute if this promise is rejected. - - SeeAlso: [Cancellation](https://github.com/mxcl/PromiseKit/blob/master/Documentation/CommonPatterns.md#cancellation) - */ - func recover(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, policy: CatchPolicy = conf.catchPolicy, _ body: @escaping(Error) throws -> Void) -> Promise { - let rg = Promise(.pending) - pipe { - switch $0 { - case .fulfilled: - rg.box.seal(.fulfilled(())) - case .rejected(let error): - if policy == .allErrors || !error.isCancelled { - on.async(flags: flags) { - do { - rg.box.seal(.fulfilled(try body(error))) - } catch { - rg.box.seal(.rejected(error)) - } - } - } else { - rg.box.seal(.rejected(error)) - } - } - } - return rg - } -} diff --git a/Sources/CustomStringConvertible.swift b/Sources/CustomStringConvertible.swift deleted file mode 100644 index eee0b020a..000000000 --- a/Sources/CustomStringConvertible.swift +++ /dev/null @@ -1,44 +0,0 @@ - -extension Promise: CustomStringConvertible { - /// - Returns: A description of the state of this promise. - public var description: String { - switch result { - case nil: - return "Promise(…\(T.self))" - case .rejected(let error)?: - return "Promise(\(error))" - case .fulfilled(let value)?: - return "Promise(\(value))" - } - } -} - -extension Promise: CustomDebugStringConvertible { - /// - Returns: A debug-friendly description of the state of this promise. - public var debugDescription: String { - switch box.inspect() { - case .pending(let handlers): - return "Promise<\(T.self)>.pending(handlers: \(handlers.bodies.count))" - case .resolved(.rejected(let error)): - return "Promise<\(T.self)>.rejected(\(type(of: error)).\(error))" - case .resolved(.fulfilled(let value)): - return "Promise<\(T.self)>.fulfilled(\(value))" - } - } -} - -#if !SWIFT_PACKAGE -extension AnyPromise { - /// - Returns: A description of the state of this promise. - override open var description: String { - switch box.inspect() { - case .pending: - return "AnyPromise(…)" - case .resolved(let obj?): - return "AnyPromise(\(obj))" - case .resolved(nil): - return "AnyPromise(nil)" - } - } -} -#endif diff --git a/Sources/Deprecations.swift b/Sources/Deprecations.swift deleted file mode 100644 index a837dcb8d..000000000 --- a/Sources/Deprecations.swift +++ /dev/null @@ -1,93 +0,0 @@ -import Dispatch - -@available(*, deprecated, message: "See `init(resolver:)`") -public func wrap(_ body: (@escaping (T?, Error?) -> Void) throws -> Void) -> Promise { - return Promise { seal in - try body(seal.resolve) - } -} - -@available(*, deprecated, message: "See `init(resolver:)`") -public func wrap(_ body: (@escaping (T, Error?) -> Void) throws -> Void) -> Promise { - return Promise { seal in - try body(seal.resolve) - } -} - -@available(*, deprecated, message: "See `init(resolver:)`") -public func wrap(_ body: (@escaping (Error?, T?) -> Void) throws -> Void) -> Promise { - return Promise { seal in - try body(seal.resolve) - } -} - -@available(*, deprecated, message: "See `init(resolver:)`") -public func wrap(_ body: (@escaping (Error?) -> Void) throws -> Void) -> Promise { - return Promise { seal in - try body(seal.resolve) - } -} - -@available(*, deprecated, message: "See `init(resolver:)`") -public func wrap(_ body: (@escaping (T) -> Void) throws -> Void) -> Promise { - return Promise { seal in - try body(seal.fulfill) - } -} - -public extension Promise { - @available(*, deprecated, message: "See `ensure`") - func always(on q: DispatchQueue = .main, execute body: @escaping () -> Void) -> Promise { - return ensure(on: q, body) - } -} - -public extension Thenable { -#if PMKFullDeprecations - /// disabled due to ambiguity with the other `.flatMap` - @available(*, deprecated, message: "See: `compactMap`") - func flatMap(on: DispatchQueue? = conf.Q.map, _ transform: @escaping(T) throws -> U?) -> Promise { - return compactMap(on: on, transform) - } -#endif -} - -public extension Thenable where T: Sequence { -#if PMKFullDeprecations - /// disabled due to ambiguity with the other `.map` - @available(*, deprecated, message: "See: `mapValues`") - func map(on: DispatchQueue? = conf.Q.map, _ transform: @escaping(T.Iterator.Element) throws -> U) -> Promise<[U]> { - return mapValues(on: on, transform) - } - - /// disabled due to ambiguity with the other `.flatMap` - @available(*, deprecated, message: "See: `flatMapValues`") - func flatMap(on: DispatchQueue? = conf.Q.map, _ transform: @escaping(T.Iterator.Element) throws -> U) -> Promise<[U.Iterator.Element]> { - return flatMapValues(on: on, transform) - } -#endif - - @available(*, deprecated, message: "See: `filterValues`") - func filter(on: DispatchQueue? = conf.Q.map, test: @escaping (T.Iterator.Element) -> Bool) -> Promise<[T.Iterator.Element]> { - return filterValues(on: on, test) - } -} - -public extension Thenable where T: Collection { - @available(*, deprecated, message: "See: `firstValue`") - var first: Promise { - return firstValue - } - - @available(*, deprecated, message: "See: `lastValue`") - var last: Promise { - return lastValue - } -} - -public extension Thenable where T: Sequence, T.Iterator.Element: Comparable { - @available(*, deprecated, message: "See: `sortedValues`") - func sorted(on: DispatchQueue? = conf.Q.map) -> Promise<[T.Iterator.Element]> { - return sortedValues(on: on) - } -} diff --git a/Sources/Info.plist b/Sources/Info.plist deleted file mode 100644 index 3a619de4d..000000000 --- a/Sources/Info.plist +++ /dev/null @@ -1,28 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - $(PRODUCT_BUNDLE_PACKAGE_TYPE) - CFBundleShortVersionString - $(CURRENT_PROJECT_VERSION) - CFBundleSignature - ???? - CFBundleVersion - 1 - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - - - diff --git a/Sources/LogEvent.swift b/Sources/LogEvent.swift deleted file mode 100644 index 99683bdb6..000000000 --- a/Sources/LogEvent.swift +++ /dev/null @@ -1,30 +0,0 @@ -/** - The PromiseKit events which may be logged. - - ```` - /// A promise or guarantee has blocked the main thread - case waitOnMainThread - - /// A promise has been deallocated without being resolved - case pendingPromiseDeallocated - - /// An error which occurred while fulfilling a promise was swallowed - case cauterized(Error) - - /// Errors which give a string error message - case misc (String) - ```` -*/ -public enum LogEvent { - /// A promise or guarantee has blocked the main thread - case waitOnMainThread - - /// A promise has been deallocated without being resolved - case pendingPromiseDeallocated - - /// A guarantee has been deallocated without being resolved - case pendingGuaranteeDeallocated - - /// An error which occurred while resolving a promise was swallowed - case cauterized(Error) -} diff --git a/Sources/NSMethodSignatureForBlock.m b/Sources/NSMethodSignatureForBlock.m deleted file mode 100644 index 700c1b37e..000000000 --- a/Sources/NSMethodSignatureForBlock.m +++ /dev/null @@ -1,77 +0,0 @@ -#import - -struct PMKBlockLiteral { - void *isa; // initialized to &_NSConcreteStackBlock or &_NSConcreteGlobalBlock - int flags; - int reserved; - void (*invoke)(void *, ...); - struct block_descriptor { - unsigned long int reserved; // NULL - unsigned long int size; // sizeof(struct Block_literal_1) - // optional helper functions - void (*copy_helper)(void *dst, void *src); // IFF (1<<25) - void (*dispose_helper)(void *src); // IFF (1<<25) - // required ABI.2010.3.16 - const char *signature; // IFF (1<<30) - } *descriptor; - // imported variables -}; - -typedef NS_OPTIONS(NSUInteger, PMKBlockDescriptionFlags) { - PMKBlockDescriptionFlagsHasCopyDispose = (1 << 25), - PMKBlockDescriptionFlagsHasCtor = (1 << 26), // helpers have C++ code - PMKBlockDescriptionFlagsIsGlobal = (1 << 28), - PMKBlockDescriptionFlagsHasStret = (1 << 29), // IFF BLOCK_HAS_SIGNATURE - PMKBlockDescriptionFlagsHasSignature = (1 << 30) -}; - -// It appears 10.7 doesn't support quotes in method signatures. Remove them -// via @rabovik's method. See https://github.com/OliverLetterer/SLObjectiveCRuntimeAdditions/pull/2 -#if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED < __MAC_10_8 -NS_INLINE static const char * pmk_removeQuotesFromMethodSignature(const char *str){ - char *result = malloc(strlen(str) + 1); - BOOL skip = NO; - char *to = result; - char c; - while ((c = *str++)) { - if ('"' == c) { - skip = !skip; - continue; - } - if (skip) continue; - *to++ = c; - } - *to = '\0'; - return result; -} -#endif - -static NSMethodSignature *NSMethodSignatureForBlock(id block) { - if (!block) - return nil; - - struct PMKBlockLiteral *blockRef = (__bridge struct PMKBlockLiteral *)block; - PMKBlockDescriptionFlags flags = (PMKBlockDescriptionFlags)blockRef->flags; - - if (flags & PMKBlockDescriptionFlagsHasSignature) { - void *signatureLocation = blockRef->descriptor; - signatureLocation += sizeof(unsigned long int); - signatureLocation += sizeof(unsigned long int); - - if (flags & PMKBlockDescriptionFlagsHasCopyDispose) { - signatureLocation += sizeof(void(*)(void *dst, void *src)); - signatureLocation += sizeof(void (*)(void *src)); - } - - const char *signature = (*(const char **)signatureLocation); -#if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED < __MAC_10_8 - signature = pmk_removeQuotesFromMethodSignature(signature); - NSMethodSignature *nsSignature = [NSMethodSignature signatureWithObjCTypes:signature]; - free((void *)signature); - - return nsSignature; -#endif - return [NSMethodSignature signatureWithObjCTypes:signature]; - } - return 0; -} diff --git a/Sources/PMKCallVariadicBlock.m b/Sources/PMKCallVariadicBlock.m deleted file mode 100644 index 1453a7d26..000000000 --- a/Sources/PMKCallVariadicBlock.m +++ /dev/null @@ -1,120 +0,0 @@ -#import "NSMethodSignatureForBlock.m" -#import -#import -#import "AnyPromise+Private.h" -#import -#import -#import - -#ifndef PMKLog -#define PMKLog NSLog -#endif - -@interface PMKArray : NSObject { -@public - id objs[3]; - NSUInteger count; -} @end - -@implementation PMKArray - -- (id)objectAtIndexedSubscript:(NSUInteger)idx { - if (count <= idx) { - // this check is necessary due to lack of checks in `pmk_safely_call_block` - return nil; - } - return objs[idx]; -} - -@end - -id __PMKArrayWithCount(NSUInteger count, ...) { - PMKArray *this = [PMKArray new]; - this->count = count; - va_list args; - va_start(args, count); - for (NSUInteger x = 0; x < count; ++x) - this->objs[x] = va_arg(args, id); - va_end(args); - return this; -} - - -static inline id _PMKCallVariadicBlock(id frock, id result) { - NSCAssert(frock, @""); - - NSMethodSignature *sig = NSMethodSignatureForBlock(frock); - const NSUInteger nargs = sig.numberOfArguments; - const char rtype = sig.methodReturnType[0]; - - #define call_block_with_rtype(type) ({^type{ \ - switch (nargs) { \ - case 1: \ - return ((type(^)(void))frock)(); \ - case 2: { \ - const id arg = [result class] == [PMKArray class] ? result[0] : result; \ - return ((type(^)(id))frock)(arg); \ - } \ - case 3: { \ - type (^block)(id, id) = frock; \ - return [result class] == [PMKArray class] \ - ? block(result[0], result[1]) \ - : block(result, nil); \ - } \ - case 4: { \ - type (^block)(id, id, id) = frock; \ - return [result class] == [PMKArray class] \ - ? block(result[0], result[1], result[2]) \ - : block(result, nil, nil); \ - } \ - default: \ - @throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"PromiseKit: The provided block’s argument count is unsupported." userInfo:nil]; \ - }}();}) - - switch (rtype) { - case 'v': - call_block_with_rtype(void); - return nil; - case '@': - return call_block_with_rtype(id) ?: nil; - case '*': { - char *str = call_block_with_rtype(char *); - return str ? @(str) : nil; - } - case 'c': return @(call_block_with_rtype(char)); - case 'i': return @(call_block_with_rtype(int)); - case 's': return @(call_block_with_rtype(short)); - case 'l': return @(call_block_with_rtype(long)); - case 'q': return @(call_block_with_rtype(long long)); - case 'C': return @(call_block_with_rtype(unsigned char)); - case 'I': return @(call_block_with_rtype(unsigned int)); - case 'S': return @(call_block_with_rtype(unsigned short)); - case 'L': return @(call_block_with_rtype(unsigned long)); - case 'Q': return @(call_block_with_rtype(unsigned long long)); - case 'f': return @(call_block_with_rtype(float)); - case 'd': return @(call_block_with_rtype(double)); - case 'B': return @(call_block_with_rtype(_Bool)); - case '^': - if (strcmp(sig.methodReturnType, "^v") == 0) { - call_block_with_rtype(void); - return nil; - } - // else fall through! - default: - @throw [NSException exceptionWithName:@"PromiseKit" reason:@"PromiseKit: Unsupported method signature." userInfo:nil]; - } -} - -static id PMKCallVariadicBlock(id frock, id result) { - @try { - return _PMKCallVariadicBlock(frock, result); - } @catch (id thrown) { - if ([thrown isKindOfClass:[NSString class]]) - return thrown; - if ([thrown isKindOfClass:[NSError class]]) - return thrown; - - // we don’t catch objc exceptions: they are meant to crash your app - @throw thrown; - } -} diff --git a/Sources/PMKCloudKit/CKContainer+Promise.swift b/Sources/PMKCloudKit/CKContainer+Promise.swift new file mode 100644 index 000000000..00ec575eb --- /dev/null +++ b/Sources/PMKCloudKit/CKContainer+Promise.swift @@ -0,0 +1,66 @@ +#if canImport(CloudKit) + +#if !PMKCocoaPods +import PromiseKit +#endif +import CloudKit + +/** + To import the `CKContainer` category: + + use_frameworks! + pod "PromiseKit/CloudKit" + + And then in your sources: + + @import PromiseKit; +*/ +public extension CKContainer { + /// Reports whether the current user’s iCloud account can be accessed. + func accountStatus() -> Promise { + return Promise { accountStatus(completionHandler: $0.resolve) } + } + + /// Requests the specified permission from the user asynchronously. +#if swift(<5.5) + func requestApplicationPermission(_ applicationPermissions: CKContainer_Application_Permissions) -> Promise { + return Promise { requestApplicationPermission(applicationPermissions, completionHandler: $0.resolve) } + } +#else + func requestApplicationPermission(_ applicationPermissions: CKContainer.ApplicationPermissions) -> Promise { + return Promise { requestApplicationPermission(applicationPermissions, completionHandler: $0.resolve) } + } +#endif + + /// Checks the status of the specified permission asynchronously. +#if swift(<5.5) + func status(forApplicationPermission applicationPermissions: CKContainer_Application_Permissions) -> Promise { + return Promise { status(forApplicationPermission: applicationPermissions, completionHandler: $0.resolve) } + } +#else + func status(forApplicationPermission applicationPermissions: CKContainer.ApplicationPermissions) -> Promise { + return Promise { status(forApplicationPermission: applicationPermissions, completionHandler: $0.resolve) } + } +#endif + /// Retrieves information about a single user based on the ID of the corresponding user record. + @available(macOS 10.12, iOS 10, tvOS 10, *) + func discoverUserIdentity(withUserRecordID recordID: CKRecord.ID) -> Promise { + return Promise { discoverUserIdentity(withUserRecordID: recordID, completionHandler: $0.resolve) } + } + + /// Returns the user record ID associated with the current user. + func fetchUserRecordID() -> Promise { + return Promise { fetchUserRecordID(completionHandler: $0.resolve) } + } +} + +#if !os(tvOS) +@available(macOS 10.12, iOS 10, tvOS 10, *) +public extension CKContainer { + func discoverAllIdentities() -> Promise<[CKUserIdentity]> { + return Promise { discoverAllIdentities(completionHandler: $0.resolve) } + } +} +#endif + +#endif diff --git a/Sources/PMKCloudKit/CKDatabase+Promise.swift b/Sources/PMKCloudKit/CKDatabase+Promise.swift new file mode 100644 index 000000000..df667efbe --- /dev/null +++ b/Sources/PMKCloudKit/CKDatabase+Promise.swift @@ -0,0 +1,91 @@ +#if canImport(CloudKit) + +import CloudKit.CKDatabase +#if !PMKCocoaPods +import PromiseKit +#endif + + +/** + To import the `CKDatabase` category: + + use_frameworks! + pod "PromiseKit/CloudKit" + + And then in your sources: + + @import PromiseKit; +*/ +public extension CKDatabase { + /// Fetches one record asynchronously from the current database. + func fetch(withRecordID recordID: CKRecord.ID) -> Promise { + return Promise { fetch(withRecordID: recordID, completionHandler: $0.resolve) } + } + + /// Fetches one record zone asynchronously from the current database. + func fetch(withRecordZoneID recordZoneID: CKRecordZone.ID) -> Promise { + return Promise { fetch(withRecordZoneID: recordZoneID, completionHandler: $0.resolve) } + } + /// Fetches all record zones asynchronously from the current database. + func fetchAllRecordZones() -> Promise<[CKRecordZone]> { + return Promise { fetchAllRecordZones(completionHandler: $0.resolve) } + } + + /// Saves one record zone asynchronously to the current database. + func save(_ record: CKRecord) -> Promise { + return Promise { save(record, completionHandler: $0.resolve) } + } + + /// Saves one record zone asynchronously to the current database. + func save(_ recordZone: CKRecordZone) -> Promise { + return Promise { save(recordZone, completionHandler: $0.resolve) } + } + + /// Delete one subscription object asynchronously from the current database. + func delete(withRecordID recordID: CKRecord.ID) -> Promise { + return Promise { delete(withRecordID: recordID, completionHandler: $0.resolve) } + } + + /// Delete one subscription object asynchronously from the current database. + func delete(withRecordZoneID zoneID: CKRecordZone.ID) -> Promise { + return Promise { delete(withRecordZoneID: zoneID, completionHandler: $0.resolve) } + } + + /// Searches the specified zone asynchronously for records that match the query parameters. + func perform(_ query: CKQuery, inZoneWith zoneID: CKRecordZone.ID? = nil) -> Promise<[CKRecord]> { + return Promise { perform(query, inZoneWith: zoneID, completionHandler: $0.resolve) } + } + + /// Fetches the record for the current user. + func fetchUserRecord(_ container: CKContainer = CKContainer.default()) -> Promise { + return container.fetchUserRecordID().then(on: nil) { uid in + return self.fetch(withRecordID: uid) + } + } +} + +#if !os(watchOS) +public extension CKDatabase { + /// Fetches one record zone asynchronously from the current database. + func fetch(withSubscriptionID subscriptionID: String) -> Promise { + return Promise { fetch(withSubscriptionID: subscriptionID, completionHandler: $0.resolve) } + } + + /// Fetches all subscription objects asynchronously from the current database. + func fetchAllSubscriptions() -> Promise<[CKSubscription]> { + return Promise { fetchAllSubscriptions(completionHandler: $0.resolve) } + } + + /// Saves one subscription object asynchronously to the current database. + func save(_ subscription: CKSubscription) -> Promise { + return Promise { save(subscription, completionHandler: $0.resolve) } + } + + /// Delete one subscription object asynchronously from the current database. + func delete(withSubscriptionID subscriptionID: String) -> Promise { + return Promise { delete(withSubscriptionID: subscriptionID, completionHandler: $0.resolve) } + } +} +#endif + +#endif diff --git a/Sources/PMKCoreLocation/.gitignore b/Sources/PMKCoreLocation/.gitignore new file mode 100644 index 000000000..bec9c1741 --- /dev/null +++ b/Sources/PMKCoreLocation/.gitignore @@ -0,0 +1,5 @@ +*.xcodeproj/**/xcuserdata/ +*.xcscmblueprint +/Carthage +/.build +.DS_Store \ No newline at end of file diff --git a/Sources/PMKCoreLocation/.travis.yml b/Sources/PMKCoreLocation/.travis.yml new file mode 100644 index 000000000..95c076137 --- /dev/null +++ b/Sources/PMKCoreLocation/.travis.yml @@ -0,0 +1,78 @@ +osx_image: xcode10.2 +language: swift +os: osx + +branches: + only: + - master +stages: + - lint + - carthage + - test +jobs: + include: + - &pod + stage: lint + osx_image: xcode8.3 + env: SWIFT=3.1 + before_install: + gem install cocoapods --prerelease --version 1.7.0.beta.3 + install: + carthage bootstrap --no-build PromiseKit + script: | + cd Carthage/Checkouts/PromiseKit + mv .github/PromiseKit.podspec . + rm -rf Extensions/CoreLocation/Sources + cp -R ../../../Sources Extensions/CoreLocation + pod lib lint --subspec=PromiseKit/CoreLocation --fail-fast --swift-version=$SWIFT + - <<: *pod + osx_image: xcode9.2 + env: SWIFT=3.2 + - <<: *pod + osx_image: xcode9.4 + env: SWIFT=3.3 + - <<: *pod + osx_image: xcode10.1 + env: SWIFT=3.4 + - <<: *pod + osx_image: xcode9.2 + env: SWIFT=4.0 + - <<: *pod + osx_image: xcode9.4 + env: SWIFT=4.1 + - <<: *pod + osx_image: xcode10.1 + env: SWIFT=4.2 + - <<: *pod + osx_image: xcode10.2 + env: SWIFT=5.0 + + - &carthage + stage: carthage + osx_image: xcode9.2 + script: | + carthage bootstrap --cache-builds + sed -i '' "s/SWIFT_TREAT_WARNINGS_AS_ERRORS = NO;/SWIFT_TREAT_WARNINGS_AS_ERRORS = YES;/" *.xcodeproj/project.pbxproj + carthage build --no-skip-current + cache.directories: + - Carthage + - <<: *carthage + osx_image: xcode9.4 + - <<: *carthage + osx_image: xcode10.1 + - <<: *carthage + osx_image: xcode10.2 + + - &test + stage: test + xcode_scheme: PMKCoreLocation + xcode_project: PMKCoreLocation.xcodeproj + xcode_destination: platform=macOS + cache.directories: + - Carthage + before_install: + carthage bootstrap --cache-builds --no-use-binaries + - <<: *test + xcode_destination: 'platform=iOS Simulator,OS=12.2,name=iPhone SE' + - <<: *test + xcode_destination: 'platform=tvOS Simulator,OS=12.2,name=Apple TV' diff --git a/Sources/PMKCoreLocation/CLGeocoder+Promise.swift b/Sources/PMKCoreLocation/CLGeocoder+Promise.swift new file mode 100644 index 000000000..792a01ce4 --- /dev/null +++ b/Sources/PMKCoreLocation/CLGeocoder+Promise.swift @@ -0,0 +1,85 @@ +#if canImport(CoreLocation) + +import CoreLocation.CLGeocoder +#if !PMKCocoaPods +import PromiseKit +#endif +#if os(iOS) || os(watchOS) || os(macOS) +import class Contacts.CNPostalAddress +#endif + +/** + To import the `CLGeocoder` category: + + use_frameworks! + pod "PromiseKit/CoreLocation" + + And then in your sources: + + import PromiseKit +*/ +extension CLGeocoder { + /// Submits a reverse-geocoding request for the specified location. + public func reverseGeocode(location: CLLocation) -> Promise<[CLPlacemark]> { + return Promise { seal in + reverseGeocodeLocation(location, completionHandler: seal.resolve) + } + } + + /// Submits a forward-geocoding request using the specified address dictionary. + @available(iOS, deprecated: 11.0) + public func geocode(_ addressDictionary: [String: String]) -> Promise<[CLPlacemark]> { + return Promise { seal in + geocodeAddressDictionary(addressDictionary, completionHandler: seal.resolve) + } + } + + /// Submits a forward-geocoding request using the specified address string. + public func geocode(_ addressString: String) -> Promise<[CLPlacemark]> { + return Promise { seal in + geocodeAddressString(addressString, completionHandler: seal.resolve) + } + } + + /// Submits a forward-geocoding request using the specified address string within the specified region. + public func geocode(_ addressString: String, region: CLRegion?) -> Promise<[CLPlacemark]> { + return Promise { seal in + geocodeAddressString(addressString, in: region, completionHandler: seal.resolve) + } + } + +#if !os(tvOS) && swift(>=3.2) + /// Submits a forward-geocoding request using the specified postal address. + @available(iOS 11.0, OSX 10.13, watchOS 4.0, *) + public func geocodePostalAddress(_ postalAddress: CNPostalAddress) -> Promise<[CLPlacemark]> { + return Promise { seal in + geocodePostalAddress(postalAddress, completionHandler: seal.resolve) + } + } + + /// Submits a forward-geocoding requesting using the specified locale and postal address + @available(iOS 11.0, OSX 10.13, watchOS 4.0, *) + public func geocodePostalAddress(_ postalAddress: CNPostalAddress, preferredLocale locale: Locale?) -> Promise<[CLPlacemark]> { + return Promise { seal in + geocodePostalAddress(postalAddress, preferredLocale: locale, completionHandler: seal.resolve) + } + } + + /// Submits a reverse-geocoding request for the specified location and a preferred locale. + @available(iOS 11.0, OSX 10.13, watchOS 4.0, *) + public func reverseGeocode(location: CLLocation, preferredLocale locale: Locale?) -> Promise<[CLPlacemark]> { + return Promise { seal in + reverseGeocodeLocation(location, preferredLocale: locale, completionHandler: seal.resolve) + } + } +#endif +} + +// TODO still not possible in Swift 3.2 +//extension CLError: CancellableError { +// public var isCancelled: Bool { +// return self == .geocodeCanceled +// } +//} + +#endif diff --git a/Sources/PMKCoreLocation/CLLocationManager+Promise.swift b/Sources/PMKCoreLocation/CLLocationManager+Promise.swift new file mode 100644 index 000000000..7944ef37d --- /dev/null +++ b/Sources/PMKCoreLocation/CLLocationManager+Promise.swift @@ -0,0 +1,315 @@ +#if canImport(CoreLocation) + +import CoreLocation.CLLocationManager +#if !PMKCocoaPods +import PromiseKit +#endif + +/** + To import the `CLLocationManager` category: + + use_frameworks! + pod "PromiseKit/CoreLocation" + + And then in your sources: + + import PromiseKit +*/ +extension CLLocationManager { + + /// The type of location permission we are asking for + public enum RequestAuthorizationType { + /// Determine the authorization from the application’s plist + case automatic + /// Request always-authorization + case always + /// Request when-in-use-authorization + case whenInUse + } + + public enum PMKError: Error { + case notAuthorized + case unhandledEnumCase + } + + /** + Request the current location. + - Note: to obtain a single location use `Promise.lastValue` + - Parameters: + - authorizationType: requestAuthorizationType: We read your Info plist and try to + determine the authorization type we should request automatically. If you + want to force one or the other, change this parameter from its default + value. + - block: A block by which to perform any filtering of the locations that are + returned. In order to only retrieve accurate locations, only return true if the + locations horizontal accuracy < 50 + - Returns: A new promise that fulfills with the most recent CLLocation that satisfies + the provided block if it exists. If the block does not exist, simply return the + last location. + */ + public class func requestLocation(authorizationType: RequestAuthorizationType = .automatic, satisfying block: ((CLLocation) -> Bool)? = nil) -> Promise<[CLLocation]> { + + func std() -> Promise<[CLLocation]> { + return LocationManager(satisfying: block).promise + } + + func auth() -> Promise { + #if os(macOS) + return Promise() + #else + func auth(type: PMKCLAuthorizationType) -> Promise { + return AuthorizationCatcher(type: type).promise.done(on: nil) { + switch $0 { + case .restricted, .denied: + throw PMKError.notAuthorized + default: + break + } + } + } + + switch authorizationType { + case .automatic: + switch Bundle.main.permissionType { + case .always, .both: + return auth(type: .always) + case .whenInUse: + return auth(type: .whenInUse) + } + case .whenInUse: + return auth(type: .whenInUse) + case .always: + return auth(type: .always) + } + #endif + } + + switch CLLocationManager.authorizationStatus() { + case .authorizedAlways, .authorizedWhenInUse: + return std() + case .notDetermined: + return auth().then(std) + case .denied, .restricted: + return Promise(error: PMKError.notAuthorized) + @unknown default: + return Promise(error: PMKError.unhandledEnumCase) + } + } + + @available(*, deprecated, renamed: "requestLocation") + public class func promise(_ requestAuthorizationType: RequestAuthorizationType = .automatic, satisfying block: ((CLLocation) -> Bool)? = nil) -> Promise<[CLLocation]> { + return requestLocation(authorizationType: requestAuthorizationType, satisfying: block) + } +} + +private class LocationManager: CLLocationManager, CLLocationManagerDelegate { + let (promise, seal) = Promise<[CLLocation]>.pending() + let satisfyingBlock: ((CLLocation) -> Bool)? + + @objc fileprivate func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { + if let block = satisfyingBlock { + let satisfiedLocations = locations.filter(block) + if !satisfiedLocations.isEmpty { + seal.fulfill(satisfiedLocations) + } else { + #if os(tvOS) + requestLocation() + #endif + } + } else { + seal.fulfill(locations) + } + } + + init(satisfying block: ((CLLocation) -> Bool)? = nil) { + satisfyingBlock = block + super.init() + delegate = self + #if !os(tvOS) + startUpdatingLocation() + #else + requestLocation() + #endif + _ = self.promise.ensure { + self.stopUpdatingLocation() + } + } + + @objc func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) { + let (domain, code) = { ($0.domain, $0.code) }(error as NSError) + if code == CLError.locationUnknown.rawValue && domain == kCLErrorDomain { + // Apple docs say you should just ignore this error + print("PromiseKit: warning: CLError.locationUnknown") + } else { + seal.reject(error) + } + } +} + + +#if !os(macOS) + +extension CLLocationManager { + /** + Request CoreLocation authorization from the user + - Note: By default we try to determine the authorization type you want by inspecting your Info.plist + - Note: This method will not perform upgrades from “when-in-use” to “always” unless you specify `.always` for the value of `type`. + */ + @available(iOS 8, tvOS 9, watchOS 2, *) + public class func requestAuthorization(type requestedAuthorizationType: RequestAuthorizationType = .automatic) -> Guarantee { + + let currentStatus = CLLocationManager.authorizationStatus() + + func std(type: PMKCLAuthorizationType) -> Guarantee { + if currentStatus == .notDetermined { + return AuthorizationCatcher(type: type).promise + } else { + return .value(currentStatus) + } + } + + switch requestedAuthorizationType { + case .always: + func iOS11Check() -> Guarantee { + switch currentStatus { + case .notDetermined, .authorizedWhenInUse: + return AuthorizationCatcher(type: .always).promise + default: + return .value(currentStatus) + } + } + #if PMKiOS11 + // ^^ define PMKiOS11 if you deploy against the iOS 11 SDK + // otherwise the warning you get below cannot be removed + return iOS11Check() + #else + if #available(iOS 11, *) { + return iOS11Check() + } else { + return std(type: .always) + } + #endif + + case .whenInUse: + return std(type: .whenInUse) + + case .automatic: + if currentStatus == .notDetermined { + switch Bundle.main.permissionType { + case .both, .whenInUse: + return AuthorizationCatcher(type: .whenInUse).promise + case .always: + return AuthorizationCatcher(type: .always).promise + } + } else { + return .value(currentStatus) + } + } + } +} + +@available(iOS 8, *) +private class AuthorizationCatcher: CLLocationManager, CLLocationManagerDelegate { + let (promise, fulfill) = Guarantee.pending() + var retainCycle: AuthorizationCatcher? + let initialAuthorizationState = CLLocationManager.authorizationStatus() + + init(type: PMKCLAuthorizationType) { + super.init() + + func ask(type: PMKCLAuthorizationType) { + delegate = self + retainCycle = self + + switch type { + case .always: + #if os(tvOS) + fallthrough + #else + requestAlwaysAuthorization() + #endif + case .whenInUse: + requestWhenInUseAuthorization() + } + + promise.done { _ in + self.retainCycle = nil + } + } + + func iOS11Check() { + switch (initialAuthorizationState, type) { + case (.notDetermined, .always), (.authorizedWhenInUse, .always), (.notDetermined, .whenInUse): + ask(type: type) + default: + fulfill(initialAuthorizationState) + } + } + + #if PMKiOS11 + // ^^ define PMKiOS11 if you deploy against the iOS 11 SDK + // otherwise the warning you get below cannot be removed + iOS11Check() + #else + if #available(iOS 11, *) { + iOS11Check() + } else { + if initialAuthorizationState == .notDetermined { + ask(type: type) + } else { + fulfill(initialAuthorizationState) + } + } + #endif + } + + @objc fileprivate func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) { + // `didChange` is a lie; it fires this immediately with the current status. + if status != initialAuthorizationState { + fulfill(status) + } + } +} + +#endif + +private extension Bundle { + enum PermissionType { + case both + case always + case whenInUse + } + + var permissionType: PermissionType { + func hasInfoPlistKey(_ key: String) -> Bool { + let value = object(forInfoDictionaryKey: key) as? String ?? "" + return !value.isEmpty + } + + if hasInfoPlistKey("NSLocationAlwaysAndWhenInUseUsageDescription") { + return .both + } + if hasInfoPlistKey("NSLocationAlwaysUsageDescription") { + return .always + } + if hasInfoPlistKey("NSLocationWhenInUseUsageDescription") { + return .whenInUse + } + + if #available(iOS 11, *) { + NSLog("PromiseKit: warning: `NSLocationAlwaysAndWhenInUseUsageDescription` key not set") + } else { + NSLog("PromiseKit: warning: `NSLocationWhenInUseUsageDescription` key not set") + } + + // won't work, but we warned the user above at least + return .whenInUse + } +} + +private enum PMKCLAuthorizationType { + case always + case whenInUse +} + +#endif diff --git a/Sources/PMKFoundation/NSNotificationCenter+Promise.swift b/Sources/PMKFoundation/NSNotificationCenter+Promise.swift new file mode 100644 index 000000000..3b7f84345 --- /dev/null +++ b/Sources/PMKFoundation/NSNotificationCenter+Promise.swift @@ -0,0 +1,33 @@ +import Foundation +#if !PMKCocoaPods +import PromiseKit +#endif + +/** + To import the `NSNotificationCenter` category: + + use_frameworks! + pod "PromiseKit/Foundation" + + Or `NSNotificationCenter` is one of the categories imported by the umbrella pod: + + use_frameworks! + pod "PromiseKit" + + And then in your sources: + + import PromiseKit +*/ +extension NotificationCenter { + /// Observe the named notification once + public func observe(once name: Notification.Name, object: Any? = nil) -> Guarantee { + let (promise, fulfill) = Guarantee.pending() + #if os(Linux) && ((swift(>=4.0) && !swift(>=4.0.1)) || (swift(>=3.0) && !swift(>=3.2.1))) + let id = addObserver(forName: name, object: object, queue: nil, usingBlock: fulfill) + #else + let id = addObserver(forName: name, object: object, queue: nil, using: fulfill) + #endif + promise.done { _ in self.removeObserver(id) } + return promise + } +} diff --git a/Sources/PMKFoundation/NSObject+Promise.swift b/Sources/PMKFoundation/NSObject+Promise.swift new file mode 100644 index 000000000..c40bc8cb0 --- /dev/null +++ b/Sources/PMKFoundation/NSObject+Promise.swift @@ -0,0 +1,61 @@ +#if !os(Linux) && !os(Windows) + +import Foundation +#if !PMKCocoaPods +import PromiseKit +#endif + +/** + To import the `NSObject` category: + + use_frameworks! + pod "PromiseKit/Foundation" + + Or `NSObject` is one of the categories imported by the umbrella pod: + + use_frameworks! + pod "PromiseKit" + + And then in your sources: + + import PromiseKit +*/ +extension NSObject { + /** + - Returns: A promise that resolves when the provided keyPath changes. + - Warning: *Important* The promise must not outlive the object under observation. + - SeeAlso: Apple’s KVO documentation. + */ + public func observe(_: PMKNamespacer, keyPath: String) -> Guarantee { + return Guarantee { KVOProxy(observee: self, keyPath: keyPath, resolve: $0) } + } +} + +private class KVOProxy: NSObject { + var retainCycle: KVOProxy? + let fulfill: (Any?) -> Void + + @discardableResult + init(observee: NSObject, keyPath: String, resolve: @escaping (Any?) -> Void) { + fulfill = resolve + super.init() + observee.addObserver(self, forKeyPath: keyPath, options: NSKeyValueObservingOptions.new, context: pointer) + retainCycle = self + } + + fileprivate override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { + if let change = change, context == pointer { + defer { retainCycle = nil } + fulfill(change[NSKeyValueChangeKey.newKey]) + if let object = object as? NSObject, let keyPath = keyPath { + object.removeObserver(self, forKeyPath: keyPath) + } + } + } + + private lazy var pointer: UnsafeMutableRawPointer = { + return Unmanaged.passUnretained(self).toOpaque() + }() +} + +#endif diff --git a/Sources/PMKFoundation/NSURLSession+Promise.swift b/Sources/PMKFoundation/NSURLSession+Promise.swift new file mode 100644 index 000000000..deb913b48 --- /dev/null +++ b/Sources/PMKFoundation/NSURLSession+Promise.swift @@ -0,0 +1,240 @@ +import Foundation +#if !PMKCocoaPods +import PromiseKit +#endif +#if canImport(FoundationNetworking) +import FoundationNetworking +#endif + +/** + To import the `NSURLSession` category: + + use_frameworks! + pod "PromiseKit/Foundation" + + Or `NSURLSession` is one of the categories imported by the umbrella pod: + + use_frameworks! + pod "PromiseKit" + + And then in your sources: + + import PromiseKit +*/ +extension URLSession { + /** + Example usage: + + firstly { + URLSession.shared.dataTask(.promise, with: rq) + }.compactMap { data, _ in + try JSONSerialization.jsonObject(with: data) as? [String: Any] + }.then { json in + //… + } + + We recommend the use of [OMGHTTPURLRQ] which allows you to construct correct REST requests: + + firstly { + let rq = OMGHTTPURLRQ.POST(url, json: parameters) + URLSession.shared.dataTask(.promise, with: rq) + }.then { data, urlResponse in + //… + } + + We provide a convenience initializer for `String` specifically for this promise: + + firstly { + URLSession.shared.dataTask(.promise, with: rq) + }.compactMap(String.init).then { string in + // decoded per the string encoding specified by the server + }.then { string in + print("response: string") + } + + Other common types can be easily decoded using compactMap also: + + firstly { + URLSession.shared.dataTask(.promise, with: rq) + }.compactMap { + UIImage(data: $0) + }.then { + self.imageView.image = $0 + } + + Though if you do decode the image this way, we recommend inflating it on a background thread + first as this will improve main thread performance when rendering the image: + + firstly { + URLSession.shared.dataTask(.promise, with: rq) + }.compactMap(on: QoS.userInitiated) { data, _ in + guard let img = UIImage(data: data) else { return nil } + _ = cgImage?.dataProvider?.data + return img + }.then { + self.imageView.image = $0 + } + + - Parameter convertible: A URL or URLRequest. + - Returns: A promise that represents the URL request. + - SeeAlso: [OMGHTTPURLRQ] + - Remark: We deliberately don’t provide a `URLRequestConvertible` for `String` because in our experience, you should be explicit with this error path to make good apps. + + [OMGHTTPURLRQ]: https://github.com/mxcl/OMGHTTPURLRQ + */ + public func dataTask(_: PMKNamespacer, with convertible: URLRequestConvertible) -> Promise<(data: Data, response: URLResponse)> { + return Promise { dataTask(with: convertible.pmkRequest, completionHandler: adapter($0)).resume() } + } + + public func uploadTask(_: PMKNamespacer, with convertible: URLRequestConvertible, from data: Data) -> Promise<(data: Data, response: URLResponse)> { + return Promise { uploadTask(with: convertible.pmkRequest, from: data, completionHandler: adapter($0)).resume() } + } + + public func uploadTask(_: PMKNamespacer, with convertible: URLRequestConvertible, fromFile file: URL) -> Promise<(data: Data, response: URLResponse)> { + return Promise { uploadTask(with: convertible.pmkRequest, fromFile: file, completionHandler: adapter($0)).resume() } + } + + /// - Remark: we force a `to` parameter because Apple deletes the downloaded file immediately after the underyling completion handler returns. + /// - Note: we do not create the destination directory for you, because we move the file with FileManager.moveItem which changes it behavior depending on the directory status of the URL you provide. So create your own directory first! + public func downloadTask(_: PMKNamespacer, with convertible: URLRequestConvertible, to saveLocation: URL) -> Promise<(saveLocation: URL, response: URLResponse)> { + return Promise { seal in + downloadTask(with: convertible.pmkRequest, completionHandler: { tmp, rsp, err in + if let error = err { + seal.reject(error) + } else if let rsp = rsp, let tmp = tmp { + do { + try FileManager.default.moveItem(at: tmp, to: saveLocation) + seal.fulfill((saveLocation, rsp)) + } catch { + seal.reject(error) + } + } else { + seal.reject(PMKError.invalidCallingConvention) + } + }).resume() + } + } +} + + +public protocol URLRequestConvertible { + var pmkRequest: URLRequest { get } +} +extension URLRequest: URLRequestConvertible { + public var pmkRequest: URLRequest { return self } +} +extension URL: URLRequestConvertible { + public var pmkRequest: URLRequest { return URLRequest(url: self) } +} + + +#if !os(Linux) && !os(Windows) +public extension String { + /** + - Remark: useful when converting a `URLSession` response into a `String` + + firstly { + URLSession.shared.dataTask(.promise, with: rq) + }.map(String.init).done { + print($0) + } + */ + init?(data: Data, urlResponse: URLResponse) { + guard let str = String(bytes: data, encoding: urlResponse.stringEncoding ?? .utf8) else { + return nil + } + self.init(str) + } +} + +private extension URLResponse { + var stringEncoding: String.Encoding? { + guard let encodingName = textEncodingName else { return nil } + let encoding = CFStringConvertIANACharSetNameToEncoding(encodingName as CFString) + guard encoding != kCFStringEncodingInvalidId else { return nil } + return String.Encoding(rawValue: CFStringConvertEncodingToNSStringEncoding(encoding)) + } +} +#endif + +private func adapter(_ seal: Resolver<(data: T, response: U)>) -> (T?, U?, Error?) -> Void { + return { t, u, e in + if let t = t, let u = u { + seal.fulfill((t, u)) + } else if let e = e { + seal.reject(e) + } else { + seal.reject(PMKError.invalidCallingConvention) + } + } +} + + +public enum PMKHTTPError: Error, LocalizedError, CustomStringConvertible { + case badStatusCode(Int, Data, HTTPURLResponse) + + public var errorDescription: String? { + func url(_ rsp: URLResponse) -> String { + return rsp.url?.absoluteString ?? "nil" + } + switch self { + case .badStatusCode(401, _, let response): + return "Unauthorized (\(url(response))" + case .badStatusCode(let code, _, let response): + return "Invalid HTTP response (\(code)) for \(url(response))." + } + } + + public func decodeResponse(_ t: T.Type, decoder: JSONDecoder = JSONDecoder()) -> T? { + switch self { + case .badStatusCode(_, let data, _): + return try? decoder.decode(t, from: data) + } + } + + //TODO rename responseJSON + public var jsonDictionary: Any? { + switch self { + case .badStatusCode(_, let data, _): + return try? JSONSerialization.jsonObject(with: data) + } + } + + var responseBodyString: String? { + switch self { + case .badStatusCode(_, let data, _): + return String(data: data, encoding: .utf8) + } + } + + public var failureReason: String? { + return responseBodyString + } + + public var description: String { + switch self { + case .badStatusCode(let code, let data, let response): + var dict: [String: Any] = [ + "Status Code": code, + "Body": String(data: data, encoding: .utf8) ?? "\(data.count) bytes" + ] + dict["URL"] = response.url + dict["Headers"] = response.allHeaderFields + return " \(NSDictionary(dictionary: dict))" // as NSDictionary makes the output look like NSHTTPURLResponse looks + } + } +} + +public extension Promise where T == (data: Data, response: URLResponse) { + func validate() -> Promise { + return map { + guard let response = $0.response as? HTTPURLResponse else { return $0 } + switch response.statusCode { + case 200..<300: + return $0 + case let code: + throw PMKHTTPError.badStatusCode(code, $0.data, response) + } + } + } +} diff --git a/Sources/PMKFoundation/Process+Promise.swift b/Sources/PMKFoundation/Process+Promise.swift new file mode 100644 index 000000000..a88cb159c --- /dev/null +++ b/Sources/PMKFoundation/Process+Promise.swift @@ -0,0 +1,175 @@ +#if os(macOS) + +import Foundation +#if !PMKCocoaPods +import PromiseKit +#endif + +/** + To import the `Process` category: + + use_frameworks! + pod "PromiseKit/Foundation" + + Or `Process` is one of the categories imported by the umbrella pod: + + use_frameworks! + pod "PromiseKit" + + And then in your sources: + + import PromiseKit + */ +extension Process { + /** + Launches the receiver and resolves when it exits. + + let proc = Process() + proc.launchPath = "/bin/ls" + proc.arguments = ["/bin"] + proc.launch(.promise).compactMap { std in + String(data: std.out.fileHandleForReading.readDataToEndOfFile(), encoding: .utf8) + }.then { stdout in + print(str) + } + */ + public func launch(_: PMKNamespacer) -> Promise<(out: Pipe, err: Pipe)> { + let (stdout, stderr) = (Pipe(), Pipe()) + + do { + standardOutput = stdout + standardError = stderr + + if #available(OSX 10.13, *) { + try run() + } else if let path = launchPath, FileManager.default.isExecutableFile(atPath: path) { + launch() + } else { + throw PMKError.notExecutable(launchPath) + } + } catch { + return Promise(error: error) + } + + + var q: DispatchQueue { + if #available(macOS 10.10, iOS 8.0, tvOS 9.0, watchOS 2.0, *) { + return DispatchQueue.global(qos: .default) + } else { + return DispatchQueue.global(priority: .default) + } + } + + return Promise { seal in + q.async { + self.waitUntilExit() + + guard self.terminationReason == .exit, self.terminationStatus == 0 else { + let stdoutData = try? self.readDataFromPipe(stdout) + let stderrData = try? self.readDataFromPipe(stderr) + + let stdoutString = stdoutData.flatMap { (data: Data) -> String? in String(data: data, encoding: .utf8) } + let stderrString = stderrData.flatMap { (data: Data) -> String? in String(data: data, encoding: .utf8) } + + return seal.reject(PMKError.execution(process: self, standardOutput: stdoutString, standardError: stderrString)) + } + seal.fulfill((stdout, stderr)) + } + } + } + + private func readDataFromPipe(_ pipe: Pipe) throws -> Data { + let handle = pipe.fileHandleForReading + defer { handle.closeFile() } + + // Someday, NSFileHandle will probably be updated with throwing equivalents to its read and write methods, + // as NSTask has, to avoid raising exceptions and crashing the app. + // Unfortunately that day has not yet come, so use the underlying BSD calls for now. + + let fd = handle.fileDescriptor + + let bufsize = 1024 * 8 + let buf = UnsafeMutablePointer.allocate(capacity: bufsize) + + defer { buf.deallocate() } + + var data = Data() + + while true { + let bytesRead = read(fd, buf, bufsize) + + if bytesRead == 0 { + break + } + + if bytesRead < 0 { + throw POSIXError.Code(rawValue: errno).map { POSIXError($0) } ?? CocoaError(.fileReadUnknown) + } + + data.append(buf, count: bytesRead) + } + + return data + } + + /** + The error generated by PromiseKit’s `Process` extension + */ + public enum PMKError { + /// NOT AVAILABLE ON 10.13 and above because Apple provide this error handling themselves + case notExecutable(String?) + case execution(process: Process, standardOutput: String?, standardError: String?) + } +} + + +extension Process.PMKError: LocalizedError { + public var errorDescription: String? { + switch self { + case .notExecutable(let path?): + return "File not executable: \(path)" + case .notExecutable(nil): + return "No launch path specified" + case .execution(process: let task, standardOutput: _, standardError: _): + return "Failed executing: `\(task)` (\(task.terminationStatus))." + } + } +} + +public extension Promise where T == (out: Pipe, err: Pipe) { + func print() -> Promise { + return tap { result in + switch result { + case .success(let raw): + let stdout = String(data: raw.out.fileHandleForReading.readDataToEndOfFile(), encoding: .utf8) + let stderr = String(data: raw.err.fileHandleForReading.readDataToEndOfFile(), encoding: .utf8) + Swift.print("stdout: `\(stdout ?? "")`") + Swift.print("stderr: `\(stderr ?? "")`") + case .failure(let err): + Swift.print(err) + } + } + } +} + +extension Process { + /// Provided because Foundation’s is USELESS + open override var description: String { + let launchPath = self.launchPath ?? "$0" + var args = [launchPath] + arguments.flatMap{ args += $0 } + return args.map { arg in + let contains: Bool + contains = arg.contains(" ") + if contains { + return "\"\(arg)\"" + } else if arg == "" { + return "\"\"" + } else { + return arg + } + }.joined(separator: " ") + } +} + +#endif diff --git a/Sources/PMKFoundation/afterlife.swift b/Sources/PMKFoundation/afterlife.swift new file mode 100644 index 000000000..b7168d921 --- /dev/null +++ b/Sources/PMKFoundation/afterlife.swift @@ -0,0 +1,30 @@ +#if !os(Linux) && !os(Windows) + +import Foundation +#if !PMKCocoaPods +import PromiseKit +#endif + +/** + - Returns: A promise that resolves when the provided object deallocates + - Important: The promise is not guaranteed to resolve immediately when the provided object is deallocated. So you cannot write code that depends on exact timing. + */ +public func after(life object: NSObject) -> Guarantee { + var reaper = objc_getAssociatedObject(object, &handle) as? GrimReaper + if reaper == nil { + reaper = GrimReaper() + objc_setAssociatedObject(object, &handle, reaper, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) + } + return reaper!.promise +} + +private var handle: UInt8 = 0 + +private class GrimReaper: NSObject { + deinit { + fulfill(()) + } + let (promise, fulfill) = Guarantee.pending() +} + +#endif diff --git a/Sources/PMKHealthKit/.gitignore b/Sources/PMKHealthKit/.gitignore new file mode 100644 index 000000000..bec9c1741 --- /dev/null +++ b/Sources/PMKHealthKit/.gitignore @@ -0,0 +1,5 @@ +*.xcodeproj/**/xcuserdata/ +*.xcscmblueprint +/Carthage +/.build +.DS_Store \ No newline at end of file diff --git a/Sources/PMKHealthKit/.travis.yml b/Sources/PMKHealthKit/.travis.yml new file mode 100644 index 000000000..91caf3a78 --- /dev/null +++ b/Sources/PMKHealthKit/.travis.yml @@ -0,0 +1,76 @@ +osx_image: xcode10.2 +language: swift +os: osx + +branches: + only: + - master +stages: + - lint + - test +jobs: + include: + - &pod + stage: lint + osx_image: xcode8.3 + env: SWIFT=3.1 + cache: cocoapods + before_install: + gem install cocoapods --prerelease --version 1.7.0.beta.3 + install: + carthage bootstrap --no-build PromiseKit + script: | + cd Carthage/Checkouts/PromiseKit + mv .github/PromiseKit.podspec . + rm -rf Extensions/HealthKit/Sources + cp -R ../../../Sources Extensions/HealthKit + pod lib lint --subspec=PromiseKit/HealthKit --fail-fast --swift-version=$SWIFT + - <<: *pod + osx_image: xcode9.2 + env: SWIFT=3.2 + - <<: *pod + osx_image: xcode9.4 + env: SWIFT=3.3 + - <<: *pod + osx_image: xcode10.1 + env: SWIFT=3.4 + - <<: *pod + osx_image: xcode9.2 + env: SWIFT=4.0 + - <<: *pod + osx_image: xcode9.4 + env: SWIFT=4.1 + - <<: *pod + osx_image: xcode10.1 + env: SWIFT=4.2 + - <<: *pod + osx_image: xcode10.2 + env: SWIFT=4.3 + - <<: *pod + osx_image: xcode10.2 + env: SWIFT=5.0 + + - &carthage + stage: carthage + osx_image: xcode9.2 + script: | + carthage bootstrap --cache-builds --platform iOS,macOS + sed -i '' "s/SWIFT_TREAT_WARNINGS_AS_ERRORS = NO;/SWIFT_TREAT_WARNINGS_AS_ERRORS = YES;/" *.xcodeproj/project.pbxproj + carthage build --no-skip-current + cache.directories: + - Carthage + - <<: *carthage + osx_image: xcode9.4 + - <<: *carthage + osx_image: xcode10.1 + - <<: *carthage + osx_image: xcode10.2 + + - stage: test + xcode_scheme: PMKHealthKit + xcode_project: PMKHealthKit.xcodeproj + xcode_destination: 'platform=iOS Simulator,OS=12.2,name=iPhone SE' + cache.directories: + - Carthage + before_install: + carthage bootstrap --cache-builds --no-use-binaries diff --git a/Sources/PMKHealthKit/HealthKit+Promise.swift b/Sources/PMKHealthKit/HealthKit+Promise.swift new file mode 100644 index 000000000..bc40f41c1 --- /dev/null +++ b/Sources/PMKHealthKit/HealthKit+Promise.swift @@ -0,0 +1,87 @@ +#if !os(tvOS) && canImport(HealthKit) + +#if !PMKCocoaPods +import PromiseKit +#endif +import HealthKit + +public extension HKHealthStore { + func requestAuthorization(toShare typesToShare: Set?, read typesToRead: Set?) -> Promise { + return Promise { seal in + requestAuthorization(toShare: typesToShare, read: typesToRead, completion: seal.resolve) + } + } + +#if os(iOS) + func enableBackgroundDelivery(for type: HKObjectType, frequency: HKUpdateFrequency) -> Promise { + return Promise { seal in + enableBackgroundDelivery(for: type, frequency: frequency, withCompletion: seal.resolve) + } + } +#endif +} + +public extension HKStatisticsQuery { + static func promise(quantityType: HKQuantityType, quantitySamplePredicate: NSPredicate? = nil, options: HKStatisticsOptions = [], healthStore: HKHealthStore = .init()) -> Promise { + return Promise { seal in + let query = HKStatisticsQuery(quantityType: quantityType, quantitySamplePredicate: quantitySamplePredicate, options: options) { + seal.resolve($1, $2) + } + healthStore.execute(query) + } + } +} + +public extension HKAnchoredObjectQuery { + static func promise(type: HKSampleType, predicate: NSPredicate? = nil, anchor: HKQueryAnchor? = nil, limit: Int = HKObjectQueryNoLimit, healthStore: HKHealthStore = .init()) -> Promise<([HKSample], [HKDeletedObject], HKQueryAnchor)> { + return Promise { seal in + let query = HKAnchoredObjectQuery(type: type, predicate: predicate, anchor: anchor, limit: limit) { + if let a = $1, let b = $2, let c = $3 { + seal.fulfill((a, b, c)) + } else if let e = $4 { + seal.reject(e) + } else { + seal.reject(PMKError.invalidCallingConvention) + } + } + healthStore.execute(query) + } + } + +} + +public extension HKStatisticsCollectionQuery { + func promise(healthStore: HKHealthStore = .init()) -> Promise { + return Promise { seal in + initialResultsHandler = { + seal.resolve($1, $2) + } + healthStore.execute(self) + } + } +} + +public extension HKSampleQuery { + static func promise(sampleType: HKSampleType, predicate: NSPredicate? = nil, limit: Int = HKObjectQueryNoLimit, sortDescriptors: [NSSortDescriptor]? = nil, healthStore: HKHealthStore = .init()) -> Promise<[HKSample]> { + return Promise { seal in + let query = HKSampleQuery(sampleType: sampleType, predicate: predicate, limit: limit, sortDescriptors: sortDescriptors) { + seal.resolve($1, $2) + } + healthStore.execute(query) + } + } +} + +@available(iOS 9.3, iOSApplicationExtension 9.3, watchOSApplicationExtension 2.2, *) +public extension HKActivitySummaryQuery { + static func promise(predicate: NSPredicate, healthStore: HKHealthStore = .init()) -> Promise<[HKActivitySummary]> { + return Promise { seal in + let query = HKActivitySummaryQuery(predicate: predicate) { + seal.resolve($1, $2) + } + healthStore.execute(query) + } + } +} + +#endif diff --git a/Sources/PMKHomeKit/.gitignore b/Sources/PMKHomeKit/.gitignore new file mode 100644 index 000000000..bec9c1741 --- /dev/null +++ b/Sources/PMKHomeKit/.gitignore @@ -0,0 +1,5 @@ +*.xcodeproj/**/xcuserdata/ +*.xcscmblueprint +/Carthage +/.build +.DS_Store \ No newline at end of file diff --git a/Sources/PMKHomeKit/.travis.yml b/Sources/PMKHomeKit/.travis.yml new file mode 100644 index 000000000..5a0f7450a --- /dev/null +++ b/Sources/PMKHomeKit/.travis.yml @@ -0,0 +1,67 @@ +os: osx +language: swift +osx_image: xcode10.2 + +branches: + only: + - master +stages: + - lint + - carthage + - test +jobs: + include: + - &pod + stage: lint + osx_image: xcode9.4 + env: SWIFT=3.3 + before_install: + gem install cocoapods --prerelease --version 1.7.0.beta.3 + install: + carthage bootstrap --no-build PromiseKit + script: | + cd Carthage/Checkouts/PromiseKit + mv .github/PromiseKit.podspec . + rm -rf Extensions/HomeKit/Sources + cp -R ../../../Sources Extensions/HomeKit + pod lib lint --subspec=PromiseKit/HomeKit --fail-fast --swift-version=$SWIFT + - <<: *pod + osx_image: xcode10.1 + env: SWIFT=3.4 + - <<: *pod + osx_image: xcode9.4 + env: SWIFT=4.1 + - <<: *pod + osx_image: xcode10.1 + env: SWIFT=4.2 + - <<: *pod + osx_image: xcode10.2 + env: SWIFT=5.0 + + - &carthage + stage: carthage + osx_image: xcode9.4 + script: | + carthage bootstrap --cache-builds + sed -i '' "s/SWIFT_TREAT_WARNINGS_AS_ERRORS = NO;/SWIFT_TREAT_WARNINGS_AS_ERRORS = YES;/" *.xcodeproj/project.pbxproj + carthage build --no-skip-current + cache.directories: + - Carthage + - <<: *carthage + osx_image: xcode10.1 + - <<: *carthage + osx_image: xcode10.2 + + - &test + stage: test + xcode_scheme: PMKHomeKit + xcode_project: PMKHomeKit.xcodeproj + xcode_destination: 'platform=iOS Simulator,OS=12.2,name=iPhone SE' + cache.directories: + - Carthage + before_install: + carthage bootstrap --cache-builds --no-use-binaries + after_success: + bash <(curl -s https://codecov.io/bash); + - <<: *test + xcode_destination: 'platform=tvOS Simulator,OS=12.2,name=Apple TV' diff --git a/Sources/PMKHomeKit/HMAcessoryBrowser+Promise.swift b/Sources/PMKHomeKit/HMAcessoryBrowser+Promise.swift new file mode 100644 index 000000000..7199d5be6 --- /dev/null +++ b/Sources/PMKHomeKit/HMAcessoryBrowser+Promise.swift @@ -0,0 +1,76 @@ +#if canImport(HomeKit) && !os(tvOS) && !os(watchOS) +#if !PMKCocoaPods +import PromiseKit +#endif +import HomeKit + +public enum HMPromiseAccessoryBrowserError: Error { + case noAccessoryFound +} + +public class HMPromiseAccessoryBrowser { + private var proxy: BrowserProxy? + + public func start(scanInterval: ScanInterval) -> Promise<[HMAccessory]> { + proxy = BrowserProxy(scanInterval: scanInterval) + return proxy!.promise + } + + public func stop() { + proxy?.cancel() + } +} + +private class BrowserProxy: PromiseProxy<[HMAccessory]>, HMAccessoryBrowserDelegate { + let browser = HMAccessoryBrowser() + let scanInterval: ScanInterval + + init(scanInterval: ScanInterval) { + self.scanInterval = scanInterval + super.init() + + browser.delegate = self; + browser.startSearchingForNewAccessories() + + //if we have a timeout, set it up + var timeout: TimeInterval? = nil + switch scanInterval { + case .returnAll(let interval): timeout = interval + case .returnFirst(let interval): timeout = interval + } + + if let timeout = timeout { + after(seconds: timeout) + .done { [weak self] () -> Void in + guard let _self = self else { return } + _self.reject(HMPromiseAccessoryBrowserError.noAccessoryFound) + } + } + } + + override func fulfill(_ value: [HMAccessory]) { + browser.stopSearchingForNewAccessories() + super.fulfill(value) + } + + override func reject(_ error: Error ) { + browser.stopSearchingForNewAccessories() + super.reject(error) + } + + override func cancel() { + browser.stopSearchingForNewAccessories() + super.cancel() + } + + /** + HMAccessoryBrowser delegate + */ + func accessoryBrowser(_ browser: HMAccessoryBrowser, didFindNewAccessory accessory: HMAccessory) { + if case .returnFirst = scanInterval { + fulfill([accessory]) + } + } +} + +#endif diff --git a/Sources/PMKHomeKit/HMActionSet+Promise.swift b/Sources/PMKHomeKit/HMActionSet+Promise.swift new file mode 100644 index 000000000..ca14fed9a --- /dev/null +++ b/Sources/PMKHomeKit/HMActionSet+Promise.swift @@ -0,0 +1,24 @@ +#if canImport(HomeKit) && !os(tvOS) && !os(watchOS) +#if !PMKCocoaPods +import PromiseKit +#endif +import HomeKit + +extension HMActionSet { + + @available(iOS 8.0, *) + public func addAction(_ action: HMAction) -> Promise { + return Promise { seal in + self.addAction(action, completionHandler: seal.resolve) + } + } + + @available(iOS 8.0, *) + public func updateName(_ name: String) -> Promise { + return Promise { seal in + self.updateName(name, completionHandler: seal.resolve) + } + } +} + +#endif diff --git a/Sources/PMKHomeKit/HMCharacteristic+Promise.swift b/Sources/PMKHomeKit/HMCharacteristic+Promise.swift new file mode 100644 index 000000000..3649f8296 --- /dev/null +++ b/Sources/PMKHomeKit/HMCharacteristic+Promise.swift @@ -0,0 +1,48 @@ +#if canImport(HomeKit) +#if !PMKCocoaPods +import PromiseKit +#endif +import HomeKit + +public enum AccessoryError: Error { + case incorrectType + case serviceMissing + case characteristicMissing +} + +@available(iOS 8.0, tvOS 10.0, *) +extension HMCharacteristic { + /** + A simple typesafe promise wrapper around readValue + */ + public func read() -> Promise { + return Promise { seal in + self.readValue { error in + if let error = error { seal.reject(error) } + else if let value = self.value as? T { seal.fulfill(value) } + else { seal.reject(AccessoryError.incorrectType) } + } + } + } + /// Because type inference is great... until you can't compile (thanks Swift) + public func readFloat() -> Promise { return read() } + public func readDouble() -> Promise { return read() } + public func readInt() -> Promise { return read() } + public func readString() -> Promise { return read() } + + /** + A simple promise wrapper around writeValue + */ + public func write(_ value: Any?) -> Promise { + return Promise { seal in + self.writeValue(value, completionHandler: seal.resolve) + } + } + /// Explicit is good + public func writeFloat(_ value: Float) -> Promise { return write(value) } + public func writeDouble(_ value: Double) -> Promise { return write(value) } + public func writeInt(_ value: Int) -> Promise { return write(value) } + public func writeString(_ value: String) -> Promise { return write(value) } +} + +#endif diff --git a/Sources/PMKHomeKit/HMEventTrigger+Promise.swift b/Sources/PMKHomeKit/HMEventTrigger+Promise.swift new file mode 100644 index 000000000..fe6c79e9c --- /dev/null +++ b/Sources/PMKHomeKit/HMEventTrigger+Promise.swift @@ -0,0 +1,19 @@ +#if canImport(HomeKit) && !os(tvOS) && !os(watchOS) +#if !PMKCocoaPods +import PromiseKit +#endif +import HomeKit + +@available(iOS 9.0, *) +extension HMEventTrigger { + + @available(iOS 11.0, *) + public func updateExecuteOnce(_ executeOnce: Bool) -> Promise { + return Promise { seal in + self.updateExecuteOnce(executeOnce, completionHandler: seal.resolve) + } + } + +} + +#endif diff --git a/Sources/PMKHomeKit/HMHome+Promise.swift b/Sources/PMKHomeKit/HMHome+Promise.swift new file mode 100644 index 000000000..330f56c93 --- /dev/null +++ b/Sources/PMKHomeKit/HMHome+Promise.swift @@ -0,0 +1,114 @@ +#if canImport(HomeKit) && !os(tvOS) && !os(watchOS) +#if !PMKCocoaPods +import PromiseKit +#endif +import HomeKit + +extension HMHome { + + @available(iOS 8.0, *) + public func updateName(_ name: String) -> Promise { + return Promise { seal in + self.updateName(name, completionHandler: seal.resolve) + } + } + + // MARK: Accessories + + /// Add and setup a new HMAccessory. Displays it's own UI + @available(iOS 11.3, *) + public func addAndSetupAccessories(with payload: HMAccessorySetupPayload) -> Promise<[HMAccessory]> { + return Promise { seal in + self.addAndSetupAccessories(with: payload, completionHandler: seal.resolve) + } + } + + /// Add and setup a new HMAccessory. Displays it's own UI + @available(iOS 10.0, *) + public func addAndSetupAccessories() -> Promise<[HMAccessory]> { + // We need to compare what we have before the action to after to know what is new + let beforeAccessories = self.accessories + let home = self + + return Promise { seal in + self.addAndSetupAccessories { error in + if let error = error { seal.reject(error) } + else { + let newAccessories = home.accessories.filter { beforeAccessories.contains($0) == false } + seal.fulfill(newAccessories) + } + } + } + } + + @available(iOS 8.0, *) + public func addAccessory(_ accessory: HMAccessory) -> Promise { + return Promise { seal in + self.addAccessory(accessory, completionHandler: seal.resolve) + } + } + + @available(iOS 8.0, *) + public func assignAccessory(_ accessory: HMAccessory, to room: HMRoom) -> Promise { + return Promise { seal in + self.assignAccessory(accessory, to: room, completionHandler: seal.resolve) + } + } + + @available(iOS 8.0, *) + public func removeAccessory(_ accessory: HMAccessory) -> Promise { + return Promise { seal in + self.removeAccessory(accessory, completionHandler: seal.resolve) + } + } + + // MARK: Rooms + + @available(iOS 8.0, *) + public func addRoom(withName name: String) -> Promise { + return Promise { seal in + self.addRoom(withName: name, completionHandler: seal.resolve) + } + } + + @available(iOS 8.0, *) + public func removeRoom(_ room: HMRoom) -> Promise { + return Promise { seal in + self.removeRoom(room, completionHandler: seal.resolve) + } + } + + // MARK: Action Sets + + @available(iOS 8.0, *) + public func addActionSet(withName name: String) -> Promise { + return Promise { seal in + self.addActionSet(withName: name, completionHandler: seal.resolve) + } + } + + @available(iOS 8.0, *) + public func removeActionSet(_ actionSet: HMActionSet) -> Promise { + return Promise { seal in + self.removeActionSet(actionSet, completionHandler: seal.resolve) + } + } + + // MARK: Triggers + + @available(iOS 8.0, *) + public func addTrigger(_ trigger: HMTrigger) -> Promise { + return Promise { seal in + self.addTrigger(trigger, completionHandler: seal.resolve) + } + } + + @available(iOS 8.0, *) + public func removeTrigger(_ trigger: HMTrigger) -> Promise { + return Promise { seal in + self.removeTrigger(trigger, completionHandler: seal.resolve) + } + } +} + +#endif diff --git a/Sources/PMKHomeKit/HMHomeManager+Promise.swift b/Sources/PMKHomeKit/HMHomeManager+Promise.swift new file mode 100644 index 000000000..673a5795e --- /dev/null +++ b/Sources/PMKHomeKit/HMHomeManager+Promise.swift @@ -0,0 +1,64 @@ +#if canImport(HomeKit) +#if !PMKCocoaPods +import PromiseKit +#endif +import HomeKit + +@available(iOS 8.0, tvOS 10.0, *) +public enum HomeKitError: Error { + case permissionDeined +} + +@available(iOS 8.0, tvOS 10.0, *) +extension HMHomeManager { + public func homes() -> Promise<[HMHome]> { + return HMHomeManagerProxy().promise + } + + #if !os(tvOS) && !os(watchOS) + + @available(iOS 8.0, *) + public func addHome(withName name: String) -> Promise { + return Promise { seal in + self.addHome(withName: name, completionHandler: seal.resolve) + } + } + + @available(iOS 8.0, *) + public func removeHome(_ home: HMHome) -> Promise { + return Promise { seal in + self.removeHome(home, completionHandler: seal.resolve) + } + } + + @available(iOS 8.0, *) + public func updatePrimaryHome(_ home: HMHome) -> Promise { + return Promise { seal in + self.updatePrimaryHome(home, completionHandler: seal.resolve) + } + } + + #endif +} + +@available(iOS 8.0, tvOS 10.0, *) +internal class HMHomeManagerProxy: PromiseProxy<[HMHome]>, HMHomeManagerDelegate { + + fileprivate let manager: HMHomeManager + + override init() { + self.manager = HMHomeManager() + super.init() + self.manager.delegate = self + + DispatchQueue.main.asyncAfter(deadline: .now() + 20.0) { [weak self] in + self?.reject(HomeKitError.permissionDeined) + } + } + + func homeManagerDidUpdateHomes(_ manager: HMHomeManager) { + fulfill(manager.homes) + } +} + +#endif diff --git a/Sources/PMKHomeKit/HMTrigger+Promise.swift b/Sources/PMKHomeKit/HMTrigger+Promise.swift new file mode 100644 index 000000000..c56cef97b --- /dev/null +++ b/Sources/PMKHomeKit/HMTrigger+Promise.swift @@ -0,0 +1,39 @@ +#if canImport(HomeKit) && !os(tvOS) && !os(watchOS) +#if !PMKCocoaPods +import PromiseKit +#endif +import HomeKit + +extension HMTrigger { + + @available(iOS 8.0, *) + public func updateName(_ name: String) -> Promise { + return Promise { seal in + self.updateName(name, completionHandler: seal.resolve) + } + } + + @available(iOS 8.0, *) + public func enable(_ enabled: Bool) -> Promise { + return Promise { seal in + self.enable(enabled, completionHandler: seal.resolve) + } + } + + @available(iOS 8.0, *) + public func addActionSet(_ actionSet: HMActionSet) -> Promise { + return Promise { seal in + self.addActionSet(actionSet, completionHandler: seal.resolve) + } + } + + @available(iOS 8.0, *) + public func removeActionSet(_ actionSet: HMActionSet) -> Promise { + return Promise { seal in + self.removeActionSet(actionSet, completionHandler: seal.resolve) + } + } + +} + +#endif diff --git a/Sources/PMKHomeKit/Utils.swift b/Sources/PMKHomeKit/Utils.swift new file mode 100644 index 000000000..f7d572251 --- /dev/null +++ b/Sources/PMKHomeKit/Utils.swift @@ -0,0 +1,46 @@ +import Foundation +#if !PMKCocoaPods +import PromiseKit +#endif + +/** + Commonly used functionality when promisifying a delegate pattern +*/ +internal class PromiseProxy: NSObject { + internal let (promise, seal) = Promise.pending(); + + private var retainCycle: PromiseProxy? + + override init() { + super.init() + // Create a retain cycle + self.retainCycle = self + // And ensure we break it when the promise is resolved + _ = promise.ensure { self.retainCycle = nil } + } + + /// These functions ensure we only resolve the promise once + internal func fulfill(_ value: T) { + guard self.promise.isResolved == false else { return } + seal.fulfill(value) + } + internal func reject(_ error: Error) { + guard self.promise.isResolved == false else { return } + seal.reject(error) + } + + /// Cancel helper + internal func cancel() { + self.reject(PMKError.cancelled) + } +} + +/** + Different ways to scan. +*/ +public enum ScanInterval { + // Return after our first item with an optional time limit + case returnFirst(timeout: TimeInterval?) + // Scan for this duration before returning all + case returnAll(interval: TimeInterval) +} diff --git a/Sources/PMKMapKit/.gitignore b/Sources/PMKMapKit/.gitignore new file mode 100644 index 000000000..f5554ff63 --- /dev/null +++ b/Sources/PMKMapKit/.gitignore @@ -0,0 +1,5 @@ +xcuserdata +*.xcscmblueprint +/Carthage +/.build +.DS_Store \ No newline at end of file diff --git a/Sources/PMKMapKit/.travis.yml b/Sources/PMKMapKit/.travis.yml new file mode 100644 index 000000000..b904ead5f --- /dev/null +++ b/Sources/PMKMapKit/.travis.yml @@ -0,0 +1,80 @@ +os: osx +language: swift +osx_image: xcode10.2 + +branches: + only: + - master +stages: + - lint + - carthage + - test +jobs: + include: + - &pod + stage: lint + osx_image: xcode8.3 + env: SWIFT=3.1 + before_install: + gem install cocoapods --prerelease --version 1.7.0.beta.3 + install: + carthage bootstrap --no-build PromiseKit + script: | + cd Carthage/Checkouts/PromiseKit + mv .github/PromiseKit.podspec . + rm -rf Extensions/MapKit/Sources + cp -R ../../../Sources Extensions/MapKit + pod lib lint --subspec=PromiseKit/MapKit --fail-fast --swift-version=$SWIFT + - <<: *pod + osx_image: xcode9.2 + env: SWIFT=3.2 + - <<: *pod + osx_image: xcode9.4 + env: SWIFT=3.3 + - <<: *pod + osx_image: xcode10.1 + env: SWIFT=3.4 + - <<: *pod + osx_image: xcode9.2 + env: SWIFT=4.0 + - <<: *pod + osx_image: xcode9.4 + env: SWIFT=4.1 + - <<: *pod + osx_image: xcode10.1 + env: SWIFT=4.2 + - <<: *pod + osx_image: xcode10.2 + env: SWIFT=5.0 + + - &carthage + stage: carthage + osx_image: xcode9.2 + script: | + carthage bootstrap --cache-builds + sed -i '' "s/SWIFT_TREAT_WARNINGS_AS_ERRORS = NO;/SWIFT_TREAT_WARNINGS_AS_ERRORS = YES;/" *.xcodeproj/project.pbxproj + carthage build --no-skip-current + cache: + directories: + - Carthage + - <<: *carthage + osx_image: xcode9.4 + - <<: *carthage + osx_image: xcode10.1 + - <<: *carthage + osx_image: xcode10.2 + + - &test + stage: test + xcode_scheme: PMKMapKit + xcode_project: PMKMapKit.xcodeproj + xcode_destination: 'platform=macOS' + cache: + directories: + - Carthage + before_install: + carthage bootstrap --cache-builds --no-use-binaries + - <<: *test + xcode_destination: 'platform=iOS Simulator,OS=12.2,name=iPhone SE' + - <<: *test + xcode_destination: 'platform=tvOS Simulator,OS=12.2,name=Apple TV' diff --git a/Sources/PMKMapKit/MKDirections+Promise.swift b/Sources/PMKMapKit/MKDirections+Promise.swift new file mode 100644 index 000000000..e70b0e514 --- /dev/null +++ b/Sources/PMKMapKit/MKDirections+Promise.swift @@ -0,0 +1,23 @@ +#if canImport(MapKit) && !os(watchOS) + +#if !PMKCocoaPods +import PromiseKit +#endif +import MapKit + +/** + import PMKMapKit +*/ +public extension MKDirections { + /// Begins calculating the requested route information asynchronously. + func calculate() -> Promise { + return Promise { calculate(completionHandler: $0.resolve) } + } + + /// Begins calculating the requested travel-time information asynchronously. + func calculateETA() -> Promise { + return Promise { calculateETA(completionHandler: $0.resolve) } + } +} + +#endif diff --git a/Sources/PMKMapKit/MKMapSnapshotter+Promise.swift b/Sources/PMKMapKit/MKMapSnapshotter+Promise.swift new file mode 100644 index 000000000..c2ca31df9 --- /dev/null +++ b/Sources/PMKMapKit/MKMapSnapshotter+Promise.swift @@ -0,0 +1,18 @@ +#if canImport(MapKit) && !os(watchOS) + +#if !PMKCocoaPods +import PromiseKit +#endif +import MapKit + +/** + import PMKMapKit +*/ +extension MKMapSnapshotter { + /// Starts generating the snapshot using the options set in this object. + public func start() -> Promise { + return Promise { start(completionHandler: $0.resolve) } + } +} + +#endif diff --git a/Sources/PMKPhotos/.gitignore b/Sources/PMKPhotos/.gitignore new file mode 100644 index 000000000..bec9c1741 --- /dev/null +++ b/Sources/PMKPhotos/.gitignore @@ -0,0 +1,5 @@ +*.xcodeproj/**/xcuserdata/ +*.xcscmblueprint +/Carthage +/.build +.DS_Store \ No newline at end of file diff --git a/Sources/PMKPhotos/.travis.yml b/Sources/PMKPhotos/.travis.yml new file mode 100644 index 000000000..b33720d9e --- /dev/null +++ b/Sources/PMKPhotos/.travis.yml @@ -0,0 +1,73 @@ +os: osx +language: swift +osx_image: xcode10.2 + +branches: + only: + - master +stages: + - lint + - carthage + - test +jobs: + include: + - &pod + stage: lint + osx_image: xcode9.2 + env: SWIFT=3.2 + before_install: + gem install cocoapods --prerelease --version 1.7.0.beta.3 + install: + carthage bootstrap --no-build PromiseKit + script: | + cd Carthage/Checkouts/PromiseKit + mv .github/PromiseKit.podspec . + rm -rf Extensions/Photos/Sources + cp -R ../../../Sources Extensions/Photos + pod lib lint --subspec=PromiseKit/Photos --fail-fast --swift-version=$SWIFT + - <<: *pod + osx_image: xcode9.4 + env: SWIFT=3.3 + - <<: *pod + osx_image: xcode10.1 + env: SWIFT=3.4 + - <<: *pod + osx_image: xcode9.2 + env: SWIFT=4.0 + - <<: *pod + osx_image: xcode9.4 + env: SWIFT=4.1 + - <<: *pod + osx_image: xcode10.1 + env: SWIFT=4.2 + - <<: *pod + osx_image: xcode10.2 + env: SWIFT=5.0 + + - &carthage + stage: carthage + osx_image: xcode9.2 + script: | + carthage bootstrap --cache-builds + sed -i '' "s/SWIFT_TREAT_WARNINGS_AS_ERRORS = NO;/SWIFT_TREAT_WARNINGS_AS_ERRORS = YES;/" *.xcodeproj/project.pbxproj + carthage build --no-skip-current + cache.directories: + - Carthage + - <<: *carthage + osx_image: xcode9.4 + - <<: *carthage + osx_image: xcode10.1 + - <<: *carthage + osx_image: xcode10.2 + + - &test + stage: test + xcode_scheme: PMKPhotos + xcode_project: PMKPhotos.xcodeproj + xcode_destination: 'platform=iOS Simulator,OS=12.2,name=iPhone SE' + cache.directories: + - Carthage + before_install: + carthage bootstrap --cache-builds --no-use-binaries + - <<: *test + xcode_destination: 'platform=tvOS Simulator,OS=12.2,name=Apple TV' diff --git a/Sources/PMKPhotos/PHPhotoLibrary+Promise.swift b/Sources/PMKPhotos/PHPhotoLibrary+Promise.swift new file mode 100644 index 000000000..1fe697655 --- /dev/null +++ b/Sources/PMKPhotos/PHPhotoLibrary+Promise.swift @@ -0,0 +1,22 @@ +#if canImport(Photos) + +import Photos.PHPhotoLibrary +#if !PMKCocoaPods +import PromiseKit +#endif + +/** + import PMKPhotos +*/ +@available(macOS 10.13, *) +extension PHPhotoLibrary { + /** + - Returns: A promise that fulfills with the user’s authorization + - Note: This promise cannot reject. + */ + public class func requestAuthorization() -> Guarantee { + return Guarantee(resolver: PHPhotoLibrary.requestAuthorization) + } +} + +#endif diff --git a/Sources/PMKStoreKit/.gitignore b/Sources/PMKStoreKit/.gitignore new file mode 100644 index 000000000..bec9c1741 --- /dev/null +++ b/Sources/PMKStoreKit/.gitignore @@ -0,0 +1,5 @@ +*.xcodeproj/**/xcuserdata/ +*.xcscmblueprint +/Carthage +/.build +.DS_Store \ No newline at end of file diff --git a/Sources/PMKStoreKit/.travis.yml b/Sources/PMKStoreKit/.travis.yml new file mode 100644 index 000000000..76450b19f --- /dev/null +++ b/Sources/PMKStoreKit/.travis.yml @@ -0,0 +1,91 @@ +os: osx +language: swift +osx_image: xcode10.2 + +branches: + only: + - master +stages: + - lint + - carthage + - swiftPM + - test +jobs: + include: + - &pod + stage: lint + osx_image: xcode8.3 + env: SWIFT=3.1 + before_install: + gem install cocoapods --prerelease --version 1.7.0.beta.3 + install: + carthage bootstrap --no-build PromiseKit + script: | + cd Carthage/Checkouts/PromiseKit + mv .github/PromiseKit.podspec . + rm -rf Extensions/StoreKit/Sources + cp -R ../../../Sources Extensions/StoreKit + pod lib lint --subspec=PromiseKit/StoreKit --fail-fast --swift-version=$SWIFT + - <<: *pod + osx_image: xcode9.2 + env: SWIFT=3.2 + - <<: *pod + osx_image: xcode9.4 + env: SWIFT=3.3 + - <<: *pod + osx_image: xcode10.1 + env: SWIFT=3.4 + - <<: *pod + osx_image: xcode9.2 + env: SWIFT=4.0 + - <<: *pod + osx_image: xcode9.4 + env: SWIFT=4.1 + - <<: *pod + osx_image: xcode10.1 + env: SWIFT=4.2 + - <<: *pod + osx_image: xcode10.2 + env: SWIFT=5.0 + + - &carthage + stage: carthage + osx_image: xcode9.2 + script: | + carthage bootstrap --cache-builds + sed -i '' "s/SWIFT_TREAT_WARNINGS_AS_ERRORS = NO;/SWIFT_TREAT_WARNINGS_AS_ERRORS = YES;/" *.xcodeproj/project.pbxproj + carthage build --no-skip-current + cache: + directories: + - Carthage + - <<: *carthage + osx_image: xcode9.4 + - <<: *carthage + osx_image: xcode10.1 + - <<: *carthage + osx_image: xcode10.2 + + - &swiftpm + stage: swiftpm + osx_image: xcode9.2 + script: swift build -Xswiftc -target -Xswiftc x86_64-apple-macosx10.12 + - <<: *swiftpm + osx_image: xcode9.4 + - <<: *swiftpm + osx_image: xcode10.1 + - <<: *swiftpm + osx_image: xcode10.2 + + - &test + stage: test + xcode_scheme: PMKStoreKit + xcode_project: PMKStoreKit.xcodeproj + xcode_destination: 'platform=macOS' + cache.directories: + - Carthage + before_install: + carthage bootstrap --cache-builds --no-use-binaries + - <<: *test + xcode_destination: 'OS=12.2,name=iPhone SE' + - <<: *test + xcode_destination: 'OS=12.2,name=Apple TV' diff --git a/Sources/PMKStoreKit/SKPayment+Promise.swift b/Sources/PMKStoreKit/SKPayment+Promise.swift new file mode 100644 index 000000000..2fde33d13 --- /dev/null +++ b/Sources/PMKStoreKit/SKPayment+Promise.swift @@ -0,0 +1,51 @@ +#if canImport(StoreKit) + +#if !PMKCocoaPods +import PromiseKit +#endif +import StoreKit + +@available(watchOS 6.2, *) +extension SKPayment { + public func promise() -> Promise { + return PaymentObserver(payment: self).promise + } +} + +@available(watchOS 6.2, *) +private class PaymentObserver: NSObject, SKPaymentTransactionObserver { + let (promise, seal) = Promise.pending() + let payment: SKPayment + var retainCycle: PaymentObserver? + + init(payment: SKPayment) { + self.payment = payment + super.init() + SKPaymentQueue.default().add(self) + SKPaymentQueue.default().add(payment) + retainCycle = self + } + + func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) { + guard let transaction = transactions.first(where: { $0.payment.productIdentifier == payment.productIdentifier }) else { + return + } + switch transaction.transactionState { + case .purchased, .restored: + queue.finishTransaction(transaction) + seal.fulfill(transaction) + queue.remove(self) + retainCycle = nil + case .failed: + let error = transaction.error ?? PMKError.cancelled + queue.finishTransaction(transaction) + seal.reject(error) + queue.remove(self) + retainCycle = nil + default: + break + } + } +} + +#endif diff --git a/Sources/PMKStoreKit/SKPaymentQueue+Promise.swift b/Sources/PMKStoreKit/SKPaymentQueue+Promise.swift new file mode 100644 index 000000000..41b6df90a --- /dev/null +++ b/Sources/PMKStoreKit/SKPaymentQueue+Promise.swift @@ -0,0 +1,61 @@ +#if canImport(StoreKit) + +#if !PMKCocoaPods +import PromiseKit +#endif +import StoreKit + +@available(watchOS 6.2, *) +public extension SKPaymentQueue { + func restoreCompletedTransactions(_: PMKNamespacer) -> Promise<[SKPaymentTransaction]> { + return PaymentObserver(self).promise + } + + func restoreCompletedTransactions(_: PMKNamespacer, withApplicationUsername username: String?) -> Promise<[SKPaymentTransaction]> { + return PaymentObserver(self, withApplicationUsername: true, userName: username).promise + } +} + +@available(watchOS 6.2, *) +private class PaymentObserver: NSObject, SKPaymentTransactionObserver { + let (promise, seal) = Promise<[SKPaymentTransaction]>.pending() + var retainCycle: PaymentObserver? + var finishedTransactions = [SKPaymentTransaction]() + + //TODO:PMK7: this is weird, just have a `String?` parameter + init(_ paymentQueue: SKPaymentQueue, withApplicationUsername: Bool = false, userName: String? = nil) { + super.init() + paymentQueue.add(self) + withApplicationUsername ? + paymentQueue.restoreCompletedTransactions() : + paymentQueue.restoreCompletedTransactions(withApplicationUsername: userName) + retainCycle = self + } + + func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) { + for transaction in transactions where transaction.transactionState == .restored { + finishedTransactions.append(transaction) + queue.finishTransaction(transaction) + } + } + + func paymentQueueRestoreCompletedTransactionsFinished(_ queue: SKPaymentQueue) { + resolve(queue, nil) + } + + func paymentQueue(_ queue: SKPaymentQueue, restoreCompletedTransactionsFailedWithError error: Error) { + resolve(queue, error) + } + + func resolve(_ queue: SKPaymentQueue, _ error: Error?) { + if let error = error { + seal.reject(error) + } else { + seal.fulfill(finishedTransactions) + } + queue.remove(self) + retainCycle = nil + } +} + +#endif diff --git a/Sources/PMKStoreKit/SKProductsRequest+Promise.swift b/Sources/PMKStoreKit/SKProductsRequest+Promise.swift new file mode 100644 index 000000000..0404203e1 --- /dev/null +++ b/Sources/PMKStoreKit/SKProductsRequest+Promise.swift @@ -0,0 +1,57 @@ +#if canImport(StoreKit) + +#if !PMKCocoaPods +import PromiseKit +#endif +import StoreKit + +/** + To import the `SKRequest` category: + + use_frameworks! + pod "PromiseKit/StoreKit" + + And then in your sources: + + import PromiseKit +*/ +@available(watchOS 6.2, *) +extension SKProductsRequest { + /** + Sends the request to the Apple App Store. + + - Returns: A promise that fulfills if the request succeeds. + */ + public func start(_: PMKNamespacer) -> Promise { + let proxy = SKDelegate() + delegate = proxy + proxy.retainCycle = proxy + start() + return proxy.promise + } +} + +@available(watchOS 6.2, *) +fileprivate class SKDelegate: NSObject, SKProductsRequestDelegate { + let (promise, seal) = Promise.pending() + var retainCycle: SKDelegate? + + @objc fileprivate func request(_ request: SKRequest, didFailWithError error: Error) { + seal.reject(error) + retainCycle = nil + } + + @objc fileprivate func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) { + seal.fulfill(response) + retainCycle = nil + } +} + +// perhaps one day Apple will actually make their errors into Errors… +//extension SKError: CancellableError { +// public var isCancelled: Bool { +// return true +// } +//} + +#endif diff --git a/Sources/PMKStoreKit/SKReceiptRefreshRequest+Promise.swift b/Sources/PMKStoreKit/SKReceiptRefreshRequest+Promise.swift new file mode 100644 index 000000000..5cb1ccc81 --- /dev/null +++ b/Sources/PMKStoreKit/SKReceiptRefreshRequest+Promise.swift @@ -0,0 +1,41 @@ +#if canImport(StoreKit) + +#if !PMKCocoaPods +import PromiseKit +#endif +import StoreKit + +@available(watchOS 6.2, *) +extension SKReceiptRefreshRequest { + public func promise() -> Promise { + return ReceiptRefreshObserver(request: self).promise + } +} + +@available(watchOS 6.2, *) +private class ReceiptRefreshObserver: NSObject, SKRequestDelegate { + let (promise, seal) = Promise.pending() + let request: SKReceiptRefreshRequest + var retainCycle: ReceiptRefreshObserver? + + init(request: SKReceiptRefreshRequest) { + self.request = request + super.init() + request.delegate = self + request.start() + retainCycle = self + } + + + func requestDidFinish(_: SKRequest) { + seal.fulfill(request) + retainCycle = nil + } + + func request(_: SKRequest, didFailWithError error: Error) { + seal.reject(error) + retainCycle = nil + } +} + +#endif diff --git a/Sources/PromiseKit.h b/Sources/PromiseKit.h deleted file mode 100644 index c30d9376a..000000000 --- a/Sources/PromiseKit.h +++ /dev/null @@ -1,7 +0,0 @@ -#import -#import - -#import // `FOUNDATION_EXPORT` - -FOUNDATION_EXPORT double PromiseKitVersionNumber; -FOUNDATION_EXPORT const unsigned char PromiseKitVersionString[]; diff --git a/Sources/Box.swift b/Sources/PromiseKit/Box.swift similarity index 85% rename from Sources/Box.swift rename to Sources/PromiseKit/Box.swift index 43cd3d1b0..7b53a9e1c 100644 --- a/Sources/Box.swift +++ b/Sources/PromiseKit/Box.swift @@ -82,20 +82,3 @@ class EmptyBox: Box { } } } - - -extension Optional where Wrapped: DispatchQueue { - @inline(__always) - func async(flags: DispatchWorkItemFlags?, _ body: @escaping() -> Void) { - switch self { - case .none: - body() - case .some(let q): - if let flags = flags { - q.async(flags: flags, execute: body) - } else { - q.async(execute: body) - } - } - } -} diff --git a/Sources/PromiseKit/Cancellation/CancelContext.swift b/Sources/PromiseKit/Cancellation/CancelContext.swift new file mode 100644 index 000000000..2e9ae677d --- /dev/null +++ b/Sources/PromiseKit/Cancellation/CancelContext.swift @@ -0,0 +1,257 @@ +import Dispatch +import Foundation + +/** + Keeps track of all promises in a promise chain with pending or currently running tasks, and cancels them all when `cancel` is called. + */ +public class CancelContext: Hashable { + public static func == (lhs: CancelContext, rhs: CancelContext) -> Bool { + return lhs === rhs + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(ObjectIdentifier(self)) + } + + // Create a barrier queue that is used as a read/write lock for the CancelContext + // For reads: barrier.sync { } + // For writes: barrier.sync(flags: .barrier) { } + private let barrier = DispatchQueue(label: "org.promisekit.barrier.cancel", attributes: .concurrent) + + private var cancelItems = [CancelItem]() + private var cancelItemSet = Set() + + /** + Cancel all members of the promise chain and their associated asynchronous operations. + + - Parameter error: Specifies the cancellation error to use for the cancel operation, defaults to `PMKError.cancelled` + */ + public func cancel(with error: Error = PMKError.cancelled) { + self.cancel(with: error, visited: Set()) + } + + func cancel(with error: Error = PMKError.cancelled, visited: Set) { + var items: [CancelItem]! + barrier.sync(flags: .barrier) { + internalCancelledError = error + items = cancelItems + } + + for item in items { + item.cancel(with: error, visited: visited) + } + } + + /** + True if all members of the promise chain have been successfully cancelled, false otherwise. + */ + public var isCancelled: Bool { + var items: [CancelItem]! + barrier.sync { + items = cancelItems + } + + for item in items where !item.isCancelled { + return false + } + return true + } + + /** + True if `cancel` has been called on the CancelContext associated with this promise, false otherwise. `cancelAttempted` will be true if `cancel` is called on any promise in the chain. + */ + public var cancelAttempted: Bool { + return cancelledError != nil + } + + private var internalCancelledError: Error? + + /** + The cancellation error initialized when the promise is cancelled, or `nil` if not cancelled. + */ + public private(set) var cancelledError: Error? { + get { + var err: Error! + barrier.sync { + err = internalCancelledError + } + return err + } + + set { + barrier.sync(flags: .barrier) { + internalCancelledError = newValue + } + } + } + + func append(cancellable: Cancellable?, reject: ((Error) -> Void)?, thenable: Z) { + if cancellable == nil && reject == nil { + return + } + let item = CancelItem(cancellable: cancellable, reject: reject) + + var error: Error? + barrier.sync(flags: .barrier) { + error = internalCancelledError + cancelItems.append(item) + cancelItemSet.insert(item) + thenable.cancelItemList.append(item) + } + + if error != nil { + item.cancel(with: error!) + } + } + + func append(context childContext: CancelContext, thenable: Z) { + guard childContext !== self else { + return + } + let item = CancelItem(context: childContext) + + var error: Error? + barrier.sync(flags: .barrier) { + error = internalCancelledError + cancelItems.append(item) + cancelItemSet.insert(item) + thenable.cancelItemList.append(item) + } + + crossCancel(childContext: childContext, parentCancelledError: error) + } + + func append(context childContext: CancelContext, thenableCancelItemList: CancelItemList) { + guard childContext !== self else { + return + } + let item = CancelItem(context: childContext) + + var error: Error? + barrier.sync(flags: .barrier) { + error = internalCancelledError + cancelItems.append(item) + cancelItemSet.insert(item) + thenableCancelItemList.append(item) + } + + crossCancel(childContext: childContext, parentCancelledError: error) + } + + private func crossCancel(childContext: CancelContext, parentCancelledError: Error?) { + let parentError = parentCancelledError + let childError = childContext.cancelledError + + if parentError != nil { + if childError == nil { + childContext.cancel(with: parentError!) + } + } else if childError != nil { + if parentError == nil { + cancel(with: childError!) + } + } + } + + func recover() { + cancelledError = nil + } + + func removeItems(_ list: CancelItemList, clearList: Bool) -> Error? { + var error: Error? + barrier.sync(flags: .barrier) { + error = internalCancelledError + if error == nil && list.items.count != 0 { + var currentIndex = 1 + // The `list` parameter should match a block of items in the cancelItemList, remove them from the cancelItemList + // in one operation for efficiency + if cancelItemSet.remove(list.items[0]) != nil { + let removeIndex = cancelItems.firstIndex(of: list.items[0])! + while currentIndex < list.items.count { + let item = list.items[currentIndex] + if item != cancelItems[removeIndex + currentIndex] { + break + } + cancelItemSet.remove(item) + currentIndex += 1 + } + cancelItems.removeSubrange(removeIndex..<(removeIndex+currentIndex)) + } + + // Remove whatever falls outside of the block + while currentIndex < list.items.count { + let item = list.items[currentIndex] + if cancelItemSet.remove(item) != nil { + cancelItems.remove(at: cancelItems.firstIndex(of: item)!) + } + currentIndex += 1 + } + + if clearList { + list.removeAll() + } + } + } + return error + } +} + +/// Tracks the cancel items for a CancellablePromise. These items are removed from the associated CancelContext when the promise resolves. +public class CancelItemList { + fileprivate var items: [CancelItem] + + init() { + self.items = [] + } + + fileprivate func append(_ item: CancelItem) { + items.append(item) + } + + fileprivate func removeAll() { + items.removeAll() + } +} + +fileprivate class CancelItem: Hashable { + static func == (lhs: CancelItem, rhs: CancelItem) -> Bool { + return lhs === rhs + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(ObjectIdentifier(self)) + } + + let cancellable: Cancellable? + var reject: ((Error) -> Void)? + weak var context: CancelContext? + var cancelAttempted = false + + init(cancellable: Cancellable?, reject: ((Error) -> Void)?) { + self.cancellable = cancellable + self.reject = reject + } + + init(context: CancelContext) { + self.cancellable = nil + self.context = context + } + + func cancel(with error: Error, visited: Set? = nil) { + cancelAttempted = true + + cancellable?.cancel() + reject?(error) + + if var v = visited, let c = context { + if !v.contains(c) { + v.insert(c) + c.cancel(with: error, visited: v) + } + } + } + + var isCancelled: Bool { + return cancellable?.isCancelled ?? cancelAttempted + } +} diff --git a/Sources/PromiseKit/Cancellation/Cancellable.swift b/Sources/PromiseKit/Cancellation/Cancellable.swift new file mode 100644 index 000000000..28b57f5a4 --- /dev/null +++ b/Sources/PromiseKit/Cancellation/Cancellable.swift @@ -0,0 +1,12 @@ +import Dispatch + +/** + Use this protocol to define cancellable tasks for CancellablePromise. + */ +public protocol Cancellable { + /// Cancel the associated task + func cancel() + + /// `true` if the task was successfully cancelled, `false` otherwise + var isCancelled: Bool { get } +} diff --git a/Sources/PromiseKit/Cancellation/CancellableCatchable.swift b/Sources/PromiseKit/Cancellation/CancellableCatchable.swift new file mode 100644 index 000000000..e03b1cf01 --- /dev/null +++ b/Sources/PromiseKit/Cancellation/CancellableCatchable.swift @@ -0,0 +1,628 @@ +import Dispatch + +/// Provides `catch` and `recover` to your object that conforms to `CancellableThenable` +public protocol CancellableCatchMixin: CancellableThenable { + /// Type of the delegate `catchable` + associatedtype C: CatchMixin + + /// Delegate `catchable` for this CancellablePromise + var catchable: C { get } +} + +public extension CancellableCatchMixin { + /** + The provided closure executes when this cancellable promise rejects. + + Rejecting a promise cascades: rejecting all subsequent promises (unless + recover is invoked) thus you will typically place your catch at the end + of a chain. Often utility promises will not have a catch, instead + delegating the error handling to the caller. + + - Parameter on: The dispatcher that executes the provided closure. + - Parameter policy: The default policy does not execute your handler for cancellation errors. + - Parameter execute: The handler to execute if this promise is rejected. + - Returns: A promise finalizer. + - SeeAlso: [Cancellation](https://github.com/mxcl/PromiseKit/blob/master/Documentation/CommonPatterns.md#cancellation) + */ + @discardableResult + func `catch`(on: Dispatcher = conf.D.return, policy: CatchPolicy = conf.catchPolicy, _ body: @escaping(Error) -> Void) -> CancellableFinalizer { + return CancellableFinalizer(self.catchable.catch(on: on, policy: policy, body), cancel: self.cancelContext) + } + + /** + The provided closure executes when this cancellable promise rejects with the specific error passed in. + A final `catch` is still required at the end of the chain. + + Rejecting a promise cascades: rejecting all subsequent promises (unless + recover is invoked) thus you will typically place your catch at the end + of a chain. Often utility promises will not have a catch, instead + delegating the error handling to the caller. + + - Parameter only: The specific error to be caught and handled. + - Parameter on: The queue to which the provided closure dispatches. + - Parameter execute: The handler to execute if this promise is rejected with the provided error. + - Note: Since this method handles only specific errors, supplying a `CatchPolicy` is unsupported. You can instead specify e.g. your cancellable error. + - SeeAlso: [Cancellation](https://github.com/mxcl/PromiseKit/blob/master/Documentation/CommonPatterns.md#cancellation) + */ + func `catch`(only: E, on: Dispatcher = conf.D.return, _ body: @escaping(E) -> Void) -> CancellableCascadingFinalizer where E: Equatable { + return CancellableCascadingFinalizer(self.catchable.catch(only: only, on: on, body), cancel: self.cancelContext) + } + + /** + The provided closure executes when this cancellable promise rejects with an error of the type passed in. + A final `catch` is still required at the end of the chain. + + Rejecting a promise cascades: rejecting all subsequent promises (unless + recover is invoked) thus you will typically place your catch at the end + of a chain. Often utility promises will not have a catch, instead + delegating the error handling to the caller. + + - Parameter only: The error type to be caught and handled. + - Parameter on: The queue to which the provided closure dispatches. + - Parameter execute: The handler to execute if this promise is rejected with the provided error type. + - SeeAlso: [Cancellation](https://github.com/mxcl/PromiseKit/blob/master/Documentation/CommonPatterns.md#cancellation) + */ + func `catch`(only: E.Type, on: Dispatcher = conf.D.return, policy: CatchPolicy = conf.catchPolicy, _ body: @escaping(E) -> Void) -> CancellableCascadingFinalizer { + return CancellableCascadingFinalizer(self.catchable.catch(only: only, on: on, policy: policy, body), cancel: self.cancelContext) + } +} + +public class CancelContextFinalizer { + /// The CancelContext associated with this finalizer + public let cancelContext: CancelContext + + init(cancel: CancelContext) { + self.cancelContext = cancel + } + + /** + Cancel all members of the promise chain and their associated asynchronous operations. + + - Parameter error: Specifies the cancellation error to use for the cancel operation, defaults to `PMKError.cancelled` + */ + public func cancel(with error: Error = PMKError.cancelled) { + cancelContext.cancel(with: error) + } + + /** + True if all members of the promise chain have been successfully cancelled, false otherwise. + */ + public var isCancelled: Bool { + return cancelContext.isCancelled + } + + /** + True if `cancel` has been called on the CancelContext associated with this promise, false otherwise. `cancelAttempted` will be true if `cancel` is called on any promise in the chain. + */ + public var cancelAttempted: Bool { + return cancelContext.cancelAttempted + } + + /** + The cancellation error generated when the promise is cancelled, or `nil` if not cancelled. + */ + public var cancelledError: Error? { + return cancelContext.cancelledError + } +} + +/** + Cancellable finalizer returned from `catch`. Use `finally` to specify a code block that executes when the promise chain resolves. + */ +public class CancellableFinalizer: CancelContextFinalizer { + let pmkFinalizer: PMKFinalizer + + init(_ pmkFinalizer: PMKFinalizer, cancel: CancelContext) { + self.pmkFinalizer = pmkFinalizer + super.init(cancel: cancel) + } + + /// `finally` is the same as `ensure`, but it is not chainable + @discardableResult + public func finally(on: Dispatcher = conf.D.return, _ body: @escaping () -> Void) -> CancelContext { + pmkFinalizer.finally(on: on, body) + return cancelContext + } +} + +public class CancellableCascadingFinalizer: CancelContextFinalizer { + let pmkCascadingFinalizer: PMKCascadingFinalizer + + init(_ pmkCascadingFinalizer: PMKCascadingFinalizer, cancel: CancelContext) { + self.pmkCascadingFinalizer = pmkCascadingFinalizer + super.init(cancel: cancel) + } + + /** + The provided closure executes when this promise rejects. + + Rejecting a promise cascades: rejecting all subsequent promises (unless + recover is invoked) thus you will typically place your catch at the end + of a chain. Often utility promises will not have a catch, instead + delegating the error handling to the caller. + + - Parameter on: The queue to which the provided closure dispatches. + - Parameter policy: The default policy does not execute your handler for cancellation errors. + - Parameter execute: The handler to execute if this promise is rejected. + - Returns: A promise finalizer. + - SeeAlso: [Cancellation](https://github.com/mxcl/PromiseKit/blob/master/Documentation/CommonPatterns.md#cancellation) + */ + @discardableResult + public func `catch`(on: Dispatcher = conf.D.return, policy: CatchPolicy = conf.catchPolicy, _ body: @escaping(Error) -> Void) -> CancellableFinalizer { + return CancellableFinalizer(pmkCascadingFinalizer.catch(on: on, policy: policy, body), cancel: cancelContext) + } + + /** + The provided closure executes when this promise rejects with the specific error passed in. A final `catch` is still required at the end of the chain. + + Rejecting a promise cascades: rejecting all subsequent promises (unless + recover is invoked) thus you will typically place your catch at the end + of a chain. Often utility promises will not have a catch, instead + delegating the error handling to the caller. + + - Parameter only: The specific error to be caught and handled. + - Parameter on: The queue to which the provided closure dispatches. + - Parameter execute: The handler to execute if this promise is rejected with the provided error. + - Note: Since this method handles only specific errors, supplying a `CatchPolicy` is unsupported. You can instead specify e.g. your cancellable error. + - SeeAlso: [Cancellation](https://github.com/mxcl/PromiseKit/blob/master/Documentation/CommonPatterns.md#cancellation) + */ + public func `catch`(only: E, on: Dispatcher = conf.D.return, _ body: @escaping(E) -> Void) -> CancellableCascadingFinalizer where E: Equatable { + return CancellableCascadingFinalizer(pmkCascadingFinalizer.catch(only: only, on: on, body), cancel: cancelContext) + } + + /** + The provided closure executes when this promise rejects with an error of the type passed in. A final `catch` is still required at the end of the chain. + + Rejecting a promise cascades: rejecting all subsequent promises (unless + recover is invoked) thus you will typically place your catch at the end + of a chain. Often utility promises will not have a catch, instead + delegating the error handling to the caller. + + - Parameter only: The error type to be caught and handled. + - Parameter on: The queue to which the provided closure dispatches. + - Parameter execute: The handler to execute if this promise is rejected with the provided error type. + - SeeAlso: [Cancellation](https://github.com/mxcl/PromiseKit/blob/master/Documentation/CommonPatterns.md#cancellation) + */ + public func `catch`(only: E.Type, on: Dispatcher = conf.D.return, policy: CatchPolicy = conf.catchPolicy, _ body: @escaping(E) -> Void) -> CancellableCascadingFinalizer { + return CancellableCascadingFinalizer(pmkCascadingFinalizer.catch(only: only, on: on, policy: policy, body), cancel: cancelContext) + } + + /** + Consumes the Swift unused-result warning. + - Note: You should `catch`, but in situations where you know you don’t need a `catch`, `cauterize` makes your intentions clear. + */ + @discardableResult + public func cauterize() -> CancellableFinalizer { + return self.catch(policy: .allErrors) { + conf.logHandler(.cauterized($0)) + } + } +} + +public extension CancellableCatchMixin { + /** + The provided closure executes when this cancellable promise rejects. + + Unlike `catch`, `recover` continues the chain. It can return a replacement promise or rethrow. + Use `recover` in circumstances where recovering the chain from certain errors is a possibility. For example: + + let context = firstly { + CLLocationManager.requestLocation() + }.recover { error in + guard error == CLError.unknownLocation else { throw error } + return .value(CLLocation.chicago) + }.cancelContext + + //… + + context.cancel() + + - Parameter on: The dispatcher that executes the provided closure. + - Parameter body: The handler to execute if this promise is rejected. + - SeeAlso: [Cancellation](https://github.com/mxcl/PromiseKit/blob/master/Documentation/CommonPatterns.md#cancellation) + */ + func recover(on: Dispatcher = conf.D.map, policy: CatchPolicy = conf.catchPolicy, _ body: @escaping(Error) throws -> V) -> CancellablePromise where V.U.T == C.T { + let cancelItemList = CancelItemList() + + let cancelBody = { (error: Error) throws -> V.U in + _ = self.cancelContext.removeItems(self.cancelItemList, clearList: true) + let rval = try body(error) + if policy == .allErrors || error.isCancelled { + self.cancelContext.recover() + } + self.cancelContext.append(context: rval.cancelContext, thenableCancelItemList: cancelItemList) + return rval.thenable + } + + let promise = self.catchable.recover(on: on, policy: policy, cancelBody) + if thenable.result != nil && policy == .allErrors { + self.cancelContext.recover() + } + return CancellablePromise(promise: promise, context: self.cancelContext, cancelItemList: cancelItemList) + } + + /** + The provided closure executes when this cancellable promise rejects. + + Unlike `catch`, `recover` continues the chain. It can return a replacement promise or rethrow. + Use `recover` in circumstances where recovering the chain from certain errors is a possibility. For example: + + let context = firstly { + CLLocationManager.requestLocation() + }.cancellize().recover { error in + guard error == CLError.unknownLocation else { throw error } + return Promise.value(CLLocation.chicago) + }.cancelContext + + //… + + context.cancel() + + - Parameter on: The dispatcher that executes the provided closure. + - Parameter policy: The default policy does not execute your handler for cancellation errors. + - Parameter body: The handler to execute if this promise is rejected. + - SeeAlso: [Cancellation](https://github.com/mxcl/PromiseKit/blob/master/Documentation/CommonPatterns.md#cancellation) + */ + func recover(on: Dispatcher = conf.D.map, policy: CatchPolicy = conf.catchPolicy, _ body: @escaping(Error) throws -> V) -> CancellablePromise where V.T == C.T { + let cancelBody = { (error: Error) throws -> V in + _ = self.cancelContext.removeItems(self.cancelItemList, clearList: true) + let rval = try body(error) + if policy == .allErrors || error.isCancelled { + self.cancelContext.recover() + } + return rval + } + + let promise = self.catchable.recover(on: on, policy: policy, cancelBody) + if thenable.result != nil && policy == .allErrors { + self.cancelContext.recover() + } + let cancellablePromise = CancellablePromise(promise: promise, context: self.cancelContext) + if let cancellable = promise.cancellable { + self.cancelContext.append(cancellable: cancellable, reject: promise.rejectIfCancelled, thenable: cancellablePromise) + } + return cancellablePromise + } + + /** + The provided closure executes when this cancellable promise rejects with the specific error passed in. + + Unlike `catch`, `recover` continues the chain. It can return a replacement promise or rethrow. + Use `recover` in circumstances where recovering the chain from certain errors is a possibility. For example: + + firstly { + CLLocationManager.requestLocation() + }.recover(CLError.unknownLocation) { + return .value(CLLocation.chicago) + } + + - Parameter only: The specific error to be recovered (e.g., `PMKError.emptySequence`) + - Parameter on: The dispatcher that executes the provided closure. + - Parameter body: The handler to execute if this promise is rejected with the provided error. + - Note: Since this method recovers only specific errors, supplying a `CatchPolicy` is unsupported. + - SeeAlso: [Cancellation](https://github.com/mxcl/PromiseKit/blob/master/Documentation/CommonPatterns.md#cancellation) + */ + func recover(only: E, on: Dispatcher = conf.D.map, _ body: @escaping(E) throws -> V) -> CancellablePromise where V.U.T == C.T, E: Equatable { + let cancelItemList = CancelItemList() + + let cancelBody = { (error: E) throws -> V.U in + _ = self.cancelContext.removeItems(self.cancelItemList, clearList: true) + let rval = try body(error) + if error.isCancelled { + self.cancelContext.recover() + } + self.cancelContext.append(context: rval.cancelContext, thenableCancelItemList: cancelItemList) + return rval.thenable + } + + let promise = self.catchable.recover(only: only, on: on, cancelBody) + if thenable.result != nil && only.isCancelled { + self.cancelContext.recover() + } + return CancellablePromise(promise: promise, context: self.cancelContext, cancelItemList: cancelItemList) + } + + /** + The provided closure executes when this cancellable promise rejects with the specific error passed in. + + Unlike `catch`, `recover` continues the chain. It can return a replacement promise or rethrow. + Use `recover` in circumstances where recovering the chain from certain errors is a possibility. For example: + + firstly { + CLLocationManager.requestLocation() + }.recover(CLError.unknownLocation) { + return Promise.value(CLLocation.chicago) + } + + - Parameter only: The specific error to be recovered. + - Parameter on: The queue to which the provided closure dispatches. + - Parameter body: The handler to execute if this promise is rejected with the provided error. + - Note: Since this method recovers only specific errors, supplying a `CatchPolicy` is unsupported. You can instead specify e.g. your cancellable error. + - SeeAlso: [Cancellation](https://github.com/mxcl/PromiseKit/blob/master/Documentation/CommonPatterns.md#cancellation) + */ + func recover(only: E, on: Dispatcher = conf.D.map, _ body: @escaping(E) throws -> V) -> CancellablePromise where V.T == C.T, E: Equatable { + let cancelBody = { (error: E) throws -> V in + _ = self.cancelContext.removeItems(self.cancelItemList, clearList: true) + let rval = try body(error) + if error.isCancelled { + self.cancelContext.recover() + } + return rval + } + + let promise = self.catchable.recover(only: only, on: on, cancelBody) + let cancellablePromise = CancellablePromise(promise: promise, context: self.cancelContext) + if let cancellable = promise.cancellable { + self.cancelContext.append(cancellable: cancellable, reject: promise.rejectIfCancelled, thenable: cancellablePromise) + } + return cancellablePromise + } + + /** + The provided closure executes when this cancellable promise rejects with an error of the type passed in. + + Unlike `catch`, `recover` continues the chain. It can return a replacement promise or rethrow. + Use `recover` in circumstances where recovering the chain from certain errors is a possibility. For example: + + firstly { + API.fetchData() + }.recover(FetchError.self) { error in + guard case .missingImage(let partialData) = error else { throw error } + //… + return .value(dataWithDefaultImage) + } + + - Parameter only: The error type to be recovered. + - Parameter on: The dispatcher that executes the provided closure. + - Parameter policy: The default policy does not execute your handler for cancellation errors. + - Parameter body: The handler to execute if this promise is rejected with the provided error type. + - SeeAlso: [Cancellation](https://github.com/mxcl/PromiseKit/blob/master/Documentation/CommonPatterns.md#cancellation) + */ + func recover(only: E.Type, on: Dispatcher = conf.D.map, policy: CatchPolicy = conf.catchPolicy, _ body: @escaping(E) throws -> V) -> CancellablePromise where V.U.T == C.T { + let cancelItemList = CancelItemList() + + let cancelBody = { (error: E) throws -> V.U in + _ = self.cancelContext.removeItems(self.cancelItemList, clearList: true) + let rval = try body(error) + if policy == .allErrors || error.isCancelled { + self.cancelContext.recover() + } + self.cancelContext.append(context: rval.cancelContext, thenableCancelItemList: cancelItemList) + return rval.thenable + } + + let promise = self.catchable.recover(only: only, on: on, policy: policy, cancelBody) + if thenable.result != nil && policy == .allErrors { + self.cancelContext.recover() + } + return CancellablePromise(promise: promise, context: self.cancelContext, cancelItemList: cancelItemList) + } + + /** + The provided closure executes when this cancellable promise rejects with an error of the type passed in. + + Unlike `catch`, `recover` continues the chain. It can return a replacement promise or rethrow. + Use `recover` in circumstances where recovering the chain from certain errors is a possibility. For example: + + firstly { + API.fetchData() + }.recover(FetchError.self) { error in + guard case .missingImage(let partialData) = error else { throw error } + //… + return Promise.value(dataWithDefaultImage) + } + + - Parameter only: The error type to be recovered. + - Parameter on: The queue to which the provided closure dispatches. + - Parameter body: The handler to execute if this promise is rejected with the provided error type. + - SeeAlso: [Cancellation](https://github.com/mxcl/PromiseKit/blob/master/Documentation/CommonPatterns.md#cancellation) + */ + func recover(only: E.Type, on: Dispatcher = conf.D.map, policy: CatchPolicy = conf.catchPolicy, _ body: @escaping(E) throws -> V) -> CancellablePromise where V.T == C.T { + let cancelBody = { (error: E) throws -> V in + _ = self.cancelContext.removeItems(self.cancelItemList, clearList: true) + let rval = try body(error) + if policy == .allErrors { + self.cancelContext.recover() + } + return rval + } + + let promise = self.catchable.recover(only: only, on: on, policy: policy, cancelBody) + if thenable.result != nil && policy == .allErrors { + self.cancelContext.recover() + } + let cancellablePromise = CancellablePromise(promise: promise, context: self.cancelContext) + if let cancellable = promise.cancellable { + self.cancelContext.append(cancellable: cancellable, reject: promise.rejectIfCancelled, thenable: cancellablePromise) + } + return cancellablePromise + } + + /** + The provided closure executes when this cancellable promise resolves, whether it rejects or not. + + let context = firstly { + UIApplication.shared.networkActivityIndicatorVisible = true + //… returns a cancellable promise + }.done { + //… + }.ensure { + UIApplication.shared.networkActivityIndicatorVisible = false + }.catch { + //… + }.cancelContext + + //… + + context.cancel() + + - Parameter on: The dispatcher that executes the provided closure. + - Parameter body: The closure that executes when this promise resolves. + - Returns: A new promise, resolved with this promise’s resolution. + */ + func ensure(on: Dispatcher = conf.D.return, _ body: @escaping () -> Void) -> CancellablePromise { + let rp = CancellablePromise.pending() + rp.promise.cancelContext = self.cancelContext + self.catchable.pipe { result in + on.dispatch { + body() + switch result { + case .success(let value): + if let error = self.cancelContext.cancelledError { + rp.resolver.reject(error) + } else { + rp.resolver.fulfill(value) + } + case .failure(let error): + rp.resolver.reject(error) + } + } + } + return rp.promise + } + + /** + The provided closure executes when this cancellable promise resolves, whether it rejects or not. + The chain waits on the returned `CancellablePromise`. + + let context = firstly { + setup() // returns a cancellable promise + }.done { + //… + }.ensureThen { + teardown() // -> CancellablePromise + }.catch { + //… + }.cancelContext + + //… + + context.cancel() + + - Parameter on: The dispatcher that executes the provided closure. + - Parameter body: The closure that executes when this promise resolves. + - Returns: A new promise, resolved with this promise’s resolution. + */ + func ensureThen(on: Dispatcher = conf.D.return, _ body: @escaping () -> CancellablePromise) -> CancellablePromise { + let rp = CancellablePromise.pending() + rp.promise.cancelContext = cancelContext + self.catchable.pipe { result in + on.dispatch { + let rv = body() + rp.promise.appendCancelContext(from: rv) + + rv.done { + switch result { + case .success(let value): + if let error = self.cancelContext.cancelledError { + rp.resolver.reject(error) + } else { + rp.resolver.fulfill(value) + } + case .failure(let error): + rp.resolver.reject(error) + } + }.catch(policy: .allErrors) { + rp.resolver.reject($0) + } + } + } + return rp.promise + } + + /** + Consumes the Swift unused-result warning. + - Note: You should `catch`, but in situations where you know you don’t need a `catch`, `cauterize` makes your intentions clear. + */ + @discardableResult + func cauterize() -> CancellableFinalizer { + return self.catch(policy: .allErrors) { + conf.logHandler(.cauterized($0)) + } + } +} + +public extension CancellableCatchMixin where C.T == Void { + /** + The provided closure executes when this cancellable promise rejects. + + This variant of `recover` ensures that no error is thrown from the handler and allows specifying a catch policy. + + - Parameter on: The dispatcher that executes the provided closure. + - Parameter body: The handler to execute if this promise is rejected. + - SeeAlso: [Cancellation](https://github.com/mxcl/PromiseKit/blob/master/Documentation/CommonPatterns.md#cancellation) + */ + func recover(on: Dispatcher = conf.D.map, policy: CatchPolicy = conf.catchPolicy, _ body: @escaping(Error) throws -> Void) -> CancellablePromise { + let cancelBody = { (error: Error) throws -> Void in + _ = self.cancelContext.removeItems(self.cancelItemList, clearList: true) + try body(error) + if policy == .allErrors { + self.cancelContext.recover() + } + } + + let promise = self.catchable.recover(on: on, policy: policy, cancelBody) + if thenable.result != nil && policy == .allErrors { + self.cancelContext.recover() + } + return CancellablePromise(promise: promise, context: self.cancelContext) + } + + + /** + The provided closure executes when this cancellable promise rejects with the specific error passed in. + + Unlike `catch`, `recover` continues the chain. It can return a replacement promise or rethrow. + Use `recover` in circumstances where recovering the chain from certain errors is a possibility. + + - Parameter only: The specific error to be recovered. + - Parameter on: The queue to which the provided closure dispatches. + - Parameter body: The handler to execute if this promise is rejected with the provided error. + - Note: Since this method recovers only specific errors, supplying a `CatchPolicy` is unsupported. You can instead specify e.g. your cancellable error. + - SeeAlso: [Cancellation](https://github.com/mxcl/PromiseKit/blob/master/Documentation/CommonPatterns.md#cancellation) + */ + func recover(only: E, on: Dispatcher = conf.D.map, _ body: @escaping(E) throws -> Void) + -> CancellablePromise where E: Equatable + { + let cancelBody = { (error: E) throws -> Void in + _ = self.cancelContext.removeItems(self.cancelItemList, clearList: true) + try body(error) + if error.isCancelled { + self.cancelContext.recover() + } + } + + let promise = self.catchable.recover(only: only, on: on, cancelBody) + if thenable.result != nil && only.isCancelled { + self.cancelContext.recover() + } + return CancellablePromise(promise: promise, context: self.cancelContext) + } + + /** + The provided closure executes when this cancellable promise rejects with an error of the type passed in. + + Unlike `catch`, `recover` continues the chain. It can return a replacement promise or rethrow. + Use `recover` in circumstances where recovering the chain from certain errors is a possibility. + + - Parameter only: The error type to be recovered. + - Parameter on: The queue to which the provided closure dispatches. + - Parameter body: The handler to execute if this promise is rejected with the provided error type. + - SeeAlso: [Cancellation](https://github.com/mxcl/PromiseKit/blob/master/Documentation/CommonPatterns.md#cancellation) + */ + func recover(only: E.Type, on: Dispatcher = conf.D.map, policy: CatchPolicy = conf.catchPolicy, _ body: @escaping(E) throws -> Void) -> CancellablePromise { + let cancelBody = { (error: E) throws -> Void in + _ = self.cancelContext.removeItems(self.cancelItemList, clearList: true) + try body(error) + if policy == .allErrors || error.isCancelled { + self.cancelContext.recover() + } + } + + let promise = self.catchable.recover(only: only, on: on, policy: policy, cancelBody) + if thenable.result != nil && policy == .allErrors { + self.cancelContext.recover() + } + return CancellablePromise(promise: promise, context: self.cancelContext) + } +} diff --git a/Sources/PromiseKit/Cancellation/CancellablePromise.swift b/Sources/PromiseKit/Cancellation/CancellablePromise.swift new file mode 100644 index 000000000..93e42002a --- /dev/null +++ b/Sources/PromiseKit/Cancellation/CancellablePromise.swift @@ -0,0 +1,141 @@ +import class Foundation.Thread +import Dispatch + +/** + A `CancellablePromise` is a functional abstraction around a failable and cancellable asynchronous operation. + + At runtime the promise can become a member of a chain of promises, where the `cancelContext` is used to track and cancel (if desired) all promises in this chain. + + - See: `CancellableThenable` + */ +public class CancellablePromise: CancellableThenable, CancellableCatchMixin { + /// Delegate `promise` for this CancellablePromise + public let promise: Promise + + /// Type of the delegate `thenable` + public typealias U = Promise + + /// Delegate `thenable` for this CancellablePromise + public var thenable: U { + return promise + } + + /// Type of the delegate `catchable` + public typealias C = Promise + + /// Delegate `catchable` for this CancellablePromise + public var catchable: C { + return promise + } + + /// The CancelContext associated with this CancellablePromise + public var cancelContext: CancelContext + + /// Tracks the cancel items for this CancellablePromise. These items are removed from the associated CancelContext when the promise resolves. + public var cancelItemList: CancelItemList + + init(promise: Promise, context: CancelContext? = nil, cancelItemList: CancelItemList? = nil) { + self.promise = promise + self.cancelContext = context ?? CancelContext() + self.cancelItemList = cancelItemList ?? CancelItemList() + } + + /// Initialize a new rejected cancellable promise. + public convenience init(cancellable: Cancellable? = nil, error: Error) { + var reject: ((Error) -> Void)! + self.init(promise: Promise { seal in + reject = seal.reject + seal.reject(error) + }) + self.appendCancellable(cancellable, reject: reject) + } + + /// Initialize a new cancellable promise bound to the provided `Thenable`. + public convenience init(_ bridge: U, cancelContext: CancelContext? = nil) where U.T == T { + var promise: Promise! + let cancellable: Cancellable! + var reject: ((Error) -> Void)! + + if let p = bridge as? Promise { + cancellable = p.cancellable + if let r = p.rejectIfCancelled { + promise = p + reject = r + } + } else if let g = bridge as? Guarantee { + cancellable = g.cancellable + } else { + cancellable = nil + } + + if promise == nil { + // Wrapper promise + promise = Promise { seal in + reject = seal.reject + bridge.done(on: CurrentThreadDispatcher()) { + seal.fulfill($0) + }.catch(on: CurrentThreadDispatcher(), policy: .allErrors) { + seal.reject($0) + } + } + } + + self.init(promise: promise, context: cancelContext) + self.appendCancellable(cancellable, reject: reject) + } + + /// Initialize a new cancellable promise that can be resolved with the provided `Resolver`. + public convenience init(cancellable: Cancellable? = nil, resolver body: (Resolver) throws -> Void) { + var reject: ((Error) -> Void)! + self.init(promise: Promise { seal in + reject = seal.reject + try body(seal) + }) + self.appendCancellable(cancellable, reject: reject) + } + + /// Initialize a new cancellable promise using the given Promise and its Resolver. + public convenience init(cancellable: Cancellable? = nil, promise: Promise, resolver: Resolver) { + self.init(promise: promise) + self.appendCancellable(cancellable, reject: resolver.reject) + } + + /// - Returns: a tuple of a new cancellable pending promise and its `Resolver`. + public class func pending() -> (promise: CancellablePromise, resolver: Resolver) { + let rp = Promise.pending() + return (promise: CancellablePromise(promise: rp.promise), resolver: rp.resolver) + } + + /// Internal function required for `Thenable` conformance. + /// - See: `Thenable.pipe` + public func pipe(to: @escaping (Result) -> Void) { + promise.pipe(to: to) + } + + /// - Returns: The current `Result` for this cancellable promise. + /// - See: `Thenable.result` + public var result: Result? { + return promise.result + } + + /** + Blocks this thread, so—you know—don’t call this on a serial thread that + any part of your chain may use. Like the main thread for example. + */ + public func wait() throws -> T { + return try promise.wait() + } +} + +extension CancellablePromise where T == Void { + /// Initializes a new cancellable promise fulfilled with `Void` + public convenience init() { + self.init(promise: Promise()) + } + + /// Initializes a new cancellable promise fulfilled with `Void` and with the given ` Cancellable` + public convenience init(cancellable: Cancellable) { + self.init() + self.appendCancellable(cancellable, reject: nil) + } +} diff --git a/Sources/PromiseKit/Cancellation/CancellableThenable.swift b/Sources/PromiseKit/Cancellation/CancellableThenable.swift new file mode 100644 index 000000000..5ca4ee68d --- /dev/null +++ b/Sources/PromiseKit/Cancellation/CancellableThenable.swift @@ -0,0 +1,520 @@ +import Dispatch + +/** + CancellableThenable represents an asynchronous operation that can be both chained and cancelled. When chained, all CancellableThenable members of the chain are cancelled when `cancel` is called on the associated CancelContext. + */ +public protocol CancellableThenable: AnyObject { + /// Type of the delegate `thenable` + associatedtype U: Thenable + + /// Delegate `thenable` for this `CancellableThenable` + var thenable: U { get } + + /// The `CancelContext` associated with this `CancellableThenable` + var cancelContext: CancelContext { get } + + /// Tracks the cancel items for this `CancellableThenable`. These items are removed from the associated `CancelContext` when the thenable resolves. + var cancelItemList: CancelItemList { get } +} + +public extension CancellableThenable { + /// Append the `task` and `reject` function for a cancellable task to the cancel context + func appendCancellable(_ cancellable: Cancellable?, reject: ((Error) -> Void)?) { + self.cancelContext.append(cancellable: cancellable, reject: reject, thenable: self) + } + + /// Append the cancel context associated with `from` to our cancel context. Typically `from` is a branch of our chain. + func appendCancelContext(from: Z) { + self.cancelContext.append(context: from.cancelContext, thenable: self) + } + + /** + Cancel all members of the promise chain and their associated asynchronous operations. + + - Parameter error: Specifies the cancellation error to use for the cancel operation, defaults to `PMKError.cancelled` + */ + func cancel(with error: Error = PMKError.cancelled) { + self.cancelContext.cancel(with: error) + } + + /** + True if all members of the promise chain have been successfully cancelled, false otherwise. + */ + var isCancelled: Bool { + return self.cancelContext.isCancelled + } + + /** + True if `cancel` has been called on the CancelContext associated with this promise, false otherwise. `cancelAttempted` will be true if `cancel` is called on any promise in the chain. + */ + var cancelAttempted: Bool { + return self.cancelContext.cancelAttempted + } + + /** + The cancellation error generated when the promise is cancelled, or `nil` if not cancelled. + */ + var cancelledError: Error? { + return self.cancelContext.cancelledError + } + + /** + The provided closure executes when this cancellable promise resolves. + + This allows chaining promises. The cancellable promise returned by the provided closure is resolved before the cancellable promise returned by this closure resolves. + + - Parameter on: The dispatcher that executes the provided closure. + - Parameter body: The closure that executes when this cancellable promise fulfills. It must return a cancellable promise. + - Returns: A new cancellable promise that resolves when the cancellable promise returned from the provided closure resolves. For example: + + let context = firstly { + URLSession.shared.dataTask(.promise, with: url1) + }.cancellize().then { response in + transform(data: response.data) // returns a CancellablePromise + }.done { transformation in + //… + }.cancelContext + + //… + + context.cancel() + */ + func then(on: Dispatcher = conf.D.map, _ body: @escaping (U.T) throws -> V) -> CancellablePromise { + + let cancelItemList = CancelItemList() + + let cancelBody = { (value: U.T) throws -> V.U in + if let error = self.cancelContext.removeItems(self.cancelItemList, clearList: true) { + throw error + } else { + let rv = try body(value) + self.cancelContext.append(context: rv.cancelContext, thenableCancelItemList: cancelItemList) + return rv.thenable + } + } + + let promise = self.thenable.then(on: on, cancelBody) + return CancellablePromise(promise: promise, context: self.cancelContext, cancelItemList: cancelItemList) + } + + /** + The provided closure executes when this cancellable promise resolves. + + This allows chaining promises. The promise returned by the provided closure is resolved before the cancellable promise returned by this closure resolves. + + - Parameter on: The dispatcher that executes the provided closure. + - Parameter body: The closure that executes when this promise fulfills. It must return a promise (not a cancellable promise). + - Returns: A new cancellable promise that resolves when the promise returned from the provided closure resolves. For example: + + let context = firstly { + URLSession.shared.dataTask(.promise, with: url1) + }.cancellize().then { response in + transform(data: response.data) // returns a Promise + }.done { transformation in + //… + }.cancelContext + + //… + + context.cancel() + */ + func then(on: Dispatcher = conf.D.map, _ body: @escaping (U.T) throws -> V) -> CancellablePromise { + let cancelBody = { (value: U.T) throws -> V in + if let error = self.cancelContext.removeItems(self.cancelItemList, clearList: true) { + throw error + } else { + return try body(value) + } + } + + let promise = self.thenable.then(on: on, cancelBody) + return CancellablePromise(promise, cancelContext: self.cancelContext) + } + + /** + The provided closure is executed when this cancellable promise is resolved. + + This is like `then` but it requires the closure to return a non-promise and non-cancellable-promise. + + - Parameter on: The queue to which the provided closure dispatches. + - Parameter transform: The closure that is executed when this CancellablePromise is fulfilled. It must return a non-promise and non-cancellable-promise. + - Returns: A new cancellable promise that is resolved with the value returned from the provided closure. For example: + + let context = firstly { + URLSession.shared.dataTask(.promise, with: url1) + }.cancellize().map { response in + response.data.length + }.done { length in + //… + }.cancelContext + + //… + + context.cancel() + */ + func map(on: Dispatcher = conf.D.map, _ transform: @escaping (U.T) throws -> V) -> CancellablePromise { + let cancelTransform = { (value: U.T) throws -> V in + if let error = self.cancelContext.removeItems(self.cancelItemList, clearList: true) { + throw error + } else { + return try transform(value) + } + } + + let promise = self.thenable.map(on: on, cancelTransform) + return CancellablePromise(promise: promise, context: self.cancelContext) + } + + /** + The provided closure is executed when this cancellable promise is resolved. + + In your closure return an `Optional`, if you return `nil` the resulting cancellable promise is rejected with `PMKError.compactMap`, otherwise the cancellable promise is fulfilled with the unwrapped value. + + let context = firstly { + URLSession.shared.dataTask(.promise, with: url) + }.cancellize().compactMap { + try JSONSerialization.jsonObject(with: $0.data) as? [String: String] + }.done { dictionary in + //… + }.catch { + // either `PMKError.compactMap` or a `JSONError` + }.cancelContext + + //… + + context.cancel() + */ + func compactMap(on: Dispatcher = conf.D.map, _ transform: @escaping (U.T) throws -> V?) -> CancellablePromise { + let cancelTransform = { (value: U.T) throws -> V? in + if let error = self.cancelContext.removeItems(self.cancelItemList, clearList: true) { + throw error + } else { + return try transform(value) + } + } + + let promise = self.thenable.compactMap(on: on, cancelTransform) + return CancellablePromise(promise: promise, context: self.cancelContext) + } + + /** + The provided closure is executed when this cancellable promise is resolved. + + Equivalent to `map { x -> Void in`, but since we force the `Void` return Swift + is happier and gives you less hassle about your closure’s qualification. + + - Parameter on: The dispatcher that executes the provided closure. + - Parameter body: The closure that is executed when this promise is fulfilled. + - Returns: A new cancellable promise fulfilled as `Void`. + + let context = firstly { + URLSession.shared.dataTask(.promise, with: url) + }.cancellize().done { response in + print(response.data) + }.cancelContext + + //… + + context.cancel() + */ + func done(on: Dispatcher = conf.D.return, _ body: @escaping (U.T) throws -> Void) -> CancellablePromise { + let cancelBody = { (value: U.T) throws -> Void in + if let error = self.cancelContext.removeItems(self.cancelItemList, clearList: true) { + throw error + } else { + try body(value) + } + } + + let promise = self.thenable.done(on: on, cancelBody) + return CancellablePromise(promise: promise, context: self.cancelContext) + } + + /** + The provided closure is executed when this cancellable promise is resolved. + + This is like `done` but it returns the same value that the handler is fed. + `get` immutably accesses the fulfilled value; the returned CancellablePromise maintains that value. + + - Parameter on: The dispatcher that executes the provided closure. + - Parameter body: The closure that is executed when this promise is fulfilled. + - Returns: A new cancellable promise that is resolved with the value that the handler is fed. For example: + + let context = firstly { + cancellize(Promise.value(1)) + }.get { foo in + print(foo, " is 1") + }.done { foo in + print(foo, " is 1") + }.done { foo in + print(foo, " is Void") + }.cancelContext + + //… + + context.cancel() + */ + func get(on: Dispatcher = conf.D.return, _ body: @escaping (U.T) throws -> Void) -> CancellablePromise { + return map(on: on) { + try body($0) + return $0 + } + } + + /** + The provided closure is executed with cancellable promise result. + + This is like `get` but provides the Result of the CancellablePromise so you can inspect the value of the chain at this point without causing any side effects. + + - Parameter on: The dispatcher that executes the provided closure. + - Parameter body: The closure that is executed with Result of CancellablePromise. + - Returns: A new cancellable promise that is resolved with the result that the handler is fed. For example: + + promise.tap{ print($0) }.then{ /*…*/ } + */ + func tap(on: Dispatcher = conf.D.map, _ body: @escaping(Result) -> Void) -> CancellablePromise { + let rp = CancellablePromise.pending() + rp.promise.cancelContext = self.cancelContext + self.thenable.pipe { result in + on.dispatch { + if let error = self.cancelContext.removeItems(self.cancelItemList, clearList: true) { + rp.resolver.reject(error) + } else { + body(result) + rp.resolver.resolve(result) + } + } + } + return rp.promise + } + + /// - Returns: a new cancellable promise chained off this cancellable promise but with its value discarded. + func asVoid() -> CancellablePromise { + return map(on: nil) { _ in } + } +} + +public extension CancellableThenable { + /** + - Returns: The error with which this cancellable promise was rejected; `nil` if this promise is not rejected. + */ + var error: Error? { + return thenable.error + } + + /** + - Returns: `true` if the cancellable promise has not yet resolved. + */ + var isPending: Bool { + return thenable.isPending + } + + /** + - Returns: `true` if the cancellable promise has resolved. + */ + var isResolved: Bool { + return thenable.isResolved + } + + /** + - Returns: `true` if the cancellable promise was fulfilled. + */ + var isFulfilled: Bool { + return thenable.isFulfilled + } + + /** + - Returns: `true` if the cancellable promise was rejected. + */ + var isRejected: Bool { + return thenable.isRejected + } + + /** + - Returns: The value with which this cancellable promise was fulfilled or `nil` if this cancellable promise is pending or rejected. + */ + var value: U.T? { + return thenable.value + } +} + +public extension CancellableThenable where U.T: Sequence { + /** + `CancellablePromise<[U.T]>` => `U.T` -> `V` => `CancellablePromise<[V]>` + + firstly { + cancellize(Promise.value([1,2,3])) + }.mapValues { integer in + integer * 2 + }.done { + // $0 => [2,4,6] + } + */ + func mapValues(on: Dispatcher = conf.D.map, _ transform: @escaping(U.T.Iterator.Element) throws -> V) -> CancellablePromise<[V]> { + return map(on: on) { try $0.map(transform) } + } + + /** + `CancellablePromise<[U.T]>` => `U.T` -> `[V]` => `CancellablePromise<[V]>` + + firstly { + cancellize(Promise.value([1,2,3])) + }.flatMapValues { integer in + [integer, integer] + }.done { + // $0 => [1,1,2,2,3,3] + } + */ + func flatMapValues(on: Dispatcher = conf.D.map, _ transform: @escaping(U.T.Iterator.Element) throws -> V) -> CancellablePromise<[V.Iterator.Element]> { + return map(on: on) { (foo: U.T) in + try foo.flatMap { try transform($0) } + } + } + + /** + `CancellablePromise<[U.T]>` => `U.T` -> `V?` => `CancellablePromise<[V]>` + + firstly { + cancellize(Promise.value(["1","2","a","3"])) + }.compactMapValues { + Int($0) + }.done { + // $0 => [1,2,3] + } + */ + func compactMapValues(on: Dispatcher = conf.D.map, _ transform: @escaping(U.T.Iterator.Element) throws -> V?) -> CancellablePromise<[V]> { + return map(on: on) { foo -> [V] in + return try foo.compactMap(transform) + } + } + + /** + `CancellablePromise<[U.T]>` => `U.T` -> `CancellablePromise` => `CancellablePromise<[V]>` + + firstly { + cancellize(Promise.value([1,2,3])) + }.thenMap { integer in + cancellize(Promise.value(integer * 2)) + }.done { + // $0 => [2,4,6] + } + */ + func thenMap(on: Dispatcher = conf.D.map, _ transform: @escaping(U.T.Iterator.Element) throws -> V) -> CancellablePromise<[V.U.T]> { + return then(on: on) { + when(fulfilled: try $0.map(transform)) + } + } + + /** + `CancellablePromise<[U.T]>` => `U.T` -> `Promise` => `CancellablePromise<[V]>` + + firstly { + Promise.value([1,2,3]) + }.cancellize().thenMap { integer in + .value(integer * 2) + }.done { + // $0 => [2,4,6] + } + */ + func thenMap(on: Dispatcher = conf.D.map, _ transform: @escaping(U.T.Iterator.Element) throws -> V) -> CancellablePromise<[V.T]> { + return then(on: on) { + when(fulfilled: try $0.map(transform)) + } + } + + /** + `CancellablePromise<[T]>` => `T` -> `CancellablePromise<[U]>` => `CancellablePromise<[U]>` + + firstly { + cancellize(Promise.value([1,2,3])) + }.thenFlatMap { integer in + cancellize(Promise.value([integer, integer])) + }.done { + // $0 => [1,1,2,2,3,3] + } + */ + func thenFlatMap(on: Dispatcher = conf.D.map, _ transform: @escaping(U.T.Iterator.Element) throws -> V) -> CancellablePromise<[V.U.T.Iterator.Element]> where V.U.T: Sequence { + return then(on: on) { + when(fulfilled: try $0.map(transform)) + }.map(on: nil) { + $0.flatMap { $0 } + } + } + + /** + `CancellablePromise<[T]>` => `T` -> `Promise<[U]>` => `CancellablePromise<[U]>` + + firstly { + Promise.value([1,2,3]) + }.cancellize().thenFlatMap { integer in + .value([integer, integer]) + }.done { + // $0 => [1,1,2,2,3,3] + } + */ + func thenFlatMap(on: Dispatcher = conf.D.map, _ transform: @escaping(U.T.Iterator.Element) throws -> V) -> CancellablePromise<[V.T.Iterator.Element]> where V.T: Sequence { + return then(on: on) { + when(fulfilled: try $0.map(transform)) + }.map(on: nil) { + $0.flatMap { $0 } + } + } + + /** + `CancellablePromise<[T]>` => `T` -> Bool => `CancellablePromise<[U]>` + + firstly { + cancellize(Promise.value([1,2,3])) + }.filterValues { + $0 > 1 + }.done { + // $0 => [2,3] + } + */ + func filterValues(on: Dispatcher = conf.D.map, _ isIncluded: @escaping (U.T.Iterator.Element) -> Bool) -> CancellablePromise<[U.T.Iterator.Element]> { + return map(on: on) { + $0.filter(isIncluded) + } + } +} + +public extension CancellableThenable where U.T: Collection { + /// - Returns: a cancellable promise fulfilled with the first value of this `Collection` or, if empty, a promise rejected with PMKError.emptySequence. + var firstValue: CancellablePromise { + return map(on: nil) { aa in + if let a1 = aa.first { + return a1 + } else { + throw PMKError.emptySequence + } + } + } + + func firstValue(on: Dispatcher = conf.D.map, where test: @escaping (U.T.Iterator.Element) -> Bool) -> CancellablePromise { + return map(on: on) { + for x in $0 where test(x) { + return x + } + throw PMKError.emptySequence + } + } + + /// - Returns: a cancellable promise fulfilled with the last value of this `Collection` or, if empty, a promise rejected with PMKError.emptySequence. + var lastValue: CancellablePromise { + return map(on: nil) { aa in + if aa.isEmpty { + throw PMKError.emptySequence + } else { + let i = aa.index(aa.endIndex, offsetBy: -1) + return aa[i] + } + } + } +} + +public extension CancellableThenable where U.T: Sequence, U.T.Iterator.Element: Comparable { + /// - Returns: a cancellable promise fulfilled with the sorted values of this `Sequence`. + func sortedValues(on: Dispatcher = conf.D.map) -> CancellablePromise<[U.T.Iterator.Element]> { + return map(on: on) { $0.sorted() } + } +} diff --git a/Sources/PromiseKit/Catchable.swift b/Sources/PromiseKit/Catchable.swift new file mode 100644 index 000000000..e3c75e987 --- /dev/null +++ b/Sources/PromiseKit/Catchable.swift @@ -0,0 +1,566 @@ +import Dispatch + +/// Provides `catch` and `recover` to your object that conforms to `Thenable` +public protocol CatchMixin: Thenable +{} + +public extension CatchMixin { + + /** + The provided closure executes when this promise rejects. + + Rejecting a promise cascades: rejecting all subsequent promises (unless + recover is invoked) thus you will typically place your catch at the end + of a chain. Often utility promises will not have a catch, instead + delegating the error handling to the caller. + + - Parameter on: The dispatcher that executes the provided closure. + - Parameter policy: The default policy does not execute your handler for cancellation errors. + - Parameter body: The handler to execute if this promise is rejected. + - Returns: A promise finalizer. + - SeeAlso: [Cancellation](https://github.com/mxcl/PromiseKit/blob/master/Documents/CommonPatterns.md#cancellation) + */ + @discardableResult + func `catch`(on: Dispatcher = conf.D.return, policy: CatchPolicy = conf.catchPolicy, _ body: @escaping(Error) -> Void) -> PMKFinalizer { + let finalizer = PMKFinalizer() + pipe { + switch $0 { + case .failure(let error): + guard policy == .allErrors || !error.isCancelled else { + fallthrough + } + on.dispatch { + body(error) + finalizer.pending.resolve(()) + } + case .success: + finalizer.pending.resolve(()) + } + } + return finalizer + } + + /** + The provided closure executes when this promise rejects with the specific error passed in. A final `catch` is still required at the end of the chain. + + Rejecting a promise cascades: rejecting all subsequent promises (unless + recover is invoked) thus you will typically place your catch at the end + of a chain. Often utility promises will not have a catch, instead + delegating the error handling to the caller. + + - Parameter only: The specific error to be caught and handled (e.g., `PMKError.emptySequence`). + - Parameter on: The dispatcher that executes the provided closure. + - Parameter body: The handler to execute if this promise is rejected with the provided error. + - Returns: A promise finalizer that accepts additional `catch` clauses. + - Note: Since this method handles only specific errors, supplying a `CatchPolicy` is unsupported. + - SeeAlso: [Cancellation](http://promisekit.org/docs/) + */ + func `catch`(only: E, on: Dispatcher = conf.D.return, _ body: @escaping(E) -> Void) -> PMKCascadingFinalizer where E: Equatable { + let finalizer = PMKCascadingFinalizer() + pipe { + switch $0 { + case .failure(let error as E) where error == only: + on.dispatch { + body(error) + finalizer.pending.resolver.fulfill(()) + } + case .failure(let error): + finalizer.pending.resolver.reject(error) + case .success: + finalizer.pending.resolver.fulfill(()) + } + } + return finalizer + } + + /** + The provided closure executes when this promise rejects with an error of the type passed in. A final `catch` is still required at the end of the chain. + + Rejecting a promise cascades: rejecting all subsequent promises (unless + recover is invoked) thus you will typically place your catch at the end + of a chain. Often utility promises will not have a catch, instead + delegating the error handling to the caller. + + - Parameter only: The error type to be caught and handled (e.g., `PMKError`). + - Parameter on: The dispatcher that executes the provided closure. + - Parameter policy: A `CatchPolicy` that further constrains the errors this handler will see. E.g., if + you are receiving `PMKError` errors, do you want to see even those that result from cancellation? + - Parameter body: The handler to execute if this promise is rejected with the provided error type. + - Returns: A promise finalizer that accepts additional `catch` clauses. + - SeeAlso: [Cancellation](http://promisekit.org/docs/) + */ + func `catch`(only: E.Type, on: Dispatcher = conf.D.return, policy: CatchPolicy = conf.catchPolicy, _ body: @escaping(E) -> Void) -> PMKCascadingFinalizer { + let finalizer = PMKCascadingFinalizer() + pipe { + switch $0 { + case .failure(let error as E): + guard policy == .allErrors || !error.isCancelled else { + return finalizer.pending.resolver.reject(error) + } + on.dispatch { + body(error) + finalizer.pending.resolver.fulfill(()) + } + case .failure(let error): + finalizer.pending.resolver.reject(error) + case .success: + finalizer.pending.resolver.fulfill(()) + } + } + return finalizer + } +} + +public class PMKFinalizer { + let pending = Guarantee.pending() + + /// `finally` is the same as `ensure`, but it is not chainable + public func finally(on: Dispatcher = conf.D.return, _ body: @escaping () -> Void) { + pending.guarantee.done(on: on) { + body() + } + } +} + +public class PMKCascadingFinalizer { + let pending = Promise.pending() + + /** + The provided closure executes when this promise rejects. + + Rejecting a promise cascades: rejecting all subsequent promises (unless + recover is invoked) thus you will typically place your catch at the end + of a chain. Often utility promises will not have a catch, instead + delegating the error handling to the caller. + + - Parameter on: The dispatcher that executes the provided closure. + - Parameter policy: The default policy does not execute your handler for cancellation errors. + - Parameter body: The handler to execute if this promise is rejected. + - Returns: A promise finalizer. + - SeeAlso: [Cancellation](http://promisekit.org/docs/) + */ + @discardableResult + public func `catch`(on: Dispatcher = conf.D.return, policy: CatchPolicy = conf.catchPolicy, _ body: @escaping(Error) -> Void) -> PMKFinalizer { + return pending.promise.catch(on: on, policy: policy) { + body($0) + } + } + + /** + The provided closure executes when this promise rejects with the specific error passed in. A final `catch` is still required at the end of the chain. + + Rejecting a promise cascades: rejecting all subsequent promises (unless + recover is invoked) thus you will typically place your catch at the end + of a chain. Often utility promises will not have a catch, instead + delegating the error handling to the caller. + + - Parameter only: The specific error to be caught and handled (e.g., `PMKError.emptySequence`). + - Parameter on: The dispatcher that executes the provided closure. + - Parameter body: The handler to execute if this promise is rejected with the provided error. + - Returns: A promise finalizer that accepts additional `catch` clauses. + - Note: Since this method handles only specific errors, supplying a `CatchPolicy` is unsupported. + - SeeAlso: [Cancellation](http://promisekit.org/docs/) + */ + public func `catch`(only: E, on: Dispatcher = conf.D.return, _ body: @escaping(E) -> Void) -> PMKCascadingFinalizer where E: Equatable { + return pending.promise.catch(only: only, on: on) { + body($0) + } + } + + /** + The provided closure executes when this promise rejects with an error of the type passed in. A final `catch` is still required at the end of the chain. + + Rejecting a promise cascades: rejecting all subsequent promises (unless + recover is invoked) thus you will typically place your catch at the end + of a chain. Often utility promises will not have a catch, instead + delegating the error handling to the caller. + + - Parameter only: The error type to be caught and handled (e.g., `PMKError`). + - Parameter on: The dispatcher that executes the provided closure. + - Parameter body: The handler to execute if this promise is rejected with the provided error type. + - Returns: A promise finalizer that accepts additional `catch` clauses. + - SeeAlso: [Cancellation](http://promisekit.org/docs/) + */ + public func `catch`(only: E.Type, on: Dispatcher = conf.D.return, policy: CatchPolicy = conf.catchPolicy, _ body: @escaping(E) -> Void) -> PMKCascadingFinalizer { + return pending.promise.catch(only: only, on: on, policy: policy) { + body($0) + } + } + + /** + Consumes the Swift unused-result warning. + - Note: You should `catch`, but in situations where you know you don’t need a `catch`, `cauterize` makes your intentions clear. + */ + @discardableResult + public func cauterize() -> PMKFinalizer { + return self.catch { + conf.logHandler(.cauterized($0)) + } + } +} + +public extension CatchMixin { + + /** + The provided closure executes when this promise rejects. + + Unlike `catch`, `recover` continues the chain. It can return a replacement promise or rethrow. + Use `recover` in circumstances where recovering the chain from certain errors is a possibility. For example: + + firstly { + CLLocationManager.requestLocation() + }.recover { error in + guard error == CLError.unknownLocation else { throw error } + return .value(CLLocation.chicago) + } + + - Parameter on: The dispatcher that executes the provided closure. + - Parameter policy: The default policy does not execute your handler for cancellation errors. + - Parameter body: The handler to execute if this promise is rejected. + - SeeAlso: [Cancellation](https://github.com/mxcl/PromiseKit/blob/master/Documents/CommonPatterns.md#cancellation) + */ + func recover(on: Dispatcher = conf.D.map, policy: CatchPolicy = conf.catchPolicy, _ body: @escaping(Error) throws -> U) -> Promise where U.T == T { + let rp = Promise(.pending) + pipe { + switch $0 { + case .success(let value): + rp.box.seal(.success(value)) + case .failure(let error): + if policy == .allErrors || !error.isCancelled { + on.dispatch { + do { + let rv = try body(error) + guard rv !== rp else { throw PMKError.returnedSelf } + rv.pipe(to: rp.box.seal) + } catch { + rp.box.seal(.failure(error)) + } + } + } else { + rp.box.seal(.failure(error)) + } + } + } + return rp + } + + /** + The provided closure executes when this promise rejects with the specific error passed in. + + Unlike `catch`, `recover` continues the chain. It can return a replacement promise or rethrow. + Use `recover` in circumstances where recovering the chain from certain errors is a possibility. For example: + + firstly { + CLLocationManager.requestLocation() + }.recover(CLError.unknownLocation) { + return .value(CLLocation.chicago) + } + + - Parameter only: The specific error to be recovered (e.g., `PMKError.emptySequence`) + - Parameter on: The dispatcher that executes the provided closure. + - Parameter body: The handler to execute if this promise is rejected with the provided error. + - Note: Since this method recovers only specific errors, supplying a `CatchPolicy` is unsupported. + - SeeAlso: [Cancellation](http://promisekit.org/docs/) + */ + func recover(only: E, on: Dispatcher = conf.D.map, _ body: @escaping(E) throws -> U) -> Promise where U.T == T, E: Equatable { + let rp = Promise(.pending) + pipe { + switch $0 { + case .success(let value): + rp.box.seal(.success(value)) + case .failure(let error as E) where error == only: + on.dispatch { + do { + let rv = try body(error) + guard rv !== rp else { throw PMKError.returnedSelf } + rv.pipe(to: rp.box.seal) + } catch { + rp.box.seal(.failure(error)) + } + } + case .failure(let error): + rp.box.seal(.failure(error)) + } + } + return rp + } + + /** + The provided closure executes when this promise rejects with an error of the type passed in. + + Unlike `catch`, `recover` continues the chain. It can return a replacement promise or rethrow. + Use `recover` in circumstances where recovering the chain from certain errors is a possibility. For example: + + firstly { + API.fetchData() + }.recover(FetchError.self) { error in + guard case .missingImage(let partialData) = error else { throw error } + //… + return .value(dataWithDefaultImage) + } + + - Parameter only: The error type to be recovered (e.g., `PMKError`). + - Parameter on: The dispatcher that executes the provided closure. + - Parameter policy: The default policy does not execute your handler for cancellation errors. + - Parameter body: The handler to execute if this promise is rejected with the provided error type. + - SeeAlso: [Cancellation](http://promisekit.org/docs/) + */ + func recover(only: E.Type, on: Dispatcher = conf.D.map, policy: CatchPolicy = conf.catchPolicy, _ body: @escaping(E) throws -> U) -> Promise where U.T == T { + let rp = Promise(.pending) + pipe { + switch $0 { + case .success(let value): + rp.box.seal(.success(value)) + case .failure(let error as E): + if policy == .allErrors || !error.isCancelled { + on.dispatch { + do { + let rv = try body(error) + guard rv !== rp else { throw PMKError.returnedSelf } + rv.pipe(to: rp.box.seal) + } catch { + rp.box.seal(.failure(error)) + } + } + } else { + rp.box.seal(.failure(error)) + } + case .failure(let error): + rp.box.seal(.failure(error)) + } + } + return rp + } + + /** + The provided closure executes when this promise rejects. + This variant of `recover` requires the handler to return a Guarantee; your closure cannot `throw`. + + It is logically impossible for this variant to accept a `catchPolicy`. All errors will be presented + to your closure for processing. + + - Parameter on: The dispatcher that executes the provided closure. + - Parameter body: The handler to execute if this promise is rejected. + - SeeAlso: [Cancellation](https://github.com/mxcl/PromiseKit/blob/master/Documents/CommonPatterns.md#cancellation) + */ + @discardableResult + func recover(on: Dispatcher = conf.D.map, _ body: @escaping(Error) -> Guarantee) -> Guarantee { + let rg = Guarantee(.pending) + pipe { + switch $0 { + case .success(let value): + rg.box.seal(value) + case .failure(let error): + on.dispatch { + body(error).pipe(to: rg.box.seal) + } + } + } + return rg + } + + /** + The provided closure executes when this promise resolves, whether it rejects or not. + + firstly { + UIApplication.shared.networkActivityIndicatorVisible = true + }.done { + //… + }.ensure { + UIApplication.shared.networkActivityIndicatorVisible = false + }.catch { + //… + } + + - Parameter on: The dispatcher that executes the provided closure. + - Parameter body: The closure that executes when this promise resolves. + - Returns: A new promise, resolved with this promise’s resolution. + */ + func ensure(on: Dispatcher = conf.D.return, _ body: @escaping () -> Void) -> Promise { + let rp = Promise(.pending) + pipe { result in + on.dispatch { + body() + rp.box.seal(result) + } + } + return rp + } + + /** + The provided closure executes when this promise resolves, whether it rejects or not. + The chain waits on the returned `Guarantee`. + + firstly { + setup() + }.done { + //… + }.ensureThen { + teardown() // -> Guarante + }.catch { + //… + } + + - Parameter on: The dispatcher that executes the provided closure. + - Parameter body: The closure that executes when this promise resolves. + - Returns: A new promise, resolved with this promise’s resolution. + */ + func ensureThen(on: Dispatcher = conf.D.return, _ body: @escaping () -> Guarantee) -> Promise { + let rp = Promise(.pending) + pipe { result in + on.dispatch { + body().done { + rp.box.seal(result) + } + } + } + return rp + } + + + /** + Consumes the Swift unused-result warning. + - Note: You should `catch`, but in situations where you know you don’t need a `catch`, `cauterize` makes your intentions clear. + */ + @discardableResult + func cauterize() -> PMKFinalizer { + return self.catch { + conf.logHandler(.cauterized($0)) + } + } +} + + +public extension CatchMixin where T == Void { + + /** + The provided closure executes when this promise rejects. + + This variant of `recover` is specialized for `Void` promises and de-errors your chain, + returning a `Guarantee`. Thus, you cannot `throw` and you must handle all error types, + including cancellation. + + - Parameter on: The dispatcher that executes the provided closure. + - Parameter body: The handler to execute if this promise is rejected. + - SeeAlso: [Cancellation](https://github.com/mxcl/PromiseKit/blob/master/Documents/CommonPatterns.md#cancellation) + */ + @discardableResult + func recover(on: Dispatcher = conf.D.map, _ body: @escaping(Error) -> Void) -> Guarantee { + let rg = Guarantee(.pending) + pipe { + switch $0 { + case .success: + rg.box.seal(()) + case .failure(let error): + on.dispatch { + body(error) + rg.box.seal(()) + } + } + } + return rg + } + + /** + The provided closure executes when this promise rejects. + + This variant of `recover` ensures that no error is thrown from the handler + and allows you to specify a catch policy. + + - Parameter on: The dispatcher that executes the provided closure. + - Parameter body: The handler to execute if this promise is rejected. + - SeeAlso: [Cancellation](https://github.com/mxcl/PromiseKit/blob/master/Documents/CommonPatterns.md#cancellation) + */ + func recover(on: Dispatcher = conf.D.map, policy: CatchPolicy = conf.catchPolicy, _ body: @escaping(Error) throws -> Void) -> Promise { + let rg = Promise(.pending) + pipe { + switch $0 { + case .success: + rg.box.seal(.success(())) + case .failure(let error): + if policy == .allErrors || !error.isCancelled { + on.dispatch { + do { + rg.box.seal(.success(try body(error))) + } catch { + rg.box.seal(.failure(error)) + } + } + } else { + rg.box.seal(.failure(error)) + } + } + } + return rg + } + + /** + The provided closure executes when this promise rejects with the specific error passed in. + + Unlike `catch`, `recover` continues the chain. It can return a replacement promise or rethrow. + Use `recover` in circumstances where recovering the chain from certain errors is a possibility. + + - Parameter only: The specific error to be recovered (e.g., `PMKError.emptySequence`) + - Parameter on: The dispatcher that executes the provided closure. + - Parameter body: The handler to execute if this promise is rejected with the provided error. + - Note: Since this method recovers only specific errors, supplying a `CatchPolicy` is unsupported. + - SeeAlso: [Cancellation](http://promisekit.org/docs/) + */ + func recover(only: E, on: Dispatcher = conf.D.map, _ body: @escaping(E) throws -> Void) -> Promise where E: Equatable { + let rp = Promise(.pending) + pipe { + switch $0 { + case .success: + rp.box.seal(.success(())) + case .failure(let error as E) where error == only: + on.dispatch { + do { + rp.box.seal(.success(try body(error))) + } catch { + rp.box.seal(.failure(error)) + } + } + case .failure(let error): + rp.box.seal(.failure(error)) + } + } + return rp + } + + /** + The provided closure executes when this promise rejects with an error of the type passed in. + + Unlike `catch`, `recover` continues the chain. It can return a replacement promise or rethrow. + Use `recover` in circumstances where recovering the chain from certain errors is a possibility. + + - Parameter only: The error type to be recovered (e.g., `PMKError`). + - Parameter on: The dispatcher that executes the provided closure. + - Parameter policy: The default policy does not execute your handler for cancellation errors. + - Parameter body: The handler to execute if this promise is rejected with the provided error type. + - SeeAlso: [Cancellation](http://promisekit.org/docs/) + */ + func recover(only: E.Type, on: Dispatcher = conf.D.map, policy: CatchPolicy = conf.catchPolicy, _ body: @escaping(E) throws -> Void) -> Promise { + let rp = Promise(.pending) + pipe { + switch $0 { + case .success: + rp.box.seal(.success(())) + case .failure(let error as E): + if policy == .allErrors || !error.isCancelled { + on.dispatch { + do { + rp.box.seal(.success(try body(error))) + } catch { + rp.box.seal(.failure(error)) + } + } + } else { + rp.box.seal(.failure(error)) + } + case .failure(let error): + rp.box.seal(.failure(error)) + } + } + return rp + } +} diff --git a/Sources/Configuration.swift b/Sources/PromiseKit/Configuration.swift similarity index 55% rename from Sources/Configuration.swift rename to Sources/PromiseKit/Configuration.swift index 4db523237..b9ff7b6c8 100644 --- a/Sources/Configuration.swift +++ b/Sources/PromiseKit/Configuration.swift @@ -8,26 +8,27 @@ import Dispatch We would like it to be, but sadly `Swift` does not expose `dispatch_once` et al. which is what we used to use in order to make the configuration immutable once first used. */ public struct PMKConfiguration { - /// The default queues that promises handlers dispatch to - public var Q: (map: DispatchQueue?, return: DispatchQueue?) = (map: DispatchQueue.main, return: DispatchQueue.main) + /// Backward compatibility: the default Dispatcher to which handlers dispatch, represented as DispatchQueues. + public var Q: (map: DispatchQueue?, return: DispatchQueue?) { + get { + let convertedMap = D.map is CurrentThreadDispatcher ? nil : D.map as? DispatchQueue + let convertedReturn = D.return is CurrentThreadDispatcher ? nil : D.return as? DispatchQueue + return (map: convertedMap, return: convertedReturn) + } + set { D = (map: newValue.map ?? CurrentThreadDispatcher(), return: newValue.return ?? CurrentThreadDispatcher()) } + } + + /// The default Dispatchers to which promise handlers dispatch + public var D: (map: Dispatcher, return: Dispatcher) = (map: DispatchQueue.main, return: DispatchQueue.main) /// The default catch-policy for all `catch` and `resolve` public var catchPolicy = CatchPolicy.allErrorsExceptCancellation - + /// The closure used to log PromiseKit events. /// Not thread safe; change before processing any promises. /// - Note: The default handler calls `print()` public var logHandler: (LogEvent) -> Void = { event in - switch event { - case .waitOnMainThread: - print("PromiseKit: warning: `wait()` called on main thread!") - case .pendingPromiseDeallocated: - print("PromiseKit: warning: pending promise deallocated") - case .pendingGuaranteeDeallocated: - print("PromiseKit: warning: pending guarantee deallocated") - case .cauterized (let error): - print("PromiseKit:cauterized-error: \(error)") - } + print("PromiseKit:", event.description) } } diff --git a/Sources/PromiseKit/CustomStringConvertible.swift b/Sources/PromiseKit/CustomStringConvertible.swift new file mode 100644 index 000000000..56a1822e7 --- /dev/null +++ b/Sources/PromiseKit/CustomStringConvertible.swift @@ -0,0 +1,28 @@ + +extension Promise: CustomStringConvertible { + /// - Returns: A description of the state of this promise. + public var description: String { + switch result { + case nil: + return "Promise(…\(T.self))" + case .failure(let error)?: + return "Promise(\(error))" + case .success(let value)?: + return "Promise(\(value))" + } + } +} + +extension Promise: CustomDebugStringConvertible { + /// - Returns: A debug-friendly description of the state of this promise. + public var debugDescription: String { + switch box.inspect() { + case .pending(let handlers): + return "Promise<\(T.self)>.pending(handlers: \(handlers.bodies.count))" + case .resolved(.failure(let error)): + return "Promise<\(T.self)>.failure(\(type(of: error)).\(error))" + case .resolved(.success(let value)): + return "Promise<\(T.self)>.success(\(value))" + } + } +} diff --git a/Sources/PromiseKit/Dispatcher.swift b/Sources/PromiseKit/Dispatcher.swift new file mode 100644 index 000000000..e27d92220 --- /dev/null +++ b/Sources/PromiseKit/Dispatcher.swift @@ -0,0 +1,120 @@ +import Dispatch + +/// A `PromiseKit` abstraction of a `DispatchQueue` that allows for a more +/// flexible variety of implementations. (For technical reasons, +/// `DispatchQueue` itself cannot be subclassed.) +/// +/// `Dispatcher`s define a `dispatch` method that executes a supplied closure. +/// Execution may be synchronous or asynchronous, serial +/// or concurrent, and can occur on any thread. +/// +/// All `DispatchQueue`s are also valid `Dispatcher`s. + +public protocol Dispatcher { + func dispatch(_ body: @escaping () -> Void) +} + +/// A `Dispatcher` that bundles a `DispatchQueue` with +/// a `DispatchGroup`, a set of `DispatchWorkItemFlags`, and a +/// quality-of-service level. Closures dispatched through this +/// `Dispatcher` will be submitted to the underlying `DispatchQueue` +/// with the supplied components. + +public struct DispatchQueueDispatcher: Dispatcher { + + let queue: DispatchQueue + let group: DispatchGroup? + let qos: DispatchQoS? + let flags: DispatchWorkItemFlags? + + public init(queue: DispatchQueue, group: DispatchGroup? = nil, qos: DispatchQoS? = nil, flags: DispatchWorkItemFlags? = nil) { + self.queue = queue + self.group = group + self.qos = qos + self.flags = flags + } + + public func dispatch(_ body: @escaping () -> Void) { + queue.asyncD(group: group, qos: qos, flags: flags, execute: body) + } +} + +/// A `Dispatcher` class that executes all closures synchronously on +/// the current thread. +/// +/// Useful for temporarily disabling asynchrony and +/// multithreading while debugging `PromiseKit` chains. +/// +/// You can set `PromiseKit`'s default dispatching behavior to this mode +/// by setting `conf.Q.map` and/or `conf.Q.return` to `nil`. (This is the +/// same as assigning an instance of `CurrentThreadDispatcher` to these +/// variables.) + +public struct CurrentThreadDispatcher: Dispatcher { + public func dispatch(_ body: () -> Void) { + body() + } +} + +extension DispatchQueue: Dispatcher { + public func dispatch(_ body: @escaping () -> Void) { + async(execute: body) + } +} + +// Used as default parameter for backward compatibility since clients may explicitly +// specify "nil" to turn off dispatching. We need to distinguish three cases: explicit +// queue, explicit nil, and no value specified. Dispatchers from conf.D cannot directly +// be used as default parameter values because they are not necessarily DispatchQueues. + +public extension DispatchQueue { + static var pmkDefault = DispatchQueue(label: "org.promisekit.sentinel") +} + +public extension DispatchQueue { + /// Converts a `DispatchQueue` with given dispatching parameters into a `Dispatcher` + func asDispatcher(group: DispatchGroup? = nil, qos: DispatchQoS? = nil, flags: DispatchWorkItemFlags? = nil) -> Dispatcher { + if group == nil && qos == nil && flags == nil { + return self + } + return DispatchQueueDispatcher(queue: self, group: group, qos: qos, flags: flags) + } +} + +// Avoid having to hard-code any particular defaults for qos or flags +internal extension DispatchQueue { + final func asyncD(group: DispatchGroup? = nil, qos: DispatchQoS? = nil, flags: DispatchWorkItemFlags? = nil, execute body: @escaping () -> Void) { + switch (qos, flags) { + case (nil, nil): + async(group: group, execute: body) + case (nil, let flags?): + async(group: group, flags: flags, execute: body) + case (let qos?, nil): + async(group: group, qos: qos, execute: body) + case (let qos?, let flags?): + async(group: group, qos: qos, flags: flags, execute: body) + } + } +} + +// This hairball disambiguates all the various combinations of explicit arguments, default +// arguments, and configured defaults. In particular, a method that is given explicit work item +// flags but no DispatchQueue should still work (that is, the dispatcher should use those flags) +// as long as the configured default is actually some kind of DispatchQueue. + +internal func selectDispatcher(given: DispatchQueue?, configured: Dispatcher, flags: DispatchWorkItemFlags?) -> Dispatcher { + guard let given = given else { + if flags != nil { + conf.logHandler(.nilDispatchQueueWithFlags) + } + return CurrentThreadDispatcher() + } + if given !== DispatchQueue.pmkDefault { + return given.asDispatcher(flags: flags) + } else if let flags = flags, let configured = configured as? DispatchQueue { + return configured.asDispatcher(flags: flags) + } else if flags != nil { + conf.logHandler(.extraneousFlagsSpecified) + } + return configured +} diff --git a/Sources/PromiseKit/Dispatchers/ConcurrencyLimitedDispatcher.swift b/Sources/PromiseKit/Dispatchers/ConcurrencyLimitedDispatcher.swift new file mode 100644 index 000000000..fe7eadbe0 --- /dev/null +++ b/Sources/PromiseKit/Dispatchers/ConcurrencyLimitedDispatcher.swift @@ -0,0 +1,41 @@ +import Foundation + +/// A PromiseKit Dispatcher that allows no more than X simultaneous +/// executions at once. + +public final class ConcurrencyLimitedDispatcher: Dispatcher { + + let queue: Dispatcher + let serializer: DispatchQueue = DispatchQueue(label: "CLD serializer") + + let semaphore: DispatchSemaphore + + /// A `PromiseKit` `Dispatcher` that allows no more than X simultaneous + /// executions at once. + /// + /// - Parameters: + /// - limit: The number of executions that may run at once. + /// - queue: The DispatchQueue or Dispatcher on which to perform executions. + /// Should be some form of concurrent queue. + + public init(limit: Int, queue: Dispatcher = DispatchQueue.global(qos: .background)) { + self.queue = queue + semaphore = DispatchSemaphore(value: limit) + } + + public convenience init(limit: Int, queue: DispatchQueue) { + self.init(limit: limit, queue: queue as Dispatcher) + } + + public func dispatch(_ body: @escaping () -> Void) { + serializer.async { + self.semaphore.wait() + self.queue.dispatch { + body() + self.semaphore.signal() + } + } + } + +} + diff --git a/Sources/PromiseKit/Dispatchers/CoreDataDispatcher.swift b/Sources/PromiseKit/Dispatchers/CoreDataDispatcher.swift new file mode 100644 index 000000000..e3630172c --- /dev/null +++ b/Sources/PromiseKit/Dispatchers/CoreDataDispatcher.swift @@ -0,0 +1,30 @@ +#if canImport(CoreData) + +import Foundation +import CoreData + +public extension NSManagedObjectContext { + var dispatcher: CoreDataDispatcher { + return CoreDataDispatcher(self) + } +} + +/// A `Dispatcher` that dispatches onto the threads associated with +/// `NSManagedObjectContext`s, allowing Core Data operations to be +/// handled using promises. + +public struct CoreDataDispatcher: Dispatcher { + + let context: NSManagedObjectContext + + public init(_ context: NSManagedObjectContext) { + self.context = context + } + + public func dispatch(_ body: @escaping () -> Void) { + context.perform(body) + } + +} + +#endif diff --git a/Sources/PromiseKit/Dispatchers/Queue.swift b/Sources/PromiseKit/Dispatchers/Queue.swift new file mode 100644 index 000000000..53931c7ae --- /dev/null +++ b/Sources/PromiseKit/Dispatchers/Queue.swift @@ -0,0 +1,64 @@ +import Foundation + +// Simple queue implementation with storage recovery + +fileprivate let arraySizeWorthCompacting = 100 +fileprivate let minUtilization = 0.6 + +struct Queue { + + var elements: [T?] = [] + var head = 0 + let maxDepth: Int? + + init(maxDepth: Int? = nil) { + self.maxDepth = maxDepth + } + + var isEmpty: Bool { + return head >= elements.count + } + + var count: Int { + return elements.count - head + } + + mutating func enqueue(_ item: T) { + elements.append(item) + if let maxDepth = maxDepth, count > maxDepth { + _ = dequeue() + } + } + + mutating func dequeue() -> T { + assert(!isEmpty, "Dequeue attempt on an empty Queue") + defer { + elements[head] = nil + head += 1 + maybeCompactStorage() + } + return elements[head]! + } + + private mutating func maybeCompactStorage() { + let n = elements.count + if n > arraySizeWorthCompacting && head > Int(Double(n) * (1 - minUtilization)) { + compactStorage() + } + } + + mutating func compactStorage() { + if isEmpty { + elements.removeAll(keepingCapacity: false) + } else { + elements.removeFirst(head) + } + head = 0 + } + + mutating func purge() { + elements.removeAll(keepingCapacity: false) + head = 0 + } + +} diff --git a/Sources/PromiseKit/Dispatchers/RateLimitedDispatcher.swift b/Sources/PromiseKit/Dispatchers/RateLimitedDispatcher.swift new file mode 100644 index 000000000..abbe12ad3 --- /dev/null +++ b/Sources/PromiseKit/Dispatchers/RateLimitedDispatcher.swift @@ -0,0 +1,110 @@ +import Foundation + +/// A `PromiseKit` `Dispatcher` that dispatches X closures every Y seconds, +/// on average. +/// +/// This implementation is O(1) in both space and time, but it uses approximate +/// time accounting. Over the long term, the rate converges to a rate of X/Y, +/// but the transient burst rate will be up to 2X/Y in some situations. +/// +/// For a completely accurate rate limiter that dispatches as rapidly as +/// possible, see `StrictRateLimitedDispatcher`. That implementation requires +/// additional storage. +/// +/// Executions are paced by start time, not by completion, so it's possible to +/// end up with more than X closures running concurrently in some circumstances. +/// +/// There is no guarantee that you will reach a given dispatch rate. There are not +/// an infinite number of threads available, and GCD scheduling has limited accuracy. +/// +/// 100% thread safe. + +public final class RateLimitedDispatcher: RateLimitedDispatcherBase { + + private var tokensInBucket: Double = 0 + private var latestAccrual: DispatchTime = DispatchTime.now() + private var retryWorkItem: DispatchWorkItem? { willSet { retryWorkItem?.cancel() }} + + private var tokensPerSecond: Double { return Double(maxDispatches) / interval } + + /// A `PromiseKit` `Dispatcher` that dispatches X executions every Y + /// seconds, on average. + /// + /// This version is O(1) in space and time but uses an approximate algorithm with + /// burst rates up to 2X per Y seconds. For a more accurate implementation, use + /// `StrictRateLimitedDispatcher`. + /// + /// - Parameters: + /// - maxDispatches: The number of executions that may be dispatched within a given interval. + /// - perInterval: The length of the reference interval, in seconds. + /// - queue: The DispatchQueue or Dispatcher on which to perform executions. May be serial or concurrent. + + override public init(maxDispatches: Int, perInterval interval: TimeInterval, queue: Dispatcher = DispatchQueue.global()) { + latestAccrual = DispatchTime.now() + super.init(maxDispatches: maxDispatches, perInterval: interval, queue: queue) + tokensInBucket = Double(maxDispatches) + } + + public convenience init(maxDispatches: Int, perInterval interval: TimeInterval, queue: DispatchQueue) { + self.init(maxDispatches: maxDispatches, perInterval: interval, queue: queue as Dispatcher) + } + + override func dispatchFromQueue() { + + guard undispatched.count > 0 else { return } + cleanupNonce += 1 + + let now = DispatchTime.now() + let tokensToAdd = (now - latestAccrual) * tokensPerSecond + tokensInBucket = min(Double(maxDispatches - nDispatched), tokensInBucket + tokensToAdd) + latestAccrual = now + + // print("runqueue \(now.rawValue), nDispatched = \(nDispatched), tokens = \(tokensInBucket), undispatched = \(undispatched.count)") + + var didDispatch = false + while tokensInBucket >= 1.0 && !undispatched.isEmpty && nDispatched < maxDispatches { + didDispatch = true + tokensInBucket -= 1.0 + nDispatched += 1 + let body = undispatched.dequeue() + queue.dispatch { + self.serializer.async { + self.recordActualStart() + } + body() + } + } + + if !didDispatch { + scheduleRetry() + } + + } + + private func scheduleRetry() { + guard retryWorkItem == nil && !undispatched.isEmpty && nDispatched < maxDispatches else { return } + let tokenDeficit = 1 - tokensInBucket + let secondsToGo = tokenDeficit / tokensPerSecond + let deadline = latestAccrual + secondsToGo + 1.0E-6 + retryWorkItem = DispatchWorkItem { [weak self] in + self?.retryWorkItem = nil + self?.dispatchFromQueue() + } + serializer.asyncAfter(deadline: deadline, execute: retryWorkItem!) + } + + override func cleanup(_ nonce: Int64) { + super.cleanup(nonce) + guard nonce == cleanupNonce else { return } + tokensInBucket = Double(maxDispatches) // Avoid accumulating roundoff errors + } + +} + +extension DispatchTime { + static func -(a: DispatchTime, b: DispatchTime) -> TimeInterval { + let delta = a.uptimeNanoseconds - b.uptimeNanoseconds + return TimeInterval(delta) / 1_000_000_000 + } +} + diff --git a/Sources/PromiseKit/Dispatchers/RateLimitedDispatcherBase.swift b/Sources/PromiseKit/Dispatchers/RateLimitedDispatcherBase.swift new file mode 100644 index 000000000..c43b80cc4 --- /dev/null +++ b/Sources/PromiseKit/Dispatchers/RateLimitedDispatcherBase.swift @@ -0,0 +1,57 @@ +import Foundation + +public class RateLimitedDispatcherBase: Dispatcher { + + let maxDispatches: Int + let interval: TimeInterval + let queue: Dispatcher + + let serializer = DispatchQueue(label: "RLD serializer") + + var nDispatched = 0 + var undispatched = Queue<() -> Void>() + + var cleanupNonce: Int64 = 0 + var cleanupWorkItem: DispatchWorkItem? { willSet { cleanupWorkItem?.cancel() }} + + public init(maxDispatches: Int, perInterval interval: TimeInterval, queue: Dispatcher = DispatchQueue.global()) { + self.maxDispatches = maxDispatches + self.interval = interval + self.queue = queue + } + + public func dispatch(_ body: @escaping () -> Void) { + serializer.async { + self.undispatched.enqueue(body) + self.dispatchFromQueue() + } + } + + func dispatchFromQueue() { + fatalError("Subclass responsibility") + } + + func recordActualStart() { + nDispatched -= 1 + dispatchFromQueue() + if nDispatched == 0 && undispatched.isEmpty { + scheduleCleanup() + } + } + + func scheduleCleanup() { + cleanupWorkItem = DispatchWorkItem { [ weak self, nonce = self.cleanupNonce ] in + self?.cleanup(nonce) + } + serializer.asyncAfter(deadline: DispatchTime.now() + interval, execute: cleanupWorkItem!) + } + + func cleanup(_ nonce: Int64) { + // Calls to cleanup() have to go through the serializer queue, so by by the time + // we get here, more activity may have occurred. Ergo, verify nonce. + guard nonce == cleanupNonce else { return } + undispatched.compactStorage() + cleanupWorkItem = nil + } + +} diff --git a/Sources/PromiseKit/Dispatchers/StrictRateLimitedDispatcher.swift b/Sources/PromiseKit/Dispatchers/StrictRateLimitedDispatcher.swift new file mode 100644 index 000000000..2a2883d26 --- /dev/null +++ b/Sources/PromiseKit/Dispatchers/StrictRateLimitedDispatcher.swift @@ -0,0 +1,106 @@ +import Foundation + +/// A `PromiseKit` `Dispatcher` that dispatches no more than X closures every Y +/// seconds. This is a sliding window, so executions occur as rapidly as +/// possible without exceeding X in any Y-second period. +/// +/// This version implements perfectly accurate timing, so it must (temporarily) +/// track up to X previous execution times and is thus O(X) in space. +/// +/// For a "pretty good" approach to rate limiting that does not consume +/// additional storage, see `RateLimitedDispatcher`. +/// +/// Executions are paced by start time, not by completion, so it's possible to +/// end up with more than X closures running concurrently in some circumstances. +/// +/// There is no guarantee that you will reach a given dispatch rate. There are not +/// an infinite number of threads available, and GCD scheduling has limited accuracy. +/// The only guarantee is that dispatching will never exceed the requested rate. +/// +/// 100% thread safe. + +public final class StrictRateLimitedDispatcher: RateLimitedDispatcherBase { + + internal var startTimeHistory: Queue + private var immediateDispatchesAvailable: Int + private var latestDeadline = DispatchTime(uptimeNanoseconds: 0) + + /// A `PromiseKit` `Dispatcher` that dispatches no more than X executions every Y + /// seconds. This is a sliding window, so executions occur as rapidly as + /// possible without exceeding X in any Y-second period. O(X) in space. + /// + /// For a "pretty good" approach to rate limiting that does not consume + /// additional storage, see `RateLimitedDispatcher`. + /// + /// - Parameters: + /// - maxDispatches: The number of executions that may be dispatched within a given interval. + /// - perInterval: The length of the reference interval, in seconds. + /// - queue: The DispatchQueue or Dispatcher on which to perform executions. May be serial or concurrent. + + override public init(maxDispatches: Int, perInterval interval: TimeInterval, queue: Dispatcher = DispatchQueue.global()) { + startTimeHistory = Queue(maxDepth: maxDispatches) + immediateDispatchesAvailable = maxDispatches + super.init(maxDispatches: maxDispatches, perInterval: interval, queue: queue) + } + + public convenience init(maxDispatches: Int, perInterval interval: TimeInterval, queue: DispatchQueue) { + self.init(maxDispatches: maxDispatches, perInterval: interval, queue: queue as Dispatcher) + } + + override func dispatchFromQueue() { + + cleanupNonce += 1 + + guard nDispatched < maxDispatches else { return } + guard !undispatched.isEmpty else { return } + + let accountedFor = nDispatched + startTimeHistory.count + immediateDispatchesAvailable + assert(accountedFor == maxDispatches, "Dispatcher bookkeeping problem") + + var deadline = DispatchTime.now() + if immediateDispatchesAvailable > 0 { + immediateDispatchesAvailable -= 1 + } else { + // Use the start time of a previous closure as a time reference. In practice, + // past start times will normally be reported and recorded in monotonically + // increasing sequence, which yields optimal scheduling. However, this is all + // potentially multithreaded, so there are no order guarantees. However, if any + // start times ARE out of order, the algorithm is still correct: for each + // dispatched item, another may be scheduled interval seconds later. Like kanban. + deadline = max(deadline, startTimeHistory.dequeue() + interval) + } + // Enforce a monotonically increasing outbound schedule to keep calls in order + if deadline <= latestDeadline { + deadline = DispatchTime(uptimeNanoseconds: latestDeadline.uptimeNanoseconds + 1) + } + + let body = undispatched.dequeue() + // A Dispatcher has no asyncAfter; use the serializer queue for timing + serializer.asyncAfter(deadline: deadline) { + self.queue.dispatch { + let now = DispatchTime.now() + self.serializer.async { + self.recordActualStartTime(now) + } + body() + } + } + + latestDeadline = deadline + nDispatched += 1 + + } + + private func recordActualStartTime(_ time: DispatchTime) { + startTimeHistory.enqueue(time) + super.recordActualStart() + } + + override func cleanup(_ nonce: Int64) { + super.cleanup(nonce) + guard nonce == cleanupNonce else { return } + startTimeHistory.purge() // We're at least an interval past last start + immediateDispatchesAvailable = maxDispatches + } + +} diff --git a/Sources/Error.swift b/Sources/PromiseKit/Error.swift similarity index 94% rename from Sources/Error.swift rename to Sources/PromiseKit/Error.swift index be22f6b4b..05349c472 100644 --- a/Sources/Error.swift +++ b/Sources/PromiseKit/Error.swift @@ -18,7 +18,10 @@ public enum PMKError: Error { /// The operation was cancelled case cancelled - + + /// The operation timed out and was cancelled + case timedOut + /// `nil` was returned from `flatMap` @available(*, deprecated, message: "See: `compactMap`") case flatMap(Any, Any.Type) @@ -52,6 +55,8 @@ extension PMKError: CustomDebugStringConvertible { return "Bad input was provided to a PromiseKit function" case .cancelled: return "The asynchronous sequence was cancelled" + case .timedOut: + return "The asynchronous sequence timed out" case .emptySequence: return "The first or last element was requested for an empty sequence" case .noWinner: @@ -81,6 +86,8 @@ extension Error { throw self } catch PMKError.cancelled { return true + } catch PMKError.timedOut { + return true } catch let error as CancellableError { return error.isCancelled } catch URLError.cancelled { diff --git a/Sources/Guarantee.swift b/Sources/PromiseKit/Guarantee.swift similarity index 66% rename from Sources/Guarantee.swift rename to Sources/PromiseKit/Guarantee.swift index ce887cdc3..21901d8bb 100644 --- a/Sources/Guarantee.swift +++ b/Sources/PromiseKit/Guarantee.swift @@ -23,9 +23,15 @@ public final class Guarantee: Thenable { body(box.seal) } + /// Returns a pending `Guarantee` that can be resolved with the provided closure’s parameter. + public convenience init(cancellable: Cancellable, resolver body: (@escaping(T) -> Void) -> Void) { + self.init(resolver: body) + setCancellable(cancellable) + } + /// - See: `Thenable.pipe` - public func pipe(to: @escaping(Result) -> Void) { - pipe{ to(.fulfilled($0)) } + public func pipe(to: @escaping(Result) -> Void) { + pipe{ to(.success($0)) } } func pipe(to: @escaping(T) -> Void) { @@ -45,20 +51,23 @@ public final class Guarantee: Thenable { } /// - See: `Thenable.result` - public var result: Result? { + public var result: Result? { switch box.inspect() { case .pending: return nil case .resolved(let value): - return .fulfilled(value) + return .success(value) } } final private class Box: EmptyBox { + var cancelled = false deinit { switch inspect() { case .pending: - PromiseKit.conf.logHandler(.pendingGuaranteeDeallocated) + if !cancelled { + PromiseKit.conf.logHandler(.pendingGuaranteeDeallocated) + } case .resolved: break } @@ -73,55 +82,72 @@ public final class Guarantee: Thenable { public class func pending() -> (guarantee: Guarantee, resolve: (T) -> Void) { return { ($0, $0.box.seal) }(Guarantee(.pending)) } + + var cancellable: Cancellable? + + public func setCancellable(_ cancellable: Cancellable) { + if let gb = (box as? Guarantee.Box) { + self.cancellable = CancellableWrapper(box: gb, cancellable: cancellable) + } else { + self.cancellable = cancellable + } + } + + final private class CancellableWrapper: Cancellable { + let box: Guarantee.Box + let cancellable: Cancellable + + init(box: Guarantee.Box, cancellable: Cancellable) { + self.box = box + self.cancellable = cancellable + } + + func cancel() { + box.cancelled = true + cancellable.cancel() + } + + var isCancelled: Bool { + return cancellable.isCancelled + } + } } public extension Guarantee { @discardableResult - func done(on: DispatchQueue? = conf.Q.return, flags: DispatchWorkItemFlags? = nil, _ body: @escaping(T) -> Void) -> Guarantee { + func done(on: Dispatcher = conf.D.return, _ body: @escaping(T) -> Void) -> Guarantee { let rg = Guarantee(.pending) pipe { (value: T) in - on.async(flags: flags) { + on.dispatch { body(value) rg.box.seal(()) } } return rg } - - func get(on: DispatchQueue? = conf.Q.return, flags: DispatchWorkItemFlags? = nil, _ body: @escaping (T) -> Void) -> Guarantee { - return map(on: on, flags: flags) { + + func get(on: Dispatcher = conf.D.return, _ body: @escaping (T) -> Void) -> Guarantee { + return map(on: on) { body($0) return $0 } } - func map(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ body: @escaping(T) -> U) -> Guarantee { + func map(on: Dispatcher = conf.D.map, _ body: @escaping(T) -> U) -> Guarantee { let rg = Guarantee(.pending) pipe { value in - on.async(flags: flags) { + on.dispatch { rg.box.seal(body(value)) } } return rg } - #if swift(>=4) && !swift(>=5.2) - func map(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ keyPath: KeyPath) -> Guarantee { + @discardableResult + func then(on: Dispatcher = conf.D.map, _ body: @escaping(T) -> Guarantee) -> Guarantee { let rg = Guarantee(.pending) pipe { value in - on.async(flags: flags) { - rg.box.seal(value[keyPath: keyPath]) - } - } - return rg - } - #endif - - @discardableResult - func then(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ body: @escaping(T) -> Guarantee) -> Guarantee { - let rg = Guarantee(.pending) - pipe { value in - on.async(flags: flags) { + on.dispatch { body(value).pipe(to: rg.box.seal) } } @@ -131,7 +157,7 @@ public extension Guarantee { func asVoid() -> Guarantee { return map(on: nil) { _ in } } - + /** Blocks this thread, so you know, don’t call this on a serial thread that any part of your chain may use. Like the main thread for example. @@ -150,7 +176,7 @@ public extension Guarantee { pipe { (foo: T) in result = foo; group.leave() } group.wait() } - + return result! } } @@ -169,21 +195,6 @@ public extension Guarantee where T: Sequence { return map(on: on, flags: flags) { $0.map(transform) } } - #if swift(>=4) && !swift(>=5.2) - /** - `Guarantee<[T]>` => `KeyPath` => `Guarantee<[U]>` - - Guarantee.value([Person(name: "Max"), Person(name: "Roman"), Person(name: "John")]) - .mapValues(\.name) - .done { - // $0 => ["Max", "Roman", "John"] - } - */ - func mapValues(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ keyPath: KeyPath) -> Guarantee<[U]> { - return map(on: on, flags: flags) { $0.map { $0[keyPath: keyPath] } } - } - #endif - /** `Guarantee<[T]>` => `T` -> `[U]` => `Guarantee<[U]>` @@ -218,29 +229,8 @@ public extension Guarantee where T: Sequence { } } - #if swift(>=4) && !swift(>=5.2) /** - `Guarantee<[T]>` => `KeyPath` => `Guarantee<[U]>` - - Guarantee.value([Person(name: "Max"), Person(name: "Roman", age: 26), Person(name: "John", age: 23)]) - .compactMapValues(\.age) - .done { - // $0 => [26, 23] - } - */ - func compactMapValues(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ keyPath: KeyPath) -> Guarantee<[U]> { - return map(on: on, flags: flags) { foo -> [U] in - #if !swift(>=4.1) - return foo.flatMap { $0[keyPath: keyPath] } - #else - return foo.compactMap { $0[keyPath: keyPath] } - #endif - } - } - #endif - - /** - `Guarantee<[T]>` => `T` -> `Guarantee` => `Guaranetee<[U]>` + `Guarantee<[T]>` => `T` -> `Guarantee` => `Guarantee<[U]>` Guarantee.value([1,2,3]) .thenMap { .value($0 * 2) } @@ -248,8 +238,8 @@ public extension Guarantee where T: Sequence { // $0 => [2,4,6] } */ - func thenMap(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ transform: @escaping(T.Iterator.Element) -> Guarantee) -> Guarantee<[U]> { - return then(on: on, flags: flags) { + func thenMap(on: Dispatcher = conf.D.map, _ transform: @escaping(T.Iterator.Element) -> Guarantee) -> Guarantee<[U]> { + return then(on: on) { when(fulfilled: $0.map(transform)) }.recover { // if happens then is bug inside PromiseKit @@ -292,23 +282,6 @@ public extension Guarantee where T: Sequence { } } - #if swift(>=4) && !swift(>=5.2) - /** - `Guarantee<[T]>` => `KeyPath` => `Guarantee<[T]>` - - Guarantee.value([Person(name: "Max"), Person(name: "Roman", age: 26, isStudent: false), Person(name: "John", age: 23, isStudent: true)]) - .filterValues(\.isStudent) - .done { - // $0 => [Person(name: "John", age: 23, isStudent: true)] - } - */ - func filterValues(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ keyPath: KeyPath) -> Guarantee<[T.Iterator.Element]> { - return map(on: on, flags: flags) { - $0.filter { $0[keyPath: keyPath] } - } - } - #endif - /** `Guarantee<[T]>` => (`T`, `T`) -> Bool => `Guarantee<[T]>` @@ -340,7 +313,6 @@ public extension Guarantee where T: Sequence, T.Iterator.Element: Comparable { } } -#if swift(>=3.1) public extension Guarantee where T == Void { convenience init() { self.init(box: SealedBox(value: Void())) @@ -349,13 +321,19 @@ public extension Guarantee where T == Void { static var value: Guarantee { return .value(Void()) } -} -#endif + convenience init(resolver body: (@escaping() -> Void) -> Void) { + self.init(resolver: { seal in + body { + seal(()) + } + }) + } +} public extension DispatchQueue { /** - Asynchronously executes the provided closure on a dispatch queue. + Asynchronously executes the provided closure on a dispatch queue, yielding a `Guarantee`. DispatchQueue.global().async(.promise) { md5(input) @@ -363,28 +341,42 @@ public extension DispatchQueue { //… } - - Parameter body: The closure that resolves this promise. + - _: Must be `.promise` to distinguish from standard `DispatchQueue.async` + - group: A `DispatchGroup`, as for standard `DispatchQueue.async` + - qos: A quality-of-service grade, as for standard `DispatchQueue.async` + - flags: Work item flags, as for standard `DispatchQueue.async` + - body: A closure that yields a value to resolve the guarantee. - Returns: A new `Guarantee` resolved by the result of the provided closure. - - Note: There is no Promise/Thenable version of this due to Swift compiler ambiguity issues. */ @available(macOS 10.10, iOS 2.0, tvOS 10.0, watchOS 2.0, *) - final func async(_: PMKNamespacer, group: DispatchGroup? = nil, qos: DispatchQoS = .default, flags: DispatchWorkItemFlags = [], execute body: @escaping () -> T) -> Guarantee { + final func async(_: PMKNamespacer, group: DispatchGroup? = nil, qos: DispatchQoS? = nil, flags: DispatchWorkItemFlags? = nil, execute body: @escaping () -> T) -> Guarantee { let rg = Guarantee(.pending) - async(group: group, qos: qos, flags: flags) { + asyncD(group: group, qos: qos, flags: flags) { rg.box.seal(body()) } return rg } } +public extension Dispatcher { + /** + Executes the provided closure on a `Dispatcher`, yielding a `Guarantee` + that represents the value ultimately returned by the closure. -#if os(Linux) -import func CoreFoundation._CFIsMainThread + dispatcher.dispatch { + md5(input) + }.done { md5 in + //… + } -extension Thread { - // `isMainThread` is not implemented yet in swift-corelibs-foundation. - static var isMainThread: Bool { - return _CFIsMainThread() + - Parameter body: The closure that yields the value of the Guarantee. + - Returns: A new `Guarantee` resolved by the result of the provided closure. + */ + func dispatch(_ body: @escaping () -> T) -> Guarantee { + let rg = Guarantee(.pending) + dispatch { + rg.box.seal(body()) + } + return rg } } -#endif diff --git a/Sources/PromiseKit/LogEvent.swift b/Sources/PromiseKit/LogEvent.swift new file mode 100644 index 000000000..9d46526c0 --- /dev/null +++ b/Sources/PromiseKit/LogEvent.swift @@ -0,0 +1,55 @@ +/** + The PromiseKit events which may be logged. + + ```` + /// A promise or guarantee has blocked the main thread + case waitOnMainThread + + /// A promise has been deallocated without being resolved + case pendingPromiseDeallocated + + /// An error which occurred while fulfilling a promise was swallowed + case cauterized(Error) + + /// Errors which give a string error message + case misc (String) + ```` +*/ +public enum LogEvent { + /// A promise or guarantee has blocked the main thread + case waitOnMainThread + + /// A promise has been deallocated without being resolved + case pendingPromiseDeallocated + + /// A guarantee has been deallocated without being resolved + case pendingGuaranteeDeallocated + + /// An error which occurred while resolving a promise was swallowed + case cauterized(Error) + + /// Odd arguments to DispatchQueue-compatibility layer + case nilDispatchQueueWithFlags + + /// DispatchWorkItem flags specified for non-DispatchQueue Dispatcher + case extraneousFlagsSpecified +} + +extension LogEvent: CustomStringConvertible { + public var description: String { + switch self { + case .waitOnMainThread: + return "warning: `wait()` called on main thread!" + case .pendingPromiseDeallocated: + return "warning: pending promise deallocated" + case .pendingGuaranteeDeallocated: + return "warning: pending guarantee deallocated" + case .cauterized(let error): + return "cauterized-error: \(error)" + case .nilDispatchQueueWithFlags: + return "warning: nil DispatchQueue specified, but DispatchWorkItemFlags were also supplied (ignored)" + case .extraneousFlagsSpecified: + return "warning: DispatchWorkItemFlags flags specified, but default Dispatcher is not a DispatchQueue (ignored)" + } + } +} diff --git a/Sources/Promise.swift b/Sources/PromiseKit/Promise.swift similarity index 61% rename from Sources/Promise.swift rename to Sources/PromiseKit/Promise.swift index ef5735224..d08a5499e 100644 --- a/Sources/Promise.swift +++ b/Sources/PromiseKit/Promise.swift @@ -6,9 +6,9 @@ import Dispatch - See: `Thenable` */ public final class Promise: Thenable, CatchMixin { - let box: Box> + let box: Box> - fileprivate init(box: SealedBox>) { + fileprivate init(box: SealedBox>) { self.box = box } @@ -38,13 +38,13 @@ public final class Promise: Thenable, CatchMixin { return .value(bar) } */ - public static func value(_ value: T) -> Promise { - return Promise(box: SealedBox(value: .fulfilled(value))) + public class func value(_ value: T) -> Promise { + return Promise(box: SealedBox(value: .success(value))) } /// Initialize a new rejected promise. public init(error: Error) { - box = SealedBox(value: .rejected(error)) + box = SealedBox(value: .failure(error)) } /// Initialize a new promise bound to the provided `Thenable`. @@ -64,13 +64,26 @@ public final class Promise: Thenable, CatchMixin { } } + /// Initialize a new promise that can be resolved with the provided `Resolver`. + public init(cancellable: Cancellable, resolver body: (Resolver) throws -> Void) { + box = EmptyBox() + let resolver = Resolver(box) + self.cancellable = cancellable + self.rejectIfCancelled = resolver.reject + do { + try body(resolver) + } catch { + resolver.reject(error) + } + } + /// - Returns: a tuple of a new pending promise and its `Resolver`. public class func pending() -> (promise: Promise, resolver: Resolver) { return { ($0, Resolver($0.box)) }(Promise(.pending)) } /// - See: `Thenable.pipe` - public func pipe(to: @escaping(Result) -> Void) { + public func pipe(to: @escaping(Result) -> Void) { switch box.inspect() { case .pending: box.inspect { @@ -87,7 +100,7 @@ public final class Promise: Thenable, CatchMixin { } /// - See: `Thenable.result` - public var result: Result? { + public var result: Result? { switch box.inspect() { case .pending: return nil @@ -99,6 +112,14 @@ public final class Promise: Thenable, CatchMixin { init(_: PMKUnambiguousInitializer) { box = EmptyBox() } + + var cancellable: Cancellable? + var rejectIfCancelled: ((Error) -> Void)? + + public func setCancellable(_ cancellable: Cancellable?, reject: ((Error) -> Void)? = nil) { + self.cancellable = cancellable + rejectIfCancelled = reject + } } public extension Promise { @@ -109,7 +130,7 @@ public extension Promise { func wait() throws -> T { if Thread.isMainThread { - conf.logHandler(LogEvent.waitOnMainThread) + conf.logHandler(.waitOnMainThread) } var result = self.result @@ -121,20 +142,14 @@ public extension Promise { group.wait() } - switch result! { - case .rejected(let error): - throw error - case .fulfilled(let value): - return value - } + return try result!.get() } } -#if swift(>=3.1) extension Promise where T == Void { /// Initializes a new promise fulfilled with `Void` public convenience init() { - self.init(box: SealedBox(value: .fulfilled(Void()))) + self.init(box: SealedBox(value: .success(Void()))) } /// Returns a new promise fulfilled with `Void` @@ -142,12 +157,10 @@ extension Promise where T == Void { return .value(Void()) } } -#endif - public extension DispatchQueue { /** - Asynchronously executes the provided closure on a dispatch queue. + Asynchronously executes the provided closure on a dispatch queue, yielding a `Promise`. DispatchQueue.global().async(.promise) { try md5(input) @@ -155,24 +168,54 @@ public extension DispatchQueue { //… } - - Parameter body: The closure that resolves this promise. + - Parameters: + - _: Must be `.promise` to distinguish from standard `DispatchQueue.async` + - group: A `DispatchGroup`, as for standard `DispatchQueue.async` + - qos: A quality-of-service grade, as for standard `DispatchQueue.async` + - flags: Work item flags, as for standard `DispatchQueue.async` + - body: A closure that yields a value to resolve the promise. - Returns: A new `Promise` resolved by the result of the provided closure. - - Note: There is no Promise/Thenable version of this due to Swift compiler ambiguity issues. */ @available(macOS 10.10, iOS 8.0, tvOS 9.0, watchOS 2.0, *) - final func async(_: PMKNamespacer, group: DispatchGroup? = nil, qos: DispatchQoS = .default, flags: DispatchWorkItemFlags = [], execute body: @escaping () throws -> T) -> Promise { + final func async(_: PMKNamespacer, group: DispatchGroup? = nil, qos: DispatchQoS? = nil, flags: DispatchWorkItemFlags? = nil, execute body: @escaping () throws -> T) -> Promise { let promise = Promise(.pending) - async(group: group, qos: qos, flags: flags) { + asyncD(group: group, qos: qos, flags: flags) { do { - promise.box.seal(.fulfilled(try body())) + promise.box.seal(.success(try body())) } catch { - promise.box.seal(.rejected(error)) + promise.box.seal(.failure(error)) } } return promise } } +public extension Dispatcher { + /** + Executes the provided closure on a `Dispatcher`, yielding a `Promise` + that represents the value ultimately returned by the closure. + + dispatcher.dispatch { + try md5(input) + }.done { md5 in + //… + } + + - Parameter body: A closure that yields a value to resolve the promise. + - Returns: A new `Promise` resolved by the result of the provided closure. + */ + func dispatch(_ body: @escaping () throws -> T) -> Promise { + let promise = Promise(.pending) + dispatch { + do { + promise.box.seal(.success(try body())) + } catch { + promise.box.seal(.failure(error)) + } + } + return promise + } +} /// used by our extensions to provide unambiguous functions with the same name as the original function public enum PMKNamespacer { diff --git a/Sources/Resolver.swift b/Sources/PromiseKit/Resolver.swift similarity index 63% rename from Sources/Resolver.swift rename to Sources/PromiseKit/Resolver.swift index c6b339fcd..d83d9cdaa 100644 --- a/Sources/Resolver.swift +++ b/Sources/PromiseKit/Resolver.swift @@ -1,8 +1,8 @@ /// An object for resolving promises public final class Resolver { - let box: Box> + let box: Box> - init(_ box: Box>) { + init(_ box: Box>) { self.box = box } @@ -16,16 +16,16 @@ public final class Resolver { public extension Resolver { /// Fulfills the promise with the provided value func fulfill(_ value: T) { - box.seal(.fulfilled(value)) + box.seal(.success(value)) } /// Rejects the promise with the provided error func reject(_ error: Error) { - box.seal(.rejected(error)) + box.seal(.failure(error)) } /// Resolves the promise with the provided result - func resolve(_ result: Result) { + func resolve(_ result: Result) { box.seal(result) } @@ -55,7 +55,6 @@ public extension Resolver { } } -#if swift(>=3.1) extension Resolver where T == Void { /// Fulfills the promise unless error is non-nil public func resolve(_ error: Error?) { @@ -65,47 +64,10 @@ extension Resolver where T == Void { fulfill(()) } } -#if false - // disabled ∵ https://github.com/mxcl/PromiseKit/issues/990 - /// Fulfills the promise - public func fulfill() { - self.fulfill(()) - } -#else /// Fulfills the promise /// - Note: underscore is present due to: https://github.com/mxcl/PromiseKit/issues/990 - public func fulfill_() { + public func fulfill() { self.fulfill(()) } -#endif -} -#endif - -#if swift(>=5.0) -extension Resolver { - /// Resolves the promise with the provided result - public func resolve(_ result: Swift.Result) { - switch result { - case .failure(let error): self.reject(error) - case .success(let value): self.fulfill(value) - } - } -} -#endif - -public enum Result { - case fulfilled(T) - case rejected(Error) -} - -public extension PromiseKit.Result { - var isFulfilled: Bool { - switch self { - case .fulfilled: - return true - case .rejected: - return false - } - } } diff --git a/Sources/Thenable.swift b/Sources/PromiseKit/Thenable.swift similarity index 52% rename from Sources/Thenable.swift rename to Sources/PromiseKit/Thenable.swift index 7d88ea6e8..4d4d09f1f 100644 --- a/Sources/Thenable.swift +++ b/Sources/PromiseKit/Thenable.swift @@ -6,20 +6,20 @@ public protocol Thenable: AnyObject { associatedtype T /// `pipe` is immediately executed when this `Thenable` is resolved - func pipe(to: @escaping(Result) -> Void) + func pipe(to: @escaping(Result) -> Void) /// The resolved result or nil if pending. - var result: Result? { get } + var result: Result? { get } } public extension Thenable { /** The provided closure executes when this promise is fulfilled. - + This allows chaining promises. The promise returned by the provided closure is resolved before the promise returned by this closure resolves. - - - Parameter on: The queue to which the provided closure dispatches. - - Parameter body: The closure that executes when this promise is fulfilled. It must return a promise. + + - Parameter on: The dispatcher that executes the provided closure. + - Parameter body: The closure that executes when this promise fulfills. It must return a promise. - Returns: A new promise that resolves when the promise returned from the provided closure resolves. For example: firstly { @@ -30,22 +30,22 @@ public extension Thenable { //… } */ - func then(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ body: @escaping(T) throws -> U) -> Promise { + func then(on: Dispatcher = conf.D.map, _ body: @escaping(T) throws -> U) -> Promise { let rp = Promise(.pending) pipe { switch $0 { - case .fulfilled(let value): - on.async(flags: flags) { + case .success(let value): + on.dispatch { do { let rv = try body(value) guard rv !== rp else { throw PMKError.returnedSelf } rv.pipe(to: rp.box.seal) } catch { - rp.box.seal(.rejected(error)) + rp.box.seal(.failure(error)) } } - case .rejected(let error): - rp.box.seal(.rejected(error)) + case .failure(let error): + rp.box.seal(.failure(error)) } } return rp @@ -53,10 +53,10 @@ public extension Thenable { /** The provided closure is executed when this promise is fulfilled. - + This is like `then` but it requires the closure to return a non-promise. - - - Parameter on: The queue to which the provided closure dispatches. + + - Parameter on: The dispatcher that executes the provided closure. - Parameter transform: The closure that is executed when this Promise is fulfilled. It must return a non-promise. - Returns: A new promise that is fulfilled with the value returned from the provided closure or rejected if the provided closure throws. For example: @@ -68,49 +68,25 @@ public extension Thenable { //… } */ - func map(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ transform: @escaping(T) throws -> U) -> Promise { + func map(on: Dispatcher = conf.D.map, _ transform: @escaping(T) throws -> U) -> Promise { let rp = Promise(.pending) pipe { switch $0 { - case .fulfilled(let value): - on.async(flags: flags) { + case .success(let value): + on.dispatch { do { - rp.box.seal(.fulfilled(try transform(value))) + rp.box.seal(.success(try transform(value))) } catch { - rp.box.seal(.rejected(error)) + rp.box.seal(.failure(error)) } } - case .rejected(let error): - rp.box.seal(.rejected(error)) + case .failure(let error): + rp.box.seal(.failure(error)) } } return rp } - #if swift(>=4) && !swift(>=5.2) - /** - Similar to func `map(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ transform: @escaping(T) throws -> U) -> Promise`, but accepts a key path instead of a closure. - - - Parameter on: The queue to which the provided key path for value dispatches. - - Parameter keyPath: The key path to the value that is using when this Promise is fulfilled. - - Returns: A new promise that is fulfilled with the value for the provided key path. - */ - func map(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ keyPath: KeyPath) -> Promise { - let rp = Promise(.pending) - pipe { - switch $0 { - case .fulfilled(let value): - on.async(flags: flags) { - rp.box.seal(.fulfilled(value[keyPath: keyPath])) - } - case .rejected(let error): - rp.box.seal(.rejected(error)) - } - } - return rp - } - #endif - /** The provided closure is executed when this promise is fulfilled. @@ -126,92 +102,60 @@ public extension Thenable { // either `PMKError.compactMap` or a `JSONError` } */ - func compactMap(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ transform: @escaping(T) throws -> U?) -> Promise { + func compactMap(on: Dispatcher = conf.D.map, _ transform: @escaping(T) throws -> U?) -> Promise { let rp = Promise(.pending) pipe { switch $0 { - case .fulfilled(let value): - on.async(flags: flags) { + case .success(let value): + on.dispatch { do { if let rv = try transform(value) { - rp.box.seal(.fulfilled(rv)) - } else { - throw PMKError.compactMap(value, U.self) - } - } catch { - rp.box.seal(.rejected(error)) - } - } - case .rejected(let error): - rp.box.seal(.rejected(error)) - } - } - return rp - } - - #if swift(>=4) && !swift(>=5.2) - /** - Similar to func `compactMap(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ transform: @escaping(T) throws -> U?) -> Promise`, but accepts a key path instead of a closure. - - - Parameter on: The queue to which the provided key path for value dispatches. - - Parameter keyPath: The key path to the value that is using when this Promise is fulfilled. If the value for `keyPath` is `nil` the resulting promise is rejected with `PMKError.compactMap`. - - Returns: A new promise that is fulfilled with the value for the provided key path. - */ - func compactMap(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ keyPath: KeyPath) -> Promise { - let rp = Promise(.pending) - pipe { - switch $0 { - case .fulfilled(let value): - on.async(flags: flags) { - do { - if let rv = value[keyPath: keyPath] { - rp.box.seal(.fulfilled(rv)) + rp.box.seal(.success(rv)) } else { throw PMKError.compactMap(value, U.self) } } catch { - rp.box.seal(.rejected(error)) + rp.box.seal(.failure(error)) } } - case .rejected(let error): - rp.box.seal(.rejected(error)) + case .failure(let error): + rp.box.seal(.failure(error)) } } return rp } - #endif /** The provided closure is executed when this promise is fulfilled. - + Equivalent to `map { x -> Void in`, but since we force the `Void` return Swift is happier and gives you less hassle about your closure’s qualification. - - - Parameter on: The queue to which the provided closure dispatches. + + - Parameter on: The dispatcher that executes the provided closure. - Parameter body: The closure that is executed when this Promise is fulfilled. - Returns: A new promise fulfilled as `Void` or rejected if the provided closure throws. - + firstly { URLSession.shared.dataTask(.promise, with: url) }.done { response in print(response.data) } */ - func done(on: DispatchQueue? = conf.Q.return, flags: DispatchWorkItemFlags? = nil, _ body: @escaping(T) throws -> Void) -> Promise { + func done(on: Dispatcher = conf.D.return, _ body: @escaping(T) throws -> Void) -> Promise { let rp = Promise(.pending) pipe { switch $0 { - case .fulfilled(let value): - on.async(flags: flags) { + case .success(let value): + on.dispatch { do { try body(value) - rp.box.seal(.fulfilled(())) + rp.box.seal(.success(())) } catch { - rp.box.seal(.rejected(error)) + rp.box.seal(.failure(error)) } } - case .rejected(let error): - rp.box.seal(.rejected(error)) + case .failure(let error): + rp.box.seal(.failure(error)) } } return rp @@ -219,14 +163,14 @@ public extension Thenable { /** The provided closure is executed when this promise is fulfilled. - + This is like `done` but it returns the same value that the handler is fed. `get` immutably accesses the fulfilled value; the returned Promise maintains that value. - - - Parameter on: The queue to which the provided closure dispatches. + + - Parameter on: The dispatcher that executes the provided closure. - Parameter body: The closure that is executed when this Promise is fulfilled. - Returns: A new promise that is fulfilled with the value that the handler is fed or rejected if the provided closure throws. For example: - + firstly { .value(1) }.get { foo in @@ -237,8 +181,8 @@ public extension Thenable { print(foo, " is Void") } */ - func get(on: DispatchQueue? = conf.Q.return, flags: DispatchWorkItemFlags? = nil, _ body: @escaping (T) throws -> Void) -> Promise { - return map(on: on, flags: flags) { + func get(on: Dispatcher = conf.D.return, _ body: @escaping (T) throws -> Void) -> Promise { + return map(on: on) { try body($0) return $0 } @@ -249,16 +193,16 @@ public extension Thenable { This is like `get` but provides the Result of the Promise so you can inspect the value of the chain at this point without causing any side effects. - - Parameter on: The queue to which the provided closure dispatches. + - Parameter on: The dispatcher that executes the provided closure. - Parameter body: The closure that is executed with Result of Promise. - Returns: A new promise that is resolved with the result that the handler is fed. For example: promise.tap{ print($0) }.then{ /*…*/ } */ - func tap(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ body: @escaping(Result) -> Void) -> Promise { + func tap(on: Dispatcher = conf.D.map, _ body: @escaping(Result) -> Void) -> Promise { return Promise { seal in pipe { result in - on.async(flags: flags) { + on.dispatch { body(result) seal.resolve(result) } @@ -280,9 +224,9 @@ public extension Thenable { switch result { case .none: return nil - case .some(.fulfilled): + case .some(.success): return nil - case .some(.rejected(let error)): + case .some(.failure(let error)): return error } } @@ -322,14 +266,26 @@ public extension Thenable { switch result { case .none: return nil - case .some(.fulfilled(let value)): + case .some(.success(let value)): return value - case .some(.rejected): + case .some(.failure): return nil } } } +public extension Thenable { + /** + Converts a Promise or Guarantee into a promise that can be cancelled. + - Parameter thenable: The Thenable (Promise or Guarantee) to be made cancellable. + - Returns: A CancellablePromise that is a cancellable variant of the given Promise or Guarantee. + */ + func cancellize(cancelContext: CancelContext? = nil) -> CancellablePromise { + return CancellablePromise(self, cancelContext: cancelContext) + } +} + + public extension Thenable where T: Sequence { /** `Promise<[T]>` => `T` -> `U` => `Promise<[U]>` @@ -342,25 +298,10 @@ public extension Thenable where T: Sequence { // $0 => [2,4,6] } */ - func mapValues(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ transform: @escaping(T.Iterator.Element) throws -> U) -> Promise<[U]> { - return map(on: on, flags: flags){ try $0.map(transform) } + func mapValues(on: Dispatcher = conf.D.map, _ transform: @escaping(T.Iterator.Element) throws -> U) -> Promise<[U]> { + return map(on: on) { try $0.map(transform) } } - #if swift(>=4) && !swift(>=5.2) - /** - `Promise<[T]>` => `KeyPath` => `Promise<[U]>` - - firstly { - .value([Person(name: "Max"), Person(name: "Roman"), Person(name: "John")]) - }.mapValues(\.name).done { - // $0 => ["Max", "Roman", "John"] - } - */ - func mapValues(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ keyPath: KeyPath) -> Promise<[U]> { - return map(on: on, flags: flags){ $0.map { $0[keyPath: keyPath] } } - } - #endif - /** `Promise<[T]>` => `T` -> `[U]` => `Promise<[U]>` @@ -372,8 +313,8 @@ public extension Thenable where T: Sequence { // $0 => [1,1,2,2,3,3] } */ - func flatMapValues(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ transform: @escaping(T.Iterator.Element) throws -> U) -> Promise<[U.Iterator.Element]> { - return map(on: on, flags: flags){ (foo: T) in + func flatMapValues(on: Dispatcher = conf.D.map, _ transform: @escaping(T.Iterator.Element) throws -> U) -> Promise<[U.Iterator.Element]> { + return map(on: on){ (foo: T) in try foo.flatMap{ try transform($0) } } } @@ -389,36 +330,12 @@ public extension Thenable where T: Sequence { // $0 => [1,2,3] } */ - func compactMapValues(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ transform: @escaping(T.Iterator.Element) throws -> U?) -> Promise<[U]> { - return map(on: on, flags: flags) { foo -> [U] in - #if !swift(>=3.3) || (swift(>=4) && !swift(>=4.1)) - return try foo.flatMap(transform) - #else - return try foo.compactMap(transform) - #endif - } - } - - #if swift(>=4) && !swift(>=5.2) - /** - `Promise<[T]>` => `KeyPath` => `Promise<[U]>` - firstly { - .value([Person(name: "Max"), Person(name: "Roman", age: 26), Person(name: "John", age: 23)]) - }.compactMapValues(\.age).done { - // $0 => [26, 23] - } - */ - func compactMapValues(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ keyPath: KeyPath) -> Promise<[U]> { - return map(on: on, flags: flags) { foo -> [U] in - #if !swift(>=4.1) - return foo.flatMap { $0[keyPath: keyPath] } - #else - return foo.compactMap { $0[keyPath: keyPath] } - #endif + func compactMapValues(on: Dispatcher = conf.D.map, _ transform: @escaping(T.Iterator.Element) throws -> U?) -> Promise<[U]> { + return map(on: on) { foo -> [U] in + return try foo.compactMap(transform) } } - #endif /** `Promise<[T]>` => `T` -> `Promise` => `Promise<[U]>` @@ -431,8 +348,8 @@ public extension Thenable where T: Sequence { // $0 => [2,4,6] } */ - func thenMap(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ transform: @escaping(T.Iterator.Element) throws -> U) -> Promise<[U.T]> { - return then(on: on, flags: flags) { + func thenMap(on: Dispatcher = conf.D.map, _ transform: @escaping(T.Iterator.Element) throws -> U) -> Promise<[U.T]> { + return then(on: on) { when(fulfilled: try $0.map(transform)) } } @@ -448,8 +365,8 @@ public extension Thenable where T: Sequence { // $0 => [1,1,2,2,3,3] } */ - func thenFlatMap(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ transform: @escaping(T.Iterator.Element) throws -> U) -> Promise<[U.T.Iterator.Element]> where U.T: Sequence { - return then(on: on, flags: flags) { + func thenFlatMap(on: Dispatcher = conf.D.map, _ transform: @escaping(T.Iterator.Element) throws -> U) -> Promise<[U.T.Iterator.Element]> where U.T: Sequence { + return then(on: on) { when(fulfilled: try $0.map(transform)) }.map(on: nil) { $0.flatMap{ $0 } @@ -467,28 +384,11 @@ public extension Thenable where T: Sequence { // $0 => [2,3] } */ - func filterValues(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ isIncluded: @escaping (T.Iterator.Element) -> Bool) -> Promise<[T.Iterator.Element]> { - return map(on: on, flags: flags) { + func filterValues(on: Dispatcher = conf.D.map, _ isIncluded: @escaping (T.Iterator.Element) -> Bool) -> Promise<[T.Iterator.Element]> { + return map(on: on) { $0.filter(isIncluded) } } - - #if swift(>=4) && !swift(>=5.2) - /** - `Promise<[T]>` => `KeyPath` => `Promise<[T]>` - - firstly { - .value([Person(name: "Max"), Person(name: "Roman", age: 26, isStudent: false), Person(name: "John", age: 23, isStudent: true)]) - }.filterValues(\.isStudent).done { - // $0 => [Person(name: "John", age: 23, isStudent: true)] - } - */ - func filterValues(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ keyPath: KeyPath) -> Promise<[T.Iterator.Element]> { - return map(on: on, flags: flags) { - $0.filter { $0[keyPath: keyPath] } - } - } - #endif } public extension Thenable where T: Collection { @@ -503,8 +403,8 @@ public extension Thenable where T: Collection { } } - func firstValue(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, where test: @escaping (T.Iterator.Element) -> Bool) -> Promise { - return map(on: on, flags: flags) { + func firstValue(on: Dispatcher = conf.D.map, where test: @escaping (T.Iterator.Element) -> Bool) -> Promise { + return map(on: on) { for x in $0 where test(x) { return x } @@ -527,7 +427,7 @@ public extension Thenable where T: Collection { public extension Thenable where T: Sequence, T.Iterator.Element: Comparable { /// - Returns: a promise fulfilled with the sorted values of this `Sequence`. - func sortedValues(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil) -> Promise<[T.Iterator.Element]> { - return map(on: on, flags: flags){ $0.sorted() } + func sortedValues(on: Dispatcher = conf.D.map) -> Promise<[T.Iterator.Element]> { + return map(on: on){ $0.sorted() } } } diff --git a/Sources/PromiseKit/Wrappers/CatchWrappers.swift b/Sources/PromiseKit/Wrappers/CatchWrappers.swift new file mode 100644 index 000000000..c8802a47b --- /dev/null +++ b/Sources/PromiseKit/Wrappers/CatchWrappers.swift @@ -0,0 +1,73 @@ +import Dispatch + +public extension _PMKCatchWrappers { + + /** + The provided closure executes when this promise rejects. + + Rejecting a promise cascades: rejecting all subsequent promises (unless + recover is invoked) thus you will typically place your catch at the end + of a chain. Often utility promises will not have a catch, instead + delegating the error handling to the caller. + + - Parameter on: The queue to which the provided closure dispatches. + - Parameter flags: `DispatchWorkItemFlags` to be applied when dispatching. + - Parameter policy: The default policy does not execute your handler for cancellation errors. + - Parameter body: The handler to execute if this promise is rejected. + - Returns: A promise finalizer. + - SeeAlso: [Cancellation](http://https://github.com/mxcl/PromiseKit/blob/master/Documents/CommonPatterns.md#cancellation/docs/) + */ + @discardableResult + func `catch`(on: DispatchQueue? = .pmkDefault, flags: DispatchWorkItemFlags? = nil, policy: CatchPolicy = conf.catchPolicy, _ body: @escaping(Error) -> Void) -> Finalizer { + let dispatcher = selectDispatcher(given: on, configured: conf.D.return, flags: flags) + return `catch`(on: dispatcher, policy: policy, body) + } + + /** + The provided closure executes when this promise rejects with the specific error passed in. A final `catch` is still required at the end of the chain. + + Rejecting a promise cascades: rejecting all subsequent promises (unless + recover is invoked) thus you will typically place your catch at the end + of a chain. Often utility promises will not have a catch, instead + delegating the error handling to the caller. + + - Parameter only: The specific error to be caught and handled (e.g., `PMKError.emptySequence`). + - Parameter on: The queue to which the provided closure dispatches. + - Parameter flags: `DispatchWorkItemFlags` to be applied when dispatching. + - Parameter body: The handler to execute if this promise is rejected with the provided error. + - Note: Since this method handles only specific errors, supplying a `CatchPolicy` is unsupported. + - SeeAlso: [Cancellation](http://promisekit.org/docs/) + */ + func `catch`(only: E, on: DispatchQueue? = .pmkDefault, flags: DispatchWorkItemFlags? = nil, _ body: @escaping(E) -> Void) + -> CascadingFinalizer where E: Equatable + { + let dispatcher = selectDispatcher(given: on, configured: conf.D.return, flags: flags) + return `catch`(only: only, on: dispatcher, body) + } + + /** + The provided closure executes when this promise rejects with an error of the type passed in. A final `catch` is still required at the end of the chain. + + Rejecting a promise cascades: rejecting all subsequent promises (unless + recover is invoked) thus you will typically place your catch at the end + of a chain. Often utility promises will not have a catch, instead + delegating the error handling to the caller. + + - Parameter only: The error type to be caught and handled (e.g., `PMKError`). + - Parameter on: The queue to which the provided closure dispatches. + - Parameter flags: `DispatchWorkItemFlags` to be applied when dispatching. + - Parameter policy: A `CatchPolicy` that further constrains the errors this handler will see. E.g., if + you are receiving `PMKError` errors, do you want to see even those that result from cancellation? + - Parameter body: The handler to execute if this promise is rejected with the provided error type. + - SeeAlso: [Cancellation](http://promisekit.org/docs/) + */ + func `catch`(only: E.Type, on: DispatchQueue? = .pmkDefault, flags: DispatchWorkItemFlags? = nil, + policy: CatchPolicy = conf.catchPolicy, _ body: @escaping(E) -> Void) -> CascadingFinalizer + { + let dispatcher = selectDispatcher(given: on, configured: conf.D.return, flags: flags) + return `catch`(only: only, on: dispatcher, policy: policy, body) + } + +} + + diff --git a/Sources/PromiseKit/Wrappers/EnsureWrappers.swift b/Sources/PromiseKit/Wrappers/EnsureWrappers.swift new file mode 100644 index 000000000..442907545 --- /dev/null +++ b/Sources/PromiseKit/Wrappers/EnsureWrappers.swift @@ -0,0 +1,51 @@ +import Dispatch + +public extension _PMKSharedWrappers { + + /** + The provided closure executes when this promise resolves, whether it rejects or not. + + firstly { + UIApplication.shared.networkActivityIndicatorVisible = true + }.done { + //… + }.ensure { + UIApplication.shared.networkActivityIndicatorVisible = false + }.catch { + //… + } + + - Parameter on: The queue to which the provided closure dispatches. + - Parameter flags: `DispatchWorkItemFlags` to be applied when dispatching. + - Parameter body: The closure that executes when this promise resolves. + - Returns: A new promise, resolved with this promise’s resolution. + */ + func ensure(on: DispatchQueue? = .pmkDefault, flags: DispatchWorkItemFlags? = nil, _ body: @escaping () -> Void) -> BaseOfT { + let dispatcher = selectDispatcher(given: on, configured: conf.D.return, flags: flags) + return ensure(on: dispatcher, body) + } + + /** + The provided closure executes when this promise resolves, whether it rejects or not. + The chain waits on the returned `Guarantee`. + + firstly { + setup() + }.done { + //… + }.ensureThen { + teardown() + }.catch { + //… + } + + - Parameter on: The queue to which the provided closure dispatches. + - Parameter flags: `DispatchWorkItemFlags` to be applied when dispatching. + - Parameter body: The closure that executes when this promise resolves. + - Returns: A new promise, resolved with this promise’s resolution. + */ + func ensureThen(on: DispatchQueue? = .pmkDefault, flags: DispatchWorkItemFlags? = nil, _ body: @escaping () -> VoidReturn) -> BaseOfT { + let dispatcher = selectDispatcher(given: on, configured: conf.D.return, flags: flags) + return ensureThen(on: dispatcher, body) + } +} diff --git a/Sources/PromiseKit/Wrappers/FinallyWrappers.swift b/Sources/PromiseKit/Wrappers/FinallyWrappers.swift new file mode 100644 index 000000000..09272102c --- /dev/null +++ b/Sources/PromiseKit/Wrappers/FinallyWrappers.swift @@ -0,0 +1,11 @@ +import Dispatch + +public extension _PMKFinallyWrappers { + /// `finally` is the same as `ensure`, but it is not chainable + @discardableResult + func finally(on: DispatchQueue? = .pmkDefault, flags: DispatchWorkItemFlags? = nil, _ body: @escaping () -> Void) -> FinallyReturn { + let dispatcher = selectDispatcher(given: on, configured: conf.D.return, flags: flags) + return finally(on: dispatcher, body) + } +} + diff --git a/Sources/PromiseKit/Wrappers/GuaranteeWrappers.swift b/Sources/PromiseKit/Wrappers/GuaranteeWrappers.swift new file mode 100644 index 000000000..de03cb7f8 --- /dev/null +++ b/Sources/PromiseKit/Wrappers/GuaranteeWrappers.swift @@ -0,0 +1,61 @@ +// Since Guarantees have no error path, closures in the API are nonthrowing, which +// makes them different from the shared Promise/CancellablePromise API. + +import Dispatch + +public extension Guarantee { + + @discardableResult + func then(on: DispatchQueue? = .pmkDefault, flags: DispatchWorkItemFlags? = nil, _ body: @escaping(T) -> Guarantee) -> Guarantee { + let dispatcher = selectDispatcher(given: on, configured: conf.D.map, flags: flags) + return then(on: dispatcher, body) + } + + @discardableResult + func then(on: DispatchQueue? = .pmkDefault, flags: DispatchWorkItemFlags? = nil, _ body: @escaping(T) throws -> Guarantee) -> Promise { + let dispatcher = selectDispatcher(given: on, configured: conf.D.map, flags: flags) + return then(on: dispatcher, body) + } + + func map(on: DispatchQueue? = .pmkDefault, flags: DispatchWorkItemFlags? = nil, _ body: @escaping(T) -> U) -> Guarantee { + let dispatcher = selectDispatcher(given: on, configured: conf.D.map, flags: flags) + return map(on: dispatcher, body) + } + + func map(on: DispatchQueue? = .pmkDefault, flags: DispatchWorkItemFlags? = nil, _ body: @escaping(T) throws -> U) -> Promise { + let dispatcher = selectDispatcher(given: on, configured: conf.D.map, flags: flags) + return map(on: dispatcher, body) + } + + @discardableResult + func done(on: DispatchQueue? = .pmkDefault, flags: DispatchWorkItemFlags? = nil, _ body: @escaping(T) -> Void) -> Guarantee { + let dispatcher = selectDispatcher(given: on, configured: conf.D.return, flags: flags) + return done(on: dispatcher, body) + } + + @discardableResult + func done(on: DispatchQueue? = .pmkDefault, flags: DispatchWorkItemFlags? = nil, _ body: @escaping(T) throws -> Void) -> Promise { + let dispatcher = selectDispatcher(given: on, configured: conf.D.return, flags: flags) + return done(on: dispatcher, body) + } + + func get(on: DispatchQueue? = .pmkDefault, flags: DispatchWorkItemFlags? = nil, _ body: @escaping (T) -> Void) -> Guarantee { + let dispatcher = selectDispatcher(given: on, configured: conf.D.return, flags: flags) + return get(on: dispatcher, body) + } + + func get(on: DispatchQueue? = .pmkDefault, flags: DispatchWorkItemFlags? = nil, _ body: @escaping (T) throws -> Void) -> Promise { + let dispatcher = selectDispatcher(given: on, configured: conf.D.return, flags: flags) + return get(on: dispatcher, body) + } +} + +public extension Guarantee where T: Sequence { + + func thenMap(on: DispatchQueue? = .pmkDefault, flags: DispatchWorkItemFlags? = nil, _ transform: @escaping(T.Iterator.Element) -> Guarantee) -> Guarantee<[U]> { + let dispatcher = selectDispatcher(given: on, configured: conf.D.map, flags: flags) + return thenMap(on: dispatcher, transform) + } + +} + diff --git a/Sources/PromiseKit/Wrappers/RecoverWrappers.swift b/Sources/PromiseKit/Wrappers/RecoverWrappers.swift new file mode 100644 index 000000000..e253d1a34 --- /dev/null +++ b/Sources/PromiseKit/Wrappers/RecoverWrappers.swift @@ -0,0 +1,275 @@ +import Dispatch + +public extension _PMKSharedWrappers { + + /** + The provided closure executes when this promise rejects. + + Unlike `catch`, `recover` continues the chain. It can return a replacement promise or rethrow. + Use `recover` in circumstances where recovering the chain from certain errors is a possibility. For example: + + firstly { + CLLocationManager.requestLocation() + }.recover { error in + guard error == CLError.unknownLocation else { throw error } + return .value(CLLocation.chicago) + } + + - Parameter on: The queue to which the provided closure dispatches. + - Parameter flags: `DispatchWorkItemFlags` to be applied when dispatching. + - Parameter policy: The default policy does not execute your handler for cancellation errors. + - Parameter body: The handler to execute if this promise is rejected. + - SeeAlso: [Cancellation](https://github.com/mxcl/PromiseKit/blob/master/Documents/CommonPatterns.md#cancellation) + */ + func recover(on: DispatchQueue? = .pmkDefault, flags: DispatchWorkItemFlags? = nil, policy: CatchPolicy = conf.catchPolicy, + _ body: @escaping(Error) throws -> U) -> BaseOfT where U.T == T + { + let dispatcher = selectDispatcher(given: on, configured: conf.D.map, flags: flags) + return recover(on: dispatcher, policy: policy, body) + } + + /** + The provided closure executes when this promise rejects with the specific error passed in. + + Unlike `catch`, `recover` continues the chain. It can return a replacement promise or rethrow. + Use `recover` in circumstances where recovering the chain from certain errors is a possibility. For example: + + firstly { + CLLocationManager.requestLocation() + }.recover(CLError.unknownLocation) { + return .value(CLLocation.chicago) + } + + - Parameter only: The specific error to be recovered (e.g., `PMKError.emptySequence`) + - Parameter on: The queue to which the provided closure dispatches. + - Parameter flags: `DispatchWorkItemFlags` to be applied when dispatching. + - Parameter body: The handler to execute if this promise is rejected with the provided error. + - Note: Since this method recovers only specific errors, supplying a `CatchPolicy` is unsupported. + - SeeAlso: [Cancellation](http://promisekit.org/docs/) + */ + func recover(only: E, on: DispatchQueue? = .pmkDefault, flags: DispatchWorkItemFlags? = nil, + _ body: @escaping(E) throws -> U) -> BaseOfT where U.T == T, E: Equatable + { + let dispatcher = selectDispatcher(given: on, configured: conf.D.map, flags: flags) + return recover(only: only, on: dispatcher, body) + } + + /** + The provided closure executes when this promise rejects with an error of the type passed in. + + Unlike `catch`, `recover` continues the chain. It can return a replacement promise or rethrow. + Use `recover` in circumstances where recovering the chain from certain errors is a possibility. For example: + + firstly { + API.fetchData() + }.recover(FetchError.self) { error in + guard case .missingImage(let partialData) = error else { throw error } + //… + return .value(dataWithDefaultImage) + } + + - Parameter only: The error type to be recovered (e.g., `PMKError`). + - Parameter on: The queue to which the provided closure dispatches. + - Parameter flags: `DispatchWorkItemFlags` to be applied when dispatching. + - Parameter policy: The default policy does not execute your handler for cancellation errors. + - Parameter body: The handler to execute if this promise is rejected with the provided error type. + - SeeAlso: [Cancellation](http://promisekit.org/docs/) + */ + func recover(only: E.Type, on: DispatchQueue? = .pmkDefault, flags: DispatchWorkItemFlags? = nil, + policy: CatchPolicy = conf.catchPolicy, _ body: @escaping(E) throws -> U) -> BaseOfT where U.T == T + { + let dispatcher = selectDispatcher(given: on, configured: conf.D.map, flags: flags) + return recover(only: only, on: dispatcher, policy: policy, body) + } +} + +public extension _PMKSharedVoidWrappers { + + /** + The provided closure executes when this promise rejects. + + This variant of `recover` ensures that no error is thrown from the handler + and allows you to specify a catch policy. + + - Parameter on: The queue to which the provided closure dispatches. + - Parameter flags: `DispatchWorkItemFlags` to be applied when dispatching. + - Parameter policy: The default policy does not execute your handler for cancellation errors. + - Parameter body: The handler to execute if this promise is rejected. + - SeeAlso: [Cancellation](https://github.com/mxcl/PromiseKit/blob/master/Documents/CommonPatterns.md#cancellation) + */ + func recover(on: DispatchQueue? = .pmkDefault, flags: DispatchWorkItemFlags? = nil, policy: CatchPolicy = conf.catchPolicy, + _ body: @escaping(Error) throws -> Void) -> BaseOfT + { + let dispatcher = selectDispatcher(given: on, configured: conf.D.map, flags: flags) + return recover(on: dispatcher, policy: policy, body) + } + + /** + The provided closure executes when this promise rejects with the specific error passed in. + + Unlike `catch`, `recover` continues the chain. It can return a replacement promise or rethrow. + Use `recover` in circumstances where recovering the chain from certain errors is a possibility. For example: + + - Parameter only: The specific error to be recovered (e.g., `PMKError.emptySequence`) + - Parameter on: The queue to which the provided closure dispatches. + - Parameter flags: `DispatchWorkItemFlags` to be applied when dispatching. + - Parameter body: The handler to execute if this promise is rejected with the provided error. + - Note: Since this method recovers only specific errors, supplying a `CatchPolicy` is unsupported. + - SeeAlso: [Cancellation](http://promisekit.org/docs/) + */ + func recover(only: E, on: DispatchQueue? = .pmkDefault, flags: DispatchWorkItemFlags? = nil, + _ body: @escaping(E) throws -> Void) -> BaseOfT where E: Equatable + { + let dispatcher = selectDispatcher(given: on, configured: conf.D.map, flags: flags) + return recover(only: only, on: dispatcher, body) + } + + /** + The provided closure executes when this promise rejects with an error of the type passed in. + + Unlike `catch`, `recover` continues the chain. It can return a replacement promise or rethrow. + Use `recover` in circumstances where recovering the chain from certain errors is a possibility. + + - Parameter only: The error type to be recovered (e.g., `PMKError`). + - Parameter on: The queue to which the provided closure dispatches. + - Parameter flags: `DispatchWorkItemFlags` to be applied when dispatching. + - Parameter policy: The default policy does not execute your handler for cancellation errors. + - Parameter body: The handler to execute if this promise is rejected with the provided error type. + - SeeAlso: [Cancellation](http://promisekit.org/docs/) + */ + func recover(only: E.Type, on: DispatchQueue? = .pmkDefault, flags: DispatchWorkItemFlags? = nil, + policy: CatchPolicy = conf.catchPolicy, _ body: @escaping(E) throws -> Void) -> BaseOfT + { + let dispatcher = selectDispatcher(given: on, configured: conf.D.map, flags: flags) + return recover(only: only, on: dispatcher, policy: policy, body) + } +} + +public extension CatchMixin { + + /** + The provided closure executes when this promise rejects. + This variant of `recover` requires the handler to return a Guarantee; your closure cannot `throw`. + + It is logically impossible for this variant to accept a `catchPolicy`. All errors will be presented + to your closure for processing. + + - Parameter on: The queue to which the provided closure dispatches. + - Parameter flags: `DispatchWorkItemFlags` to be applied when dispatching. + - Parameter body: The handler to execute if this promise is rejected. + - SeeAlso: [Cancellation](https://github.com/mxcl/PromiseKit/blob/master/Documents/CommonPatterns.md#cancellation) + */ + @discardableResult + func recover(on: DispatchQueue? = .pmkDefault, flags: DispatchWorkItemFlags? = nil, _ body: @escaping(Error) -> Guarantee) -> Guarantee { + let dispatcher = selectDispatcher(given: on, configured: conf.D.map, flags: flags) + return recover(on: dispatcher, body) + } +} + +public extension CatchMixin where T == Void { + + /** + The provided closure executes when this promise rejects. + + This variant of `recover` is specialized for `Void` promises and de-errors your chain, + returning a `Guarantee`. Thus, you cannot `throw` and you must handle all error types, + including cancellation. + + - Parameter on: The queue to which the provided closure dispatches. + - Parameter flags: `DispatchWorkItemFlags` to be applied when dispatching. + - Parameter body: The handler to execute if this promise is rejected. + - SeeAlso: [Cancellation](https://github.com/mxcl/PromiseKit/blob/master/Documents/CommonPatterns.md#cancellation) + */ + @discardableResult + func recover(on: DispatchQueue? = .pmkDefault, flags: DispatchWorkItemFlags? = nil, _ body: @escaping(Error) -> Void) -> Guarantee { + let dispatcher = selectDispatcher(given: on, configured: conf.D.map, flags: flags) + return recover(on: dispatcher, body) + } +} + +public extension CancellableCatchMixin { + + /** + The provided closure executes when this cancellable promise rejects. + + Unlike `catch`, `recover` continues the chain. It can return a replacement promise or rethrow. + Use `recover` in circumstances where recovering the chain from certain errors is a possibility. For example: + + let context = firstly { + CLLocationManager.requestLocation() + }.recover { error in + guard error == CLError.unknownLocation else { throw error } + return .value(CLLocation.chicago) + }.cancelContext + + //… + + context.cancel() + + - Parameter on: The queue to which the provided closure dispatches. + - Parameter flags: `DispatchWorkItemFlags` to be applied when dispatching. + - Parameter policy: The default policy does not execute your handler for cancellation errors. + - Parameter body: The handler to execute if this promise is rejected. + - SeeAlso: [Cancellation](https://github.com/mxcl/PromiseKit/blob/master/Documentation/CommonPatterns.md#cancellation) + */ + func recover(on: DispatchQueue? = .pmkDefault, flags: DispatchWorkItemFlags? = nil, + policy: CatchPolicy = conf.catchPolicy, _ body: @escaping(Error) throws -> V) -> CancellablePromise where V.U.T == C.T + { + let dispatcher = selectDispatcher(given: on, configured: conf.D.map, flags: flags) + return recover(on: dispatcher, policy: policy, body) + } + + /** + The provided closure executes when this cancellable promise rejects with the specific error passed in. + + Unlike `catch`, `recover` continues the chain. It can return a replacement promise or rethrow. + Use `recover` in circumstances where recovering the chain from certain errors is a possibility. For example: + + firstly { + CLLocationManager.requestLocation() + }.recover(CLError.unknownLocation) { + return .value(CLLocation.chicago) + } + + - Parameter only: The specific error to be recovered (e.g., `PMKError.emptySequence`) + - Parameter on: The queue to which the provided closure dispatches. + - Parameter flags: `DispatchWorkItemFlags` to be applied when dispatching. + - Parameter body: The handler to execute if this promise is rejected with the provided error. + - Note: Since this method recovers only specific errors, supplying a `CatchPolicy` is unsupported. + - SeeAlso: [Cancellation](https://github.com/mxcl/PromiseKit/blob/master/Documentation/CommonPatterns.md#cancellation) + */ + func recover(only: E, on: DispatchQueue? = .pmkDefault, flags: DispatchWorkItemFlags? = nil, + _ body: @escaping(E) throws -> V) -> CancellablePromise where V.U.T == C.T, E: Equatable + { + let dispatcher = selectDispatcher(given: on, configured: conf.D.map, flags: flags) + return recover(only: only, on: dispatcher, body) + } + + /** + The provided closure executes when this cancellable promise rejects with an error of the type passed in. + + Unlike `catch`, `recover` continues the chain. It can return a replacement promise or rethrow. + Use `recover` in circumstances where recovering the chain from certain errors is a possibility. For example: + + firstly { + API.fetchData() + }.recover(FetchError.self) { error in + guard case .missingImage(let partialData) = error else { throw error } + //… + return .value(dataWithDefaultImage) + } + + - Parameter only: The error type to be recovered. + - Parameter on: The queue to which the provided closure dispatches. + - Parameter flags: `DispatchWorkItemFlags` to be applied when dispatching. + - Parameter policy: The default policy does not execute your handler for cancellation errors. + - Parameter body: The handler to execute if this promise is rejected with the provided error type. + - SeeAlso: [Cancellation](https://github.com/mxcl/PromiseKit/blob/master/Documentation/CommonPatterns.md#cancellation) + */ + func recover(only: E.Type, on: DispatchQueue? = .pmkDefault, flags: DispatchWorkItemFlags? = nil, + policy: CatchPolicy = conf.catchPolicy, _ body: @escaping(E) throws -> V) -> CancellablePromise where V.U.T == C.T + { + let dispatcher = selectDispatcher(given: on, configured: conf.D.map, flags: flags) + return recover(only: only, on: dispatcher, policy: policy, body) + } +} diff --git a/Sources/PromiseKit/Wrappers/SequenceWrappers.swift b/Sources/PromiseKit/Wrappers/SequenceWrappers.swift new file mode 100644 index 000000000..afe2e5e98 --- /dev/null +++ b/Sources/PromiseKit/Wrappers/SequenceWrappers.swift @@ -0,0 +1,261 @@ +import Dispatch + +public extension Thenable where T: Sequence { + /** + `Promise<[T]>` => `T` -> `U` => `Promise<[U]>` + + firstly { + .value([1,2,3]) + }.mapValues { integer in + integer * 2 + }.done { + // $0 => [2,4,6] + } + */ + func mapValues(on: DispatchQueue? = .pmkDefault, flags: DispatchWorkItemFlags? = nil, _ transform: @escaping(T.Iterator.Element) throws -> U) -> Promise<[U]> { + let dispatcher = selectDispatcher(given: on, configured: conf.D.map, flags: flags) + return mapValues(on: dispatcher, transform) + } + + /** + `Promise<[T]>` => `T` -> `[U]` => `Promise<[U]>` + + firstly { + .value([1,2,3]) + }.flatMapValues { integer in + [integer, integer] + }.done { + // $0 => [1,1,2,2,3,3] + } + */ + func flatMapValues(on: DispatchQueue? = .pmkDefault, flags: DispatchWorkItemFlags? = nil, _ transform: @escaping(T.Iterator.Element) throws -> U) -> Promise<[U.Iterator.Element]> { + let dispatcher = selectDispatcher(given: on, configured: conf.D.map, flags: flags) + return flatMapValues(on: dispatcher, transform) + } + + /** + `Promise<[T]>` => `T` -> `U?` => `Promise<[U]>` + + firstly { + .value(["1","2","a","3"]) + }.compactMapValues { + Int($0) + }.done { + // $0 => [1,2,3] + } + */ + func compactMapValues(on: DispatchQueue? = .pmkDefault, flags: DispatchWorkItemFlags? = nil, _ transform: @escaping(T.Iterator.Element) throws -> U?) -> Promise<[U]> { + let dispatcher = selectDispatcher(given: on, configured: conf.D.map, flags: flags) + return compactMapValues(on: dispatcher, transform) + } + + /** + `Promise<[T]>` => `T` -> `Promise` => `Promise<[U]>` + + firstly { + .value([1,2,3]) + }.thenMap { integer in + .value(integer * 2) + }.done { + // $0 => [2,4,6] + } + */ + func thenMap(on: DispatchQueue? = .pmkDefault, flags: DispatchWorkItemFlags? = nil, _ transform: @escaping(T.Iterator.Element) throws -> U) -> Promise<[U.T]> { + let dispatcher = selectDispatcher(given: on, configured: conf.D.map, flags: flags) + return thenMap(on: dispatcher, transform) + } + + /** + `Promise<[T]>` => `T` -> `Promise<[U]>` => `Promise<[U]>` + + firstly { + .value([1,2,3]) + }.thenFlatMap { integer in + .value([integer, integer]) + }.done { + // $0 => [1,1,2,2,3,3] + } + */ + func thenFlatMap(on: DispatchQueue? = .pmkDefault, flags: DispatchWorkItemFlags? = nil, _ transform: @escaping(T.Iterator.Element) throws -> U) -> Promise<[U.T.Iterator.Element]> where U.T: Sequence { + let dispatcher = selectDispatcher(given: on, configured: conf.D.map, flags: flags) + return thenFlatMap(on: dispatcher, transform) + } + + /** + `Promise<[T]>` => `T` -> Bool => `Promise<[U]>` + + firstly { + .value([1,2,3]) + }.filterValues { + $0 > 1 + }.done { + // $0 => [2,3] + } + */ + func filterValues(on: DispatchQueue? = .pmkDefault, flags: DispatchWorkItemFlags? = nil, _ isIncluded: @escaping (T.Iterator.Element) -> Bool) -> Promise<[T.Iterator.Element]> { + let dispatcher = selectDispatcher(given: on, configured: conf.D.map, flags: flags) + return filterValues(on: dispatcher, isIncluded) + } +} + +public extension Thenable where T: Collection { + func firstValue(on: DispatchQueue? = .pmkDefault, flags: DispatchWorkItemFlags? = nil, where test: @escaping (T.Iterator.Element) -> Bool) -> Promise { + let dispatcher = selectDispatcher(given: on, configured: conf.D.map, flags: flags) + return firstValue(on: dispatcher, where: test) + } +} + +public extension Thenable where T: Sequence, T.Iterator.Element: Comparable { + /// - Returns: a promise fulfilled with the sorted values of this `Sequence`. + func sortedValues(on: DispatchQueue? = .pmkDefault, flags: DispatchWorkItemFlags? = nil) -> Promise<[T.Iterator.Element]> { + let dispatcher = selectDispatcher(given: on, configured: conf.D.map, flags: flags) + return sortedValues(on: dispatcher) + } +} + +public extension CancellableThenable where U.T: Sequence { + /** + `CancellablePromise<[U.T]>` => `U.T` -> `V` => `CancellablePromise<[V]>` + + firstly { + cancellize(Promise.value([1,2,3])) + }.mapValues { integer in + integer * 2 + }.done { + // $0 => [2,4,6] + } + */ + func mapValues(on: DispatchQueue? = .pmkDefault, flags: DispatchWorkItemFlags? = nil, _ transform: @escaping(U.T.Iterator.Element) throws -> V) -> CancellablePromise<[V]> { + let dispatcher = selectDispatcher(given: on, configured: conf.D.map, flags: flags) + return mapValues(on: dispatcher, transform) + } + + /** + `CancellablePromise<[U.T]>` => `U.T` -> `[V]` => `CancellablePromise<[V]>` + + firstly { + cancellize(Promise.value([1,2,3])) + }.flatMapValues { integer in + [integer, integer] + }.done { + // $0 => [1,1,2,2,3,3] + } + */ + func flatMapValues(on: DispatchQueue? = .pmkDefault, flags: DispatchWorkItemFlags? = nil, _ transform: @escaping(U.T.Iterator.Element) throws -> V) -> CancellablePromise<[V.Iterator.Element]> { + let dispatcher = selectDispatcher(given: on, configured: conf.D.map, flags: flags) + return flatMapValues(on: dispatcher, transform) + } + + /** + `CancellablePromise<[U.T]>` => `U.T` -> `V?` => `CancellablePromise<[V]>` + + firstly { + cancellize(Promise.value(["1","2","a","3"])) + }.compactMapValues { + Int($0) + }.done { + // $0 => [1,2,3] + } + */ + func compactMapValues(on: DispatchQueue? = .pmkDefault, flags: DispatchWorkItemFlags? = nil, _ transform: @escaping(U.T.Iterator.Element) throws -> V?) -> CancellablePromise<[V]> { + let dispatcher = selectDispatcher(given: on, configured: conf.D.map, flags: flags) + return compactMapValues(on: dispatcher, transform) + } + + /** + `CancellablePromise<[U.T]>` => `U.T` -> `CancellablePromise` => `CancellablePromise<[V]>` + + firstly { + cancellize(Promise.value([1,2,3])) + }.thenMap { integer in + cancellize(Promise.value(integer * 2)) + }.done { + // $0 => [2,4,6] + } + */ + func thenMap(on: DispatchQueue? = .pmkDefault, flags: DispatchWorkItemFlags? = nil, _ transform: @escaping(U.T.Iterator.Element) throws -> V) -> CancellablePromise<[V.U.T]> { + let dispatcher = selectDispatcher(given: on, configured: conf.D.map, flags: flags) + return thenMap(on: dispatcher, transform) + } + + /** + `CancellablePromise<[U.T]>` => `U.T` -> `Promise` => `CancellablePromise<[V]>` + + firstly { + Promise.value([1,2,3]) + }.cancellize().thenMap { integer in + .value(integer * 2) + }.done { + // $0 => [2,4,6] + } + */ + func thenMap(on: DispatchQueue? = .pmkDefault, flags: DispatchWorkItemFlags? = nil, _ transform: @escaping(U.T.Iterator.Element) throws -> V) -> CancellablePromise<[V.T]> { + let dispatcher = selectDispatcher(given: on, configured: conf.D.map, flags: flags) + return thenMap(on: dispatcher, transform) + } + + /** + `CancellablePromise<[T]>` => `T` -> `CancellablePromise<[U]>` => `CancellablePromise<[U]>` + + firstly { + cancellize(Promise.value([1,2,3])) + }.thenFlatMap { integer in + cancellize(Promise.value([integer, integer])) + }.done { + // $0 => [1,1,2,2,3,3] + } + */ + func thenFlatMap(on: DispatchQueue? = .pmkDefault, flags: DispatchWorkItemFlags? = nil, _ transform: @escaping(U.T.Iterator.Element) throws -> V) -> CancellablePromise<[V.U.T.Iterator.Element]> where V.U.T: Sequence { + let dispatcher = selectDispatcher(given: on, configured: conf.D.map, flags: flags) + return thenFlatMap(on: dispatcher, transform) + } + + /** + `CancellablePromise<[T]>` => `T` -> `Promise<[U]>` => `CancellablePromise<[U]>` + + firstly { + Promise.value([1,2,3]) + }.cancellize().thenFlatMap { integer in + .value([integer, integer]) + }.done { + // $0 => [1,1,2,2,3,3] + } + */ + func thenFlatMap(on: DispatchQueue? = .pmkDefault, flags: DispatchWorkItemFlags? = nil, _ transform: @escaping(U.T.Iterator.Element) throws -> V) -> CancellablePromise<[V.T.Iterator.Element]> where V.T: Sequence { + let dispatcher = selectDispatcher(given: on, configured: conf.D.map, flags: flags) + return thenFlatMap(on: dispatcher, transform) + } + + /** + `CancellablePromise<[T]>` => `T` -> Bool => `CancellablePromise<[U]>` + + firstly { + cancellize(Promise.value([1,2,3])) + }.filterValues { + $0 > 1 + }.done { + // $0 => [2,3] + } + */ + func filterValues(on: DispatchQueue? = .pmkDefault, flags: DispatchWorkItemFlags? = nil, _ isIncluded: @escaping (U.T.Iterator.Element) -> Bool) -> CancellablePromise<[U.T.Iterator.Element]> { + let dispatcher = selectDispatcher(given: on, configured: conf.D.map, flags: flags) + return filterValues(on: dispatcher, isIncluded) + } +} + +public extension CancellableThenable where U.T: Collection { + func firstValue(on: DispatchQueue? = .pmkDefault, flags: DispatchWorkItemFlags? = nil, where test: @escaping (U.T.Iterator.Element) -> Bool) -> CancellablePromise { + let dispatcher = selectDispatcher(given: on, configured: conf.D.map, flags: flags) + return firstValue(on: dispatcher, where: test) + } +} + +public extension CancellableThenable where U.T: Sequence, U.T.Iterator.Element: Comparable { + /// - Returns: a cancellable promise fulfilled with the sorted values of this `Sequence`. + func sortedValues(on: DispatchQueue? = .pmkDefault, flags: DispatchWorkItemFlags? = nil) -> CancellablePromise<[U.T.Iterator.Element]> { + let dispatcher = selectDispatcher(given: on, configured: conf.D.map, flags: flags) + return sortedValues(on: dispatcher) + } +} + + diff --git a/Sources/PromiseKit/Wrappers/ThenableWrappers.swift b/Sources/PromiseKit/Wrappers/ThenableWrappers.swift new file mode 100644 index 000000000..40adf92f5 --- /dev/null +++ b/Sources/PromiseKit/Wrappers/ThenableWrappers.swift @@ -0,0 +1,250 @@ +import Dispatch + +public extension _PMKSharedWrappers { + + /** + The provided closure is executed when this promise is resolved. + + Equivalent to `map { x -> Void in`, but since we force the `Void` return Swift + is happier and gives you less hassle about your closure’s qualification. + + firstly { + URLSession.shared.dataTask(.promise, with: url) + }.done { response in + print(response.data) + } + + - Parameter on: The queue to which the provided closure dispatches. + - Parameter flags: `DispatchWorkItemFlags` to be applied when dispatching. + - Parameter body: The closure that is executed when this Promise is fulfilled. + - Returns: A new promise fulfilled as `Void`. + */ + @_disfavoredOverload + func done(on: DispatchQueue? = .pmkDefault, flags: DispatchWorkItemFlags? = nil, _ body: @escaping(T) throws -> Void) -> BaseOfVoid { + let dispatcher = selectDispatcher(given: on, configured: conf.D.return, flags: flags) + return done(on: dispatcher, body) + } + + /** + The provided closure is executed when this promise is resolved. + + This is like `done` but it returns the same value that the handler is fed. + `get` immutably accesses the fulfilled value; the returned Promise maintains that value. + + firstly { + .value(1) + }.get { foo in + print(foo, " is 1") + }.done { foo in + print(foo, " is 1") + }.done { foo in + print(foo, " is Void") + } + + - Parameter on: The queue to which the provided closure dispatches. + - Parameter flags: `DispatchWorkItemFlags` to be applied when dispatching. + - Parameter body: The closure that is executed when this Promise is fulfilled. + - Returns: A new promise that is resolved with the value that the handler is fed. + */ + @_disfavoredOverload + func get(on: DispatchQueue? = .pmkDefault, flags: DispatchWorkItemFlags? = nil, _ body: @escaping (T) throws -> Void) -> BaseOfT { + let dispatcher = selectDispatcher(given: on, configured: conf.D.return, flags: flags) + return get(on: dispatcher, body) + } + + /** + The provided closure is executed with promise result. + + This is like `get` but provides the Result of the Promise so you can inspect the value of the chain at this point without causing any side effects. + + promise.tap{ print($0) }.then{ /*…*/ } + + - Parameter on: The queue to which the provided closure dispatches. + - Parameter flags: `DispatchWorkItemFlags` to be applied when dispatching. + - Parameter body: The closure that is executed with Result of Promise. + - Returns: A new promise that is resolved with the result that the handler is fed. + */ + @_disfavoredOverload + func tap(on: DispatchQueue? = .pmkDefault, flags: DispatchWorkItemFlags? = nil, _ body: @escaping(Result) -> Void) -> BaseOfT { + let dispatcher = selectDispatcher(given: on, configured: conf.D.map, flags: flags) + return tap(on: dispatcher, body) + } +} + +public extension Thenable { + + /** + The provided closure executes when this promise resolves. + + This allows chaining promises. The promise returned by the provided closure is resolved before the promise returned by this closure resolves. + + firstly { + URLSession.shared.dataTask(.promise, with: url1) + }.then { response in + transform(data: response.data) + }.done { transformation in + //… + } + + - Parameter on: The queue to which the provided closure dispatches. + - Parameter flags: `DispatchWorkItemFlags` to be applied when dispatching. + - Parameter body: The closure that executes when this promise fulfills. It must return a promise. + - Returns: A new promise that resolves when the promise returned from the provided closure resolves. + */ + @_disfavoredOverload + func then(on: DispatchQueue? = .pmkDefault, flags: DispatchWorkItemFlags? = nil, _ body: @escaping(T) throws -> U) -> Promise { + let dispatcher = selectDispatcher(given: on, configured: conf.D.map, flags: flags) + return then(on: dispatcher, body) + } + + /** + The provided closure is executed when this promise is resolved. + + This is like `then` but it requires the closure to return a non-promise. + + - Parameter on: The queue to which the provided closure dispatches. + - Parameter flags: `DispatchWorkItemFlags` to be applied when dispatching. + - Parameter transform: The closure that is executed when this Promise is fulfilled. It must return a non-promise. + - Returns: A new promise that is resolved with the value returned from the provided closure. For example: + + firstly { + URLSession.shared.dataTask(.promise, with: url1) + }.map { response in + response.data.length + }.done { length in + //… + } + */ + @_disfavoredOverload + func map(on: DispatchQueue? = .pmkDefault, flags: DispatchWorkItemFlags? = nil, _ transform: @escaping(T) throws -> U) -> Promise { + let dispatcher = selectDispatcher(given: on, configured: conf.D.map, flags: flags) + return map(on: dispatcher, transform) + } + + /** + The provided closure is executed when this promise is resolved. + + In your closure return an `Optional`, if you return `nil` the resulting promise is rejected with `PMKError.compactMap`, otherwise the promise is fulfilled with the unwrapped value. + + firstly { + URLSession.shared.dataTask(.promise, with: url) + }.compactMap { + try JSONSerialization.jsonObject(with: $0.data) as? [String: String] + }.done { dictionary in + //… + }.catch { + // either `PMKError.compactMap` or a `JSONError` + } + */ + @_disfavoredOverload + func compactMap(on: DispatchQueue? = .pmkDefault, flags: DispatchWorkItemFlags? = nil, _ transform: @escaping(T) throws -> U?) -> Promise { + let dispatcher = selectDispatcher(given: on, configured: conf.D.map, flags: flags) + return compactMap(on: dispatcher, transform) + } +} + +public extension CancellableThenable { + + /** + The provided closure executes when this cancellable promise resolves. + + This allows chaining promises. The cancellable promise returned by the provided closure is resolved before the cancellable promise returned by this closure resolves. + + let context = firstly { + URLSession.shared.dataTask(.promise, with: url1) + }.cancellize().then { response in + transform(data: response.data) // returns a CancellablePromise + }.done { transformation in + //… + }.cancelContext + //… + context.cancel() + + - Parameter on: The queue to which the provided closure dispatches. + - Parameter flags: `DispatchWorkItemFlags` to be applied when dispatching. + - Parameter body: The closure that executes when this cancellable promise fulfills. It must return a cancellable promise. + - Returns: A new cancellable promise that resolves when the promise returned from the provided closure resolves. + */ + @_disfavoredOverload + func then(on: DispatchQueue? = .pmkDefault, flags: DispatchWorkItemFlags? = nil, _ body: @escaping (U.T) throws -> V) -> CancellablePromise { + let dispatcher = selectDispatcher(given: on, configured: conf.D.map, flags: flags) + return then(on: dispatcher, body) + } + + /** + The provided closure executes when this cancellable promise resolves. + + This allows chaining promises. The promise returned by the provided closure is resolved before the cancellable promise returned by this closure resolves. + + let context = firstly { + URLSession.shared.dataTask(.promise, with: url1) + }.cancellize().then { response in + transform(data: response.data) // returns a Promise + }.done { transformation in + //… + }.cancelContext + //… + context.cancel() + + - Parameter on: The dispatcher that executes the provided closure. + - Parameter flags: `DispatchWorkItemFlags` to be applied when dispatching. + - Parameter body: The closure that executes when this cancellable promise fulfills. It must return a promise (not a cancellable promise). + - Returns: A new cancellable promise that resolves when the promise returned from the provided closure resolves. + */ + @_disfavoredOverload + func then(on: DispatchQueue? = .pmkDefault, flags: DispatchWorkItemFlags? = nil, _ body: @escaping (U.T) throws -> V) -> CancellablePromise { + let dispatcher = selectDispatcher(given: on, configured: conf.D.map, flags: flags) + return then(on: dispatcher, body) + } + + /** + The provided closure is executed when this cancellable promise is resolved. + + This is like `then` but it requires the closure to return a non-promise and non-cancellable-promise. + + let context = firstly { + URLSession.shared.dataTask(.promise, with: url1) + }.cancellize().map { response in + response.data.length + }.done { length in + //… + }.cancelContext + //… + context.cancel() + + - Parameter on: The queue to which the provided closure dispatches. + - Parameter flags: `DispatchWorkItemFlags` to be applied when dispatching. + - Parameter transform: The closure that is executed when this CancellablePromise is fulfilled. It must return a non-promise and non-cancellable-promise. + - Returns: A new cancellable promise that is resolved with the value returned from the provided closure. + */ + @_disfavoredOverload + func map(on: DispatchQueue? = .pmkDefault, flags: DispatchWorkItemFlags? = nil, _ transform: @escaping (U.T) throws -> V) -> CancellablePromise { + let dispatcher = selectDispatcher(given: on, configured: conf.D.map, flags: flags) + return map(on: dispatcher, transform) + } + + /** + The provided closure is executed when this cancellable promise is resolved. + + In your closure return an `Optional`, if you return `nil` the resulting cancellable promise is rejected + with `PMKError.compactMap`, otherwise the cancellable promise is fulfilled with the unwrapped value. + + let context = firstly { + URLSession.shared.dataTask(.promise, with: url) + }.cancellize().compactMap { + try JSONSerialization.jsonObject(with: $0.data) as? [String: String] + }.done { dictionary in + //… + }.catch { + // either `PMKError.compactMap` or a `JSONError` + }.cancelContext + //… + context.cancel() + */ + @_disfavoredOverload + func compactMap(on: DispatchQueue? = .pmkDefault, flags: DispatchWorkItemFlags? = nil, _ transform: @escaping (U.T) throws -> V?) -> CancellablePromise { + let dispatcher = selectDispatcher(given: on, configured: conf.D.map, flags: flags) + return compactMap(on: dispatcher, transform) + } +} + diff --git a/Sources/PromiseKit/Wrappers/WrapperProtocols.swift b/Sources/PromiseKit/Wrappers/WrapperProtocols.swift new file mode 100644 index 000000000..c668583b8 --- /dev/null +++ b/Sources/PromiseKit/Wrappers/WrapperProtocols.swift @@ -0,0 +1,82 @@ +import Dispatch + +// These are protocols that define DispatchQueue-based wrappers for functions that are found on multiple +// entities. By putting the wrappers in a separate mixin protocol, they can be added to the objects +// without duplication. +// +// Ideally, we would just add the mixin to protocols such as Thenable. However, Swift (as of v5) +// does not allow protocol extension that add conformance to other protocols. The underlying issue is the risk +// of overlapping conformances. See https://goo.gl/rViwWS. The workaround is to declare conformance on each +// underlying object separately. +// +// Associated types within protocols may not be generic, so there are many functions that can't be genericized +// in this way. For example, anything of the form `func foo(_ body: () -> U) -> Promise` is unrepresentable. +// +// These protocols have to be public to make their contents accessible to users, but the protocols themselves +// should never appear in Xcode or in the documentation. + +public protocol _PMKSharedWrappers { + + associatedtype T + associatedtype BaseOfT + associatedtype BaseOfVoid + associatedtype VoidReturn + + func done(on: Dispatcher, _ body: @escaping(T) throws -> Void) -> BaseOfVoid + func get(on: Dispatcher, _ body: @escaping(T) throws -> Void) -> BaseOfT + func tap(on: Dispatcher, _ body: @escaping(Result) -> Void) -> BaseOfT + + func recover(on: Dispatcher, policy: CatchPolicy, _ body: @escaping(Error) throws -> U) -> BaseOfT where U.T == T + func recover(only: E, on: Dispatcher, _ body: @escaping(E) throws -> U) -> BaseOfT where U.T == T, E: Equatable + func recover(only: E.Type, on: Dispatcher, policy: CatchPolicy, _ body: @escaping(E) throws -> U) -> BaseOfT where U.T == T + + func ensure(on: Dispatcher, _ body: @escaping () -> Void) -> BaseOfT + func ensureThen(on: Dispatcher, _ body: @escaping () -> VoidReturn) -> BaseOfT +} + +extension Promise: _PMKSharedWrappers { + public typealias T = T + public typealias BaseOfT = Promise +} + +extension CancellablePromise: _PMKSharedWrappers { + public typealias T = T + public typealias BaseOfT = CancellablePromise +} + +public protocol _PMKSharedVoidWrappers { + + associatedtype BaseOfT + + func recover(on: Dispatcher, policy: CatchPolicy, _ body: @escaping(Error) throws -> Void) -> BaseOfT + func recover(only: E, on: Dispatcher, _ body: @escaping(E) throws -> Void) -> BaseOfT where E: Equatable + func recover(only: E.Type, on: Dispatcher, policy: CatchPolicy, _ body: @escaping(E) throws -> Void) -> BaseOfT +} + +extension Promise: _PMKSharedVoidWrappers where T == Void {} +extension CancellablePromise: _PMKSharedVoidWrappers where C.T == Void {} + +public protocol _PMKCatchWrappers { + + associatedtype Finalizer + associatedtype CascadingFinalizer + + func `catch`(on: Dispatcher, policy: CatchPolicy, _ body: @escaping(Error) -> Void) -> Finalizer + func `catch`(only: E, on: Dispatcher, _ body: @escaping(E) -> Void) -> CascadingFinalizer where E: Equatable + func `catch`(only: E.Type, on: Dispatcher, policy: CatchPolicy, _ body: @escaping(E) -> Void) -> CascadingFinalizer +} + +extension Promise: _PMKCatchWrappers {} +extension PMKCascadingFinalizer: _PMKCatchWrappers {} +extension CancellablePromise: _PMKCatchWrappers {} +extension CancellableCascadingFinalizer: _PMKCatchWrappers {} + +public protocol _PMKFinallyWrappers { + + associatedtype FinallyReturn + + func finally(on: Dispatcher, _ body: @escaping () -> Void) -> FinallyReturn +} + +extension PMKFinalizer: _PMKFinallyWrappers {} +extension CancellableFinalizer: _PMKFinallyWrappers {} diff --git a/Sources/after.swift b/Sources/PromiseKit/after.swift similarity index 60% rename from Sources/after.swift rename to Sources/PromiseKit/after.swift index cdaeccd9e..eadb0aa6f 100644 --- a/Sources/after.swift +++ b/Sources/PromiseKit/after.swift @@ -1,21 +1,25 @@ import struct Foundation.TimeInterval import Dispatch + +/// Extend DispatchWorkItem to be cancellable +extension DispatchWorkItem: Cancellable { } + /** after(seconds: 1.5).then { //… } - Returns: A guarantee that resolves after the specified duration. +- Note: cancelling this guarantee will cancel the underlying timer task +- SeeAlso: [Cancellation](http://promisekit.org/docs/) */ public func after(seconds: TimeInterval) -> Guarantee { let (rg, seal) = Guarantee.pending() let when = DispatchTime.now() + seconds -#if swift(>=4.0) - q.asyncAfter(deadline: when) { seal(()) } -#else - q.asyncAfter(deadline: when, execute: seal) -#endif + let task = DispatchWorkItem { seal(()) } + rg.setCancellable(task) + q.asyncAfter(deadline: when, execute: task) return rg } @@ -25,15 +29,15 @@ public func after(seconds: TimeInterval) -> Guarantee { } - Returns: A guarantee that resolves after the specified duration. + - Note: cancelling this guarantee will cancel the underlying timer task + - SeeAlso: [Cancellation](http://promisekit.org/docs/) */ public func after(_ interval: DispatchTimeInterval) -> Guarantee { let (rg, seal) = Guarantee.pending() let when = DispatchTime.now() + interval -#if swift(>=4.0) - q.asyncAfter(deadline: when) { seal(()) } -#else - q.asyncAfter(deadline: when, execute: seal) -#endif + let task = DispatchWorkItem { seal(()) } + rg.setCancellable(task) + q.asyncAfter(deadline: when, execute: task) return rg } diff --git a/Sources/PromiseKit/firstly.swift b/Sources/PromiseKit/firstly.swift new file mode 100644 index 000000000..e1b656d57 --- /dev/null +++ b/Sources/PromiseKit/firstly.swift @@ -0,0 +1,89 @@ +import Dispatch + +/** + Judicious use of `firstly` *may* make chains more readable. + + Compare: + + URLSession.shared.dataTask(url: url1).then { + URLSession.shared.dataTask(url: url2) + }.then { + URLSession.shared.dataTask(url: url3) + } + + With: + + firstly { + URLSession.shared.dataTask(url: url1) + }.then { + URLSession.shared.dataTask(url: url2) + }.then { + URLSession.shared.dataTask(url: url3) + } + + - Note: the block you pass executes immediately on the current thread/queue. + */ +public func firstly(execute body: () throws -> U) -> Promise { + do { + let rp = Promise(.pending) + try body().pipe(to: rp.box.seal) + return rp + } catch { + return Promise(error: error) + } +} + +/// - See: firstly() +public func firstly(execute body: () -> Guarantee) -> Guarantee { + return body() +} + +//////////////////////////////////////////////////////////// Cancellation + +/** + `firstly` for cancellable promises. + + Compare: + + let context = URLSession.shared.dataTask(url: url1).cancellize().then { + URLSession.shared.dataTask(url: url2) + }.then { + URLSession.shared.dataTask(url: url3) + }.cancelContext + + // … + + context.cancel() + + With: + + let context = firstly { + URLSession.shared.dataTask(url: url1) + }.cancellize().then { + URLSession.shared.dataTask(url: url2) + }.then { + URLSession.shared.dataTask(url: url3) + }.cancelContext + + // … + + context.cancel() + + - Note: the block you pass excecutes immediately on the current thread/queue. + - See: firstly(execute: () -> Thenable) +*/ +public func firstly(execute body: () throws -> V) -> CancellablePromise { + do { + let rv = try body() + let rp: CancellablePromise + if let promise = rv as? CancellablePromise { + rp = promise + } else { + rp = CancellablePromise(rv.thenable) + } + rp.appendCancelContext(from: rv) + return rp + } catch { + return CancellablePromise(error: error) + } +} diff --git a/Sources/hang.swift b/Sources/PromiseKit/hang.swift similarity index 77% rename from Sources/hang.swift rename to Sources/PromiseKit/hang.swift index 1022dcad7..5c5498d04 100644 --- a/Sources/hang.swift +++ b/Sources/PromiseKit/hang.swift @@ -1,3 +1,5 @@ +#if canImport(CoreFoundation) + import Foundation import CoreFoundation @@ -14,7 +16,7 @@ import CoreFoundation */ public func hang(_ promise: Promise) throws -> T { #if os(Linux) || os(Android) -#if swift(>=4) +#if compiler(>=5) let runLoopMode: CFRunLoopMode = kCFRunLoopDefaultMode #else // isMainThread is not yet implemented on Linux. @@ -47,9 +49,22 @@ public func hang(_ promise: Promise) throws -> T { } switch promise.result! { - case .rejected(let error): + case .failure(let error): throw error - case .fulfilled(let value): + case .success(let value): return value } } + +//////////////////////////////////////////////////////////// Cancellation + +/** + Runs the active run-loop until the provided promise resolves. + + Simply calls `hang` directly on the delegate promise, so the behavior is exactly the same with Promise and CancellablePromise. + */ +public func hang(_ promise: CancellablePromise) throws -> T { + return try hang(promise.promise) +} + +#endif diff --git a/Sources/PromiseKit/race.swift b/Sources/PromiseKit/race.swift new file mode 100644 index 000000000..eaab34eed --- /dev/null +++ b/Sources/PromiseKit/race.swift @@ -0,0 +1,188 @@ +import struct Foundation.TimeInterval +import Dispatch + +@inline(__always) +private func _race(_ thenables: [U]) -> Promise { + let rp = Promise(.pending) + for thenable in thenables { + thenable.pipe(to: rp.box.seal) + } + return rp +} + +/** + Waits for one promise to resolve + + race(promise1, promise2, promise3).then { winner in + //… + } + + - Returns: The promise that resolves first + - Warning: If the first resolution is a rejection, the returned promise is rejected +*/ +public func race(_ thenables: U...) -> Promise { + return _race(thenables) +} + +/** + Waits for one promise to resolve + + race(promise1, promise2, promise3).then { winner in + //… + } + + - Returns: The promise that resolves first + - Warning: If the first resolution is a rejection, the returned promise is rejected + - Remark: If the provided array is empty the returned promise is rejected with PMKError.badInput +*/ +public func race(_ thenables: [U]) -> Promise { + guard !thenables.isEmpty else { + return Promise(error: PMKError.badInput) + } + return _race(thenables) +} + +/** + Waits for one guarantee to resolve + + race(promise1, promise2, promise3).then { winner in + //… + } + + - Returns: The guarantee that resolves first +*/ +public func race(_ guarantees: Guarantee...) -> Guarantee { + let rg = Guarantee(.pending) + for guarantee in guarantees { + guarantee.pipe(to: rg.box.seal) + } + return rg +} + +//////////////////////////////////////////////////////////// Cancellation + +/** + Resolves with the first resolving cancellable promise from a set of cancellable promises. Calling + `cancel` on the race promise cancels all pending promises. All promises will be cancelled if any + promise rejects. + + let racePromise = race(promise1, promise2, promise3).then { winner in + //… + } + + //… + + racePromise.cancel() + + - Returns: A new promise that resolves when the first promise in the provided promises resolves. + - Warning: If any of the provided promises reject, the returned promise is rejected. + - Warning: aborts if the array is empty. +*/ +public func race(_ thenables: V...) -> CancellablePromise { + return race(thenables) +} + +/** + Resolves with the first resolving promise from a set of promises. Calling `cancel` on the race + promise cancels all pending promises. All promises will be cancelled if any promise rejects. + + let racePromise = race(promise1, promise2, promise3).then { winner in + //… + } + + //… + + racePromise.cancel() + + - Returns: A new promise that resolves when the first promise in the provided promises resolves. + - Warning: If any of the provided promises reject, the returned promise is rejected. + - Remark: Returns promise rejected with PMKError.badInput if empty array provided +*/ +public func race(_ thenables: [V]) -> CancellablePromise { + guard !thenables.isEmpty else { + return CancellablePromise(error: PMKError.badInput) + } + + let cancelThenables: (Result) -> Void = { result in + if case .failure = result { + for t in thenables { + if !t.cancelAttempted { + t.cancel() + } + } + } + } + + let promise = CancellablePromise(race(asThenables(thenables))) + for t in thenables { + t.thenable.pipe(to: cancelThenables) + promise.appendCancelContext(from: t) + } + return promise +} + +/** + Waits for one promise to fulfill + + race(fulfilled: [promise1, promise2, promise3]).then { winner in + //… + } + + - Returns: The promise that was fulfilled first. + - Warning: Skips all rejected promises. + - Remark: If the provided array is empty, the returned promise is rejected with `PMKError.badInput`. If there are no fulfilled promises, the returned promise is rejected with `PMKError.noWinner`. +*/ +public func race(fulfilled thenables: [U]) -> Promise { + var countdown = thenables.count + guard countdown > 0 else { + return Promise(error: PMKError.badInput) + } + + let rp = Promise(.pending) + + let barrier = DispatchQueue(label: "org.promisekit.barrier.race", attributes: .concurrent) + + for promise in thenables { + promise.pipe { result in + barrier.sync(flags: .barrier) { + switch result { + case .failure: + guard rp.isPending else { return } + countdown -= 1 + if countdown == 0 { + rp.box.seal(.failure(PMKError.noWinner)) + } + case .success(let value): + guard rp.isPending else { return } + countdown = 0 + rp.box.seal(.success(value)) + } + } + } + } + + return rp +} + +/** + Returns a promise that can be used to set a timeout for `race`. + + let promise1, promise2: Promise + race(promise1, promise2, timeout(seconds: 1.0)).done { winner in + //… + }.catch(policy: .allErrors) { + // Rejects with `PMKError.timedOut` if the timeout is exceeded before either `promise1` or + // `promise2` succeeds. + } + + When used with cancellable promises, all promises will be cancelled if the timeout is + exceeded or any promise rejects: + + let promise1, promise2: CancellablePromise + race(promise1, promise2, cancellize(timeout(seconds: 1.0))).done { winner in + //… + } + */ +public func timeout(seconds: TimeInterval) -> Promise { + return after(seconds: seconds).done { throw PMKError.timedOut } +} diff --git a/Sources/when.swift b/Sources/PromiseKit/when.swift similarity index 54% rename from Sources/when.swift rename to Sources/PromiseKit/when.swift index 44335b84f..eb548babf 100644 --- a/Sources/when.swift +++ b/Sources/PromiseKit/when.swift @@ -9,7 +9,7 @@ private func _when(_ thenables: [U]) -> Promise { let rp = Promise(.pending) -#if PMKDisableProgress || os(Linux) +#if PMKDisableProgress || os(Linux) || os(Android) var progress: (completedUnitCount: Int, totalUnitCount: Int) = (0, 0) #else let progress = Progress(totalUnitCount: Int64(thenables.count)) @@ -23,17 +23,17 @@ private func _when(_ thenables: [U]) -> Promise { promise.pipe { result in barrier.sync(flags: .barrier) { switch result { - case .rejected(let error): + case .failure(let error): if rp.isPending { progress.completedUnitCount = progress.totalUnitCount - rp.box.seal(.rejected(error)) + rp.box.seal(.failure(error)) } - case .fulfilled: + case .success: guard rp.isPending else { return } progress.completedUnitCount += 1 countdown -= 1 if countdown == 0 { - rp.box.seal(.fulfilled(())) + rp.box.seal(.success(())) } } } @@ -106,7 +106,7 @@ public func when Promise { - // ... + // … } let urls: [URL] = /*…*/ @@ -120,7 +120,7 @@ public func when(fulfilled promiseIterator: It, concurrent func testDone() { barrier.sync { if pendingPromises == 0 { - #if !swift(>=3.3) || (swift(>=4) && !swift(>=4.1)) - root.resolver.fulfill(promises.flatMap{ $0.value }) - #else root.resolver.fulfill(promises.compactMap{ $0.value }) - #endif } } } @@ -185,10 +181,10 @@ public func when(fulfilled promiseIterator: It, concurrent } switch resolution { - case .fulfilled: + case .success: dequeue() testDone() - case .rejected(let error): + case .failure(let error): root.resolver.reject(error) } } @@ -207,7 +203,7 @@ public func when(fulfilled promiseIterator: It, concurrent `when(fulfilled:)` rejects as soon as one of the provided promises rejects. `when(resolved:)` waits on all provided promises whatever their result, and then provides an array of `Result` so you can individually inspect the results. As a consequence this function returns a `Guarantee`, ie. errors are lifted from the individual promises into the results array of the returned `Guarantee`. when(resolved: promise1, promise2, promise3).then { results in - for result in results where case .fulfilled(let value) { + for result in results where case .success(let value) { //… } }.catch { error in @@ -218,12 +214,12 @@ public func when(fulfilled promiseIterator: It, concurrent - Note: we do not provide tuple variants for `when(resolved:)` but will accept a pull-request - Remark: Doesn't take Thenable due to protocol `associatedtype` paradox */ -public func when(resolved promises: Promise...) -> Guarantee<[Result]> { +public func when(resolved promises: Promise...) -> Guarantee<[Result]> { return when(resolved: promises) } /// - See: `when(resolved: Promise...)` -public func when(resolved promises: [Promise]) -> Guarantee<[Result]> { +public func when(resolved promises: [Promise]) -> Guarantee<[Result]> { guard !promises.isEmpty else { return .value([]) } @@ -231,7 +227,7 @@ public func when(resolved promises: [Promise]) -> Guarantee<[Result]> { var countdown = promises.count let barrier = DispatchQueue(label: "org.promisekit.barrier.join", attributes: .concurrent) - let rg = Guarantee<[Result]>(.pending) + let rg = Guarantee<[Result]>(.pending) for promise in promises { promise.pipe { result in barrier.sync(flags: .barrier) { @@ -278,15 +274,14 @@ No more than three downloads will occur simultaneously. Downloads will continue - Returns: A new promise that resolves once all the provided promises resolve. The array is ordered the same as the input, ie. the result order is *not* resolution order. - SeeAlso: `when(resolved:)` */ -#if swift(>=5.3) public func when(resolved promiseIterator: It, concurrently: Int) - -> Guarantee<[Result]> where It.Element: Thenable { + -> Guarantee<[Result]> where It.Element: Thenable { guard concurrently > 0 else { - return Guarantee.value([Result.rejected(PMKError.badInput)]) + return Guarantee.value([Result.failure(PMKError.badInput)]) } var generator = promiseIterator - let root = Guarantee<[Result]>.pending() + let root = Guarantee<[Result]>.pending() var pendingPromises = 0 var promises: [It.Element] = [] @@ -350,7 +345,6 @@ public func when(resolved promiseIterator: It, concurrentl return root.guarantee } -#endif /// Waits on all provided Guarantees. public func when(_ guarantees: Guarantee...) -> Guarantee { @@ -361,3 +355,228 @@ public func when(_ guarantees: Guarantee...) -> Guarantee { public func when(guarantees: [Guarantee]) -> Guarantee { return when(fulfilled: guarantees).recover{ _ in }.asVoid() } + +//////////////////////////////////////////////////////////// Cancellation + +/** + Wait for all cancellable promises in a set to fulfill. + + For example: + + let p = when(fulfilled: promise1, promise2).then { results in + //… + }.catch { error in + switch error { + case URLError.notConnectedToInternet: + //… + case CLError.denied: + //… + } + } + + //… + + p.cancel() + + - Note: If *any* of the provided promises reject, the returned promise is immediately rejected with that error. + - Warning: In the event of rejection the other promises will continue to resolve and, as per any other promise, will either fulfill or reject. This is the right pattern for `getter` style asynchronous tasks, but often for `setter` tasks (eg. storing data on a server), you most likely will need to wait on all tasks and then act based on which have succeeded and which have failed, in such situations use `when(resolved:)`. + - Parameter promises: The promises upon which to wait before the returned promise resolves. + - Returns: A new promise that resolves when all the provided promises fulfill or one of the provided promises rejects. + - Note: `when` provides `NSProgress`. + - SeeAlso: `when(resolved:)` +*/ +public func when(fulfilled thenables: V...) -> CancellablePromise<[V.U.T]> { + let rp = CancellablePromise(when(fulfilled: asThenables(thenables))) + for t in thenables { + rp.appendCancelContext(from: t) + } + return rp +} + +public func when(fulfilled thenables: [V]) -> CancellablePromise<[V.U.T]> { + let rp = CancellablePromise(when(fulfilled: asThenables(thenables))) + for t in thenables { + rp.appendCancelContext(from: t) + } + return rp +} + +/// Wait for all cancellable promises in a set to fulfill. +public func when(fulfilled promises: V...) -> CancellablePromise where V.U.T == Void { + let rp = CancellablePromise(when(fulfilled: asThenables(promises))) + for p in promises { + rp.appendCancelContext(from: p) + } + return rp +} + +/// Wait for all cancellable promises in a set to fulfill. +public func when(fulfilled promises: [V]) -> CancellablePromise where V.U.T == Void { + let rp = CancellablePromise(when(fulfilled: asThenables(promises))) + for p in promises { + rp.appendCancelContext(from: p) + } + return rp +} + +/** + Wait for all cancellable promises in a set to fulfill. + + - Note: by convention the cancellable 'when' functions should not have a 'cancellable' prefix, however the prefix is necessary due to a compiler bug exemplified by the following: + + ```` + This works fine: + 1 func hi(_: String...) { } + 2 func hi(_: String, _: String) { } + 3 hi("hi", "there") + + This does not compile: + 1 func hi(_: String...) { } + 2 func hi(_: String, _: String) { } + 3 func hi(_: Int...) { } + 4 func hi(_: Int, _: Int) { } + 5 + 6 hi("hi", "there") // Ambiguous use of 'hi' (lines 1 & 2 are candidates) + 7 hi(1, 2) // Ambiguous use of 'hi' (lines 3 & 4 are candidates) + ```` + + - SeeAlso: `when(fulfilled:,_:)` +*/ +public func cancellableWhen(fulfilled pu: U, _ pv: V) -> CancellablePromise<(U.U.T, V.U.T)> { + return when(fulfilled: [pu.asVoid(), pv.asVoid()]).map(on: nil) { (pu.value!, pv.value!) } +} + +/// Wait for all cancellable promises in a set to fulfill. +/// - SeeAlso: `when(fulfilled:,_:)` +public func cancellableWhen(fulfilled pu: U, _ pv: V, _ pw: W) -> CancellablePromise<(U.U.T, V.U.T, W.U.T)> { + return when(fulfilled: [pu.asVoid(), pv.asVoid(), pw.asVoid()]).map(on: nil) { (pu.value!, pv.value!, pw.value!) } +} + +/// Wait for all cancellable promises in a set to fulfill. +/// - SeeAlso: `when(fulfilled:,_:)` +public func cancellableWhen(fulfilled pu: U, _ pv: V, _ pw: W, _ px: X) -> CancellablePromise<(U.U.T, V.U.T, W.U.T, X.U.T)> { + return when(fulfilled: [pu.asVoid(), pv.asVoid(), pw.asVoid(), px.asVoid()]).map(on: nil) { (pu.value!, pv.value!, pw.value!, px.value!) } +} + +/// Wait for all cancellable promises in a set to fulfill. +/// - SeeAlso: `when(fulfilled:,_:)` +public func cancellableWhen(fulfilled pu: U, _ pv: V, _ pw: W, _ px: X, _ py: Y) -> CancellablePromise<(U.U.T, V.U.T, W.U.T, X.U.T, Y.U.T)> { + return when(fulfilled: [pu.asVoid(), pv.asVoid(), pw.asVoid(), px.asVoid(), py.asVoid()]).map(on: nil) { (pu.value!, pv.value!, pw.value!, px.value!, py.value!) } +} + +/** + Generate cancellable promises at a limited rate and wait for all to fulfill. Call `cancel` on the returned promise to cancel all currently pending promises. + + For example: + + func downloadFile(url: URL) -> CancellablePromise { + // … + } + + let urls: [URL] = /*…*/ + let urlGenerator = urls.makeIterator() + + let generator = AnyIterator> { + guard url = urlGenerator.next() else { + return nil + } + return downloadFile(url) + } + + let promise = when(generator, concurrently: 3).done { datas in + // … + } + + // … + + promise.cancel() + + + No more than three downloads will occur simultaneously. + + - Note: The generator is called *serially* on a *background* queue. + - Warning: Refer to the warnings on `when(fulfilled:)` + - Parameter promiseGenerator: Generator of promises. + - Parameter cancel: Optional cancel context, overrides the default context. + - Returns: A new promise that resolves when all the provided promises fulfill or one of the provided promises rejects. + - SeeAlso: `when(resolved:)` + */ +public func when(fulfilled promiseIterator: It, concurrently: Int) -> CancellablePromise<[It.Element.U.T]> where It.Element: CancellableThenable { + guard concurrently > 0 else { + return CancellablePromise(error: PMKError.badInput) + } + + var pi = promiseIterator + var generatedPromises: [CancellablePromise] = [] + var rootPromise: CancellablePromise<[It.Element.U.T]>! + + let generator = AnyIterator> { + guard let promise = pi.next() as? CancellablePromise else { + return nil + } + if let root = rootPromise { + root.appendCancelContext(from: promise) + } else { + generatedPromises.append(promise) + } + return promise.promise + } + + rootPromise = CancellablePromise(when(fulfilled: generator, concurrently: concurrently)) + for p in generatedPromises { + rootPromise.appendCancelContext(from: p) + } + return rootPromise +} + +/** + Waits on all provided cancellable promises. + + `when(fulfilled:)` rejects as soon as one of the provided promises rejects. `when(resolved:)` waits on all provided promises and *never* rejects. When cancelled, all promises will attempt to be cancelled and those that are successfully cancelled will have a result of + PMKError.cancelled. + + let p = when(resolved: promise1, promise2, promise3, cancel: context).then { results in + for result in results where case .fulfilled(let value) { + //… + } + }.catch { error in + // invalid! Never rejects + } + + //… + + p.cancel() + + - Returns: A new promise that resolves once all the provided promises resolve. The array is ordered the same as the input, ie. the result order is *not* resolution order. + - Note: Any promises that error are implicitly consumed. + - Remark: Doesn't take CancellableThenable due to protocol associatedtype paradox +*/ +public func when(resolved promises: CancellablePromise...) -> CancellablePromise<[Result]> { + return when(resolved: promises) +} + +/// Waits on all provided cancellable promises. +/// - SeeAlso: `when(resolved:)` +public func when(resolved promises: [CancellablePromise]) -> CancellablePromise<[Result]> { + let rp = CancellablePromise(when(resolved: asPromises(promises))) + for p in promises { + rp.appendCancelContext(from: p) + } + return rp +} + +func asThenables(_ cancellableThenables: [V]) -> [V.U] { + var thenables: [V.U] = [] + for ct in cancellableThenables { + thenables.append(ct.thenable) + } + return thenables +} + +func asPromises(_ cancellablePromises: [CancellablePromise]) -> [Promise] { + var promises = [Promise]() + for cp in cancellablePromises { + promises.append(cp.promise) + } + return promises +} diff --git a/Sources/after.m b/Sources/after.m deleted file mode 100644 index 25f9966fc..000000000 --- a/Sources/after.m +++ /dev/null @@ -1,14 +0,0 @@ -#import "AnyPromise.h" -@import Dispatch; -@import Foundation.NSDate; -@import Foundation.NSValue; - -/// @return A promise that fulfills after the specified duration. -AnyPromise *PMKAfter(NSTimeInterval duration) { - return [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) { - dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(duration * NSEC_PER_SEC)); - dispatch_after(time, dispatch_get_global_queue(0, 0), ^{ - resolve(@(duration)); - }); - }]; -} diff --git a/Sources/dispatch_promise.m b/Sources/dispatch_promise.m deleted file mode 100644 index ecb89f711..000000000 --- a/Sources/dispatch_promise.m +++ /dev/null @@ -1,10 +0,0 @@ -#import "AnyPromise.h" -@import Dispatch; - -AnyPromise *dispatch_promise_on(dispatch_queue_t queue, id block) { - return [AnyPromise promiseWithValue:nil].thenOn(queue, block); -} - -AnyPromise *dispatch_promise(id block) { - return dispatch_promise_on(dispatch_get_global_queue(0, 0), block); -} diff --git a/Sources/firstly.swift b/Sources/firstly.swift deleted file mode 100644 index 4bfc03858..000000000 --- a/Sources/firstly.swift +++ /dev/null @@ -1,39 +0,0 @@ -import Dispatch - -/** - Judicious use of `firstly` *may* make chains more readable. - - Compare: - - URLSession.shared.dataTask(url: url1).then { - URLSession.shared.dataTask(url: url2) - }.then { - URLSession.shared.dataTask(url: url3) - } - - With: - - firstly { - URLSession.shared.dataTask(url: url1) - }.then { - URLSession.shared.dataTask(url: url2) - }.then { - URLSession.shared.dataTask(url: url3) - } - - - Note: the block you pass executes immediately on the current thread/queue. - */ -public func firstly(execute body: () throws -> U) -> Promise { - do { - let rp = Promise(.pending) - try body().pipe(to: rp.box.seal) - return rp - } catch { - return Promise(error: error) - } -} - -/// - See: firstly() -public func firstly(execute body: () -> Guarantee) -> Guarantee { - return body() -} diff --git a/Sources/fwd.h b/Sources/fwd.h deleted file mode 100644 index 480d1480e..000000000 --- a/Sources/fwd.h +++ /dev/null @@ -1,165 +0,0 @@ -#import -#import - -@class AnyPromise; -extern NSString * __nonnull const PMKErrorDomain; - -#define PMKFailingPromiseIndexKey @"PMKFailingPromiseIndexKey" -#define PMKJoinPromisesKey @"PMKJoinPromisesKey" - -#define PMKUnexpectedError 1l -#define PMKInvalidUsageError 3l -#define PMKAccessDeniedError 4l -#define PMKOperationFailed 8l -#define PMKTaskError 9l -#define PMKJoinError 10l - - -#ifdef __cplusplus -extern "C" { -#endif - -/** - @return A new promise that resolves after the specified duration. - - @parameter duration The duration in seconds to wait before this promise is resolve. - - For example: - - PMKAfter(1).then(^{ - //… - }); -*/ -extern AnyPromise * __nonnull PMKAfter(NSTimeInterval duration) NS_REFINED_FOR_SWIFT; - - - -/** - `when` is a mechanism for waiting more than one asynchronous task and responding when they are all complete. - - `PMKWhen` accepts varied input. If an array is passed then when those promises fulfill, when’s promise fulfills with an array of fulfillment values. If a dictionary is passed then the same occurs, but when’s promise fulfills with a dictionary of fulfillments keyed as per the input. - - Interestingly, if a single promise is passed then when waits on that single promise, and if a single non-promise object is passed then when fulfills immediately with that object. If the array or dictionary that is passed contains objects that are not promises, then these objects are considered fulfilled promises. The reason we do this is to allow a pattern know as "abstracting away asynchronicity". - - If *any* of the provided promises reject, the returned promise is immediately rejected with that promise’s rejection. The error’s `userInfo` object is supplemented with `PMKFailingPromiseIndexKey`. - - For example: - - PMKWhen(@[promise1, promise2]).then(^(NSArray *results){ - //… - }); - - @warning *Important* In the event of rejection the other promises will continue to resolve and as per any other promise will either fulfill or reject. This is the right pattern for `getter` style asynchronous tasks, but often for `setter` tasks (eg. storing data on a server), you most likely will need to wait on all tasks and then act based on which have succeeded and which have failed. In such situations use `PMKJoin`. - - @param input The input upon which to wait before resolving this promise. - - @return A promise that is resolved with either: - - 1. An array of values from the provided array of promises. - 2. The value from the provided promise. - 3. The provided non-promise object. - - @see PMKJoin - -*/ -extern AnyPromise * __nonnull PMKWhen(id __nonnull input) NS_REFINED_FOR_SWIFT; - - - -/** - Creates a new promise that resolves only when all provided promises have resolved. - - Typically, you should use `PMKWhen`. - - For example: - - PMKJoin(@[promise1, promise2]).then(^(NSArray *resultingValues){ - //… - }).catch(^(NSError *error){ - assert(error.domain == PMKErrorDomain); - assert(error.code == PMKJoinError); - - NSArray *promises = error.userInfo[PMKJoinPromisesKey]; - for (AnyPromise *promise in promises) { - if (promise.rejected) { - //… - } - } - }); - - @param promises An array of promises. - - @return A promise that thens three parameters: - - 1) An array of mixed values and errors from the resolved input. - 2) An array of values from the promises that fulfilled. - 3) An array of errors from the promises that rejected or nil if all promises fulfilled. - - @see when -*/ -AnyPromise *__nonnull PMKJoin(NSArray * __nonnull promises) NS_REFINED_FOR_SWIFT; - - - -/** - Literally hangs this thread until the promise has resolved. - - Do not use hang… unless you are testing, playing or debugging. - - If you use it in production code I will literally and honestly cry like a child. - - @return The resolved value of the promise. - - @warning T SAFE. IT IS NOT SAFE. IT IS NOT SAFE. IT IS NOT SAFE. IT IS NO -*/ -extern id __nullable PMKHang(AnyPromise * __nonnull promise); - - - -/** - Executes the provided block on a background queue. - - dispatch_promise is a convenient way to start a promise chain where the - first step needs to run synchronously on a background queue. - - dispatch_promise(^{ - return md5(input); - }).then(^(NSString *md5){ - NSLog(@"md5: %@", md5); - }); - - @param block The block to be executed in the background. Returning an `NSError` will reject the promise, everything else (including void) fulfills the promise. - - @return A promise resolved with the return value of the provided block. - - @see dispatch_async -*/ -extern AnyPromise * __nonnull dispatch_promise(id __nonnull block) NS_SWIFT_UNAVAILABLE("Use our `DispatchQueue.async` override instead"); - - - -/** - Executes the provided block on the specified background queue. - - dispatch_promise_on(myDispatchQueue, ^{ - return md5(input); - }).then(^(NSString *md5){ - NSLog(@"md5: %@", md5); - }); - - @param block The block to be executed in the background. Returning an `NSError` will reject the promise, everything else (including void) fulfills the promise. - - @return A promise resolved with the return value of the provided block. - - @see dispatch_promise -*/ -extern AnyPromise * __nonnull dispatch_promise_on(dispatch_queue_t __nonnull queue, id __nonnull block) NS_SWIFT_UNAVAILABLE("Use our `DispatchQueue.async` override instead"); - -/** - Returns a new promise that resolves when the value of the first resolved promise in the provided array of promises. -*/ -extern AnyPromise * __nonnull PMKRace(NSArray * __nonnull promises) NS_REFINED_FOR_SWIFT; - -#ifdef __cplusplus -} // Extern C -#endif diff --git a/Sources/hang.m b/Sources/hang.m deleted file mode 100644 index 913339e51..000000000 --- a/Sources/hang.m +++ /dev/null @@ -1,29 +0,0 @@ -#import "AnyPromise.h" -#import "AnyPromise+Private.h" -@import CoreFoundation.CFRunLoop; - -/** - Suspends the active thread waiting on the provided promise. - - @return The value of the provided promise once resolved. - */ -id PMKHang(AnyPromise *promise) { - if (promise.pending) { - static CFRunLoopSourceContext context; - - CFRunLoopRef runLoop = CFRunLoopGetCurrent(); - CFRunLoopSourceRef runLoopSource = CFRunLoopSourceCreate(NULL, 0, &context); - CFRunLoopAddSource(runLoop, runLoopSource, kCFRunLoopDefaultMode); - - promise.ensure(^{ - CFRunLoopStop(runLoop); - }); - while (promise.pending) { - CFRunLoopRun(); - } - CFRunLoopRemoveSource(runLoop, runLoopSource, kCFRunLoopDefaultMode); - CFRelease(runLoopSource); - } - - return promise.value; -} diff --git a/Sources/join.m b/Sources/join.m deleted file mode 100644 index 979f092df..000000000 --- a/Sources/join.m +++ /dev/null @@ -1,54 +0,0 @@ -@import Foundation.NSDictionary; -#import "AnyPromise+Private.h" -#import -@import Foundation.NSError; -@import Foundation.NSNull; -#import "PromiseKit.h" -#import - -/** - Waits on all provided promises. - - `PMKWhen` rejects as soon as one of the provided promises rejects. `PMKJoin` waits on all provided promises, then rejects if any of those promises rejects, otherwise it fulfills with values from the provided promises. - - - Returns: A new promise that resolves once all the provided promises resolve. -*/ -AnyPromise *PMKJoin(NSArray *promises) { - if (promises == nil) - return [AnyPromise promiseWithValue:[NSError errorWithDomain:PMKErrorDomain code:PMKInvalidUsageError userInfo:@{NSLocalizedDescriptionKey: @"PMKJoin(nil)"}]]; - - if (promises.count == 0) - return [AnyPromise promiseWithValue:promises]; - - return [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) { - NSPointerArray *results = NSPointerArrayMake(promises.count); - __block atomic_int countdown = promises.count; - __block BOOL rejected = NO; - - [promises enumerateObjectsUsingBlock:^(AnyPromise *promise, NSUInteger ii, BOOL *stop) { - [promise __pipe:^(id value) { - - if (IsError(value)) { - rejected = YES; - } - - //FIXME surely this isn't thread safe on multiple cores? - [results replacePointerAtIndex:ii withPointer:(__bridge void *)(value ?: [NSNull null])]; - - atomic_fetch_sub_explicit(&countdown, 1, memory_order_relaxed); - - if (countdown == 0) { - if (!rejected) { - resolve(results.allObjects); - } else { - id userInfo = @{PMKJoinPromisesKey: promises}; - id err = [NSError errorWithDomain:PMKErrorDomain code:PMKJoinError userInfo:userInfo]; - resolve(err); - } - } - }]; - - (void) stop; - }]; - }]; -} diff --git a/Sources/race.m b/Sources/race.m deleted file mode 100644 index cab38ec19..000000000 --- a/Sources/race.m +++ /dev/null @@ -1,9 +0,0 @@ -#import "AnyPromise+Private.h" - -AnyPromise *PMKRace(NSArray *promises) { - return [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) { - for (AnyPromise *promise in promises) { - [promise __pipe:resolve]; - } - }]; -} diff --git a/Sources/race.swift b/Sources/race.swift deleted file mode 100644 index 76ae96d06..000000000 --- a/Sources/race.swift +++ /dev/null @@ -1,102 +0,0 @@ -import Dispatch - -@inline(__always) -private func _race(_ thenables: [U]) -> Promise { - let rp = Promise(.pending) - for thenable in thenables { - thenable.pipe(to: rp.box.seal) - } - return rp -} - -/** - Waits for one promise to resolve - - race(promise1, promise2, promise3).then { winner in - //… - } - - - Returns: The promise that resolves first - - Warning: If the first resolution is a rejection, the returned promise is rejected -*/ -public func race(_ thenables: U...) -> Promise { - return _race(thenables) -} - -/** - Waits for one promise to resolve - - race(promise1, promise2, promise3).then { winner in - //… - } - - - Returns: The promise that resolves first - - Warning: If the first resolution is a rejection, the returned promise is rejected - - Remark: If the provided array is empty the returned promise is rejected with PMKError.badInput -*/ -public func race(_ thenables: [U]) -> Promise { - guard !thenables.isEmpty else { - return Promise(error: PMKError.badInput) - } - return _race(thenables) -} - -/** - Waits for one guarantee to resolve - - race(promise1, promise2, promise3).then { winner in - //… - } - - - Returns: The guarantee that resolves first -*/ -public func race(_ guarantees: Guarantee...) -> Guarantee { - let rg = Guarantee(.pending) - for guarantee in guarantees { - guarantee.pipe(to: rg.box.seal) - } - return rg -} - -/** - Waits for one promise to fulfill - - race(fulfilled: [promise1, promise2, promise3]).then { winner in - //… - } - - - Returns: The promise that was fulfilled first. - - Warning: Skips all rejected promises. - - Remark: If the provided array is empty, the returned promise is rejected with `PMKError.badInput`. If there are no fulfilled promises, the returned promise is rejected with `PMKError.noWinner`. -*/ -public func race(fulfilled thenables: [U]) -> Promise { - var countdown = thenables.count - guard countdown > 0 else { - return Promise(error: PMKError.badInput) - } - - let rp = Promise(.pending) - - let barrier = DispatchQueue(label: "org.promisekit.barrier.race", attributes: .concurrent) - - for promise in thenables { - promise.pipe { result in - barrier.sync(flags: .barrier) { - switch result { - case .rejected: - guard rp.isPending else { return } - countdown -= 1 - if countdown == 0 { - rp.box.seal(.rejected(PMKError.noWinner)) - } - case .fulfilled(let value): - guard rp.isPending else { return } - countdown = 0 - rp.box.seal(.fulfilled(value)) - } - } - } - } - - return rp -} diff --git a/Sources/when.m b/Sources/when.m deleted file mode 100644 index 43e5feddc..000000000 --- a/Sources/when.m +++ /dev/null @@ -1,107 +0,0 @@ -@import Foundation.NSDictionary; -#import "AnyPromise+Private.h" -@import Foundation.NSProgress; -#import -@import Foundation.NSError; -@import Foundation.NSNull; -#import "PromiseKit.h" - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" -// ^^ OSAtomicDecrement32 is deprecated on watchOS - - -// NSProgress resources: -// * https://robots.thoughtbot.com/asynchronous-nsprogress -// * http://oleb.net/blog/2014/03/nsprogress/ -// NSProgress! Beware! -// * https://github.com/AFNetworking/AFNetworking/issues/2261 - -/** - Wait for all promises in a set to resolve. - - @note If *any* of the provided promises reject, the returned promise is immediately rejected with that error. - @warning In the event of rejection the other promises will continue to resolve and, as per any other promise, will either fulfill or reject. This is the right pattern for `getter` style asynchronous tasks, but often for `setter` tasks (eg. storing data on a server), you most likely will need to wait on all tasks and then act based on which have succeeded and which have failed, in such situations use `when(resolved:)`. - @param promises The promises upon which to wait before the returned promise resolves. - @note PMKWhen provides NSProgress. - @return A new promise that resolves when all the provided promises fulfill or one of the provided promises rejects. -*/ -AnyPromise *PMKWhen(id promises) { - if (promises == nil) - return [AnyPromise promiseWithValue:[NSError errorWithDomain:PMKErrorDomain code:PMKInvalidUsageError userInfo:@{NSLocalizedDescriptionKey: @"PMKWhen(nil)"}]]; - - if ([promises isKindOfClass:[NSArray class]] || [promises isKindOfClass:[NSDictionary class]]) { - if ([promises count] == 0) - return [AnyPromise promiseWithValue:promises]; - } else if ([promises isKindOfClass:[AnyPromise class]]) { - promises = @[promises]; - } else { - return [AnyPromise promiseWithValue:promises]; - } - -#ifndef PMKDisableProgress - NSProgress *progress = [NSProgress progressWithTotalUnitCount:(int64_t)[promises count]]; - progress.pausable = NO; - progress.cancellable = NO; -#else - struct PMKProgress { - int completedUnitCount; - int totalUnitCount; - double fractionCompleted; - }; - __block struct PMKProgress progress; -#endif - - __block int32_t countdown = (int32_t)[promises count]; - BOOL const isdict = [promises isKindOfClass:[NSDictionary class]]; - - return [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) { - NSInteger index = 0; - - for (__strong id key in promises) { - AnyPromise *promise = isdict ? promises[key] : key; - if (!isdict) key = @(index); - - if (![promise isKindOfClass:[AnyPromise class]]) - promise = [AnyPromise promiseWithValue:promise]; - - [promise __pipe:^(id value){ - if (progress.fractionCompleted >= 1) - return; - - if (IsError(value)) { - progress.completedUnitCount = progress.totalUnitCount; - - NSMutableDictionary *userInfo = [NSMutableDictionary dictionaryWithDictionary:[(NSError *)value userInfo] ?: @{}]; - userInfo[PMKFailingPromiseIndexKey] = key; - [userInfo setObject:value forKey:NSUnderlyingErrorKey]; - id err = [[NSError alloc] initWithDomain:[value domain] code:[value code] userInfo:userInfo]; - resolve(err); - } - else if (OSAtomicDecrement32(&countdown) == 0) { - progress.completedUnitCount = progress.totalUnitCount; - - id results; - if (isdict) { - results = [NSMutableDictionary new]; - for (id key in promises) { - id promise = promises[key]; - results[key] = IsPromise(promise) ? ((AnyPromise *)promise).value : promise; - } - } else { - results = [NSMutableArray new]; - for (AnyPromise *promise in promises) { - id value = IsPromise(promise) ? (promise.value ?: [NSNull null]) : promise; - [results addObject:value]; - } - } - resolve(results); - } else { - progress.completedUnitCount++; - } - }]; - } - }]; -} - -#pragma GCC diagnostic pop diff --git a/Tests/JS-A+/.gitignore b/Tests/A+/JavaScript/.gitignore similarity index 100% rename from Tests/JS-A+/.gitignore rename to Tests/A+/JavaScript/.gitignore diff --git a/Tests/JS-A+/AllTests.swift b/Tests/A+/JavaScript/AllTests.swift similarity index 56% rename from Tests/JS-A+/AllTests.swift rename to Tests/A+/JavaScript/AllTests.swift index a1fd6445e..1ee7cb10c 100644 --- a/Tests/JS-A+/AllTests.swift +++ b/Tests/A+/JavaScript/AllTests.swift @@ -5,33 +5,45 @@ // Created by Lois Di Qual on 2/28/18. // -#if swift(>=3.2) - -import XCTest -import PromiseKit +#if !os(Linux) && !os(watchOS) && !os(Windows) import JavaScriptCore +import PromiseKit +import XCTest -class AllTests: XCTestCase { - - func testAll() { - - let scriptPath = URL(fileURLWithPath: #file).deletingLastPathComponent().appendingPathComponent("build/build.js") +class APlusJavaScriptTests: XCTestCase { + func test_2_1_2() { runner(test: "2.1.2") } + func test_2_1_3() { runner(test: "2.1.3") } + func test_2_2_1() { runner(test: "2.2.1") } + func test_2_2_2() { runner(test: "2.2.2") } + func test_2_2_3() { runner(test: "2.2.3") } + func test_2_2_4() { runner(test: "2.2.4") } + func test_2_2_5() { runner(test: "2.2.5") } + // func test_2_2_6() { runner(test: "2.2.6") } // disabled as fails for some reason currently + func test_2_2_7() { runner(test: "2.2.7") } + func test_2_3_1() { runner(test: "2.3.1") } + func test_2_3_2() { runner(test: "2.3.2") } + func test_2_3_4() { runner(test: "2.3.4") } + + func runner(test testName: String, file: StaticString = #file, line: UInt = #line) { + let scriptPath = URL(fileURLWithPath: #filePath).deletingLastPathComponent().appendingPathComponent("build/build.js") guard FileManager.default.fileExists(atPath: scriptPath.path) else { - return print("Skipping JS-A+: see README for instructions on how to build") + return print("Skipping A+.js: see README for instructions on how to build") } guard let script = try? String(contentsOf: scriptPath) else { - return XCTFail("Couldn't read content of test suite JS file") + return XCTFail("Couldn't read content of test suite JS file", file: file, line: line) } let context = JSUtils.sharedContext + let expectation = self.expectation(description: "async") // Add a global exception handler context.exceptionHandler = { context, exception in - guard let exception = exception else { - return XCTFail("Unknown JS exception") + if let exception = exception { + JSUtils.printStackTrace(exception: exception, includeExceptionDescription: true) } - JSUtils.printStackTrace(exception: exception, includeExceptionDescription: true) + XCTFail(file: file, line: line) + expectation.fulfill() } // Setup mock functions (timers, console.log, etc) @@ -43,7 +55,7 @@ class AllTests: XCTestCase { // Create adapter guard let adapter = JSValue(object: NSDictionary(), in: context) else { - fatalError("Couldn't create adapter") + return XCTFail("Couldn't create adapter", file: file, line: line) } adapter.setObject(JSAdapter.resolved, forKeyedSubscript: "resolved" as NSString) adapter.setObject(JSAdapter.rejected, forKeyedSubscript: "rejected" as NSString) @@ -52,32 +64,33 @@ class AllTests: XCTestCase { // Evaluate contents of `build.js`, which exposes `runTests` in the global context context.evaluateScript(script) guard let runTests = context.objectForKeyedSubscript("runTests") else { - return XCTFail("Couldn't find `runTests` in JS context") + return XCTFail("Couldn't find `runTests` in JS context", file: file, line: line) } // Create a callback that's called whenever there's a failure let onFail: @convention(block) (JSValue, JSValue) -> Void = { test, error in guard let test = test.toString(), let error = error.toString() else { - return XCTFail("Unknown test failure") + return XCTFail("Unknown test failure", file: file, line: line) } - XCTFail("\(test) failed: \(error)") + return XCTFail("\(test) failed: \(error)", file: file, line: line) } let onFailValue: JSValue = JSValue(object: onFail, in: context) - // Create a new callback that we'll send to `runTest` so that it notifies when tests are done running. - let expectation = self.expectation(description: "async") let onDone: @convention(block) (JSValue) -> Void = { failures in expectation.fulfill() } let onDoneValue: JSValue = JSValue(object: onDone, in: context) - // If there's a need to only run one specific test, uncomment the next line and comment the one after - // let testName: JSValue = JSValue(object: "2.3.1", in: context) - let testName = JSUtils.undefined + guard let testName = JSValue(object: testName, in: context) else { + return XCTFail(file: file, line: line) + } + + // use this to run *all* tests + //let testName = JSUtils.undefined // Call `runTests` runTests.call(withArguments: [adapter, onFailValue, onDoneValue, testName]) - self.wait(for: [expectation], timeout: 60) + wait(for: [expectation], timeout: 30) } } diff --git a/Tests/JS-A+/JSAdapter.swift b/Tests/A+/JavaScript/JSAdapter.swift similarity index 96% rename from Tests/JS-A+/JSAdapter.swift rename to Tests/A+/JavaScript/JSAdapter.swift index 6dcbe74c6..52894d655 100644 --- a/Tests/JS-A+/JSAdapter.swift +++ b/Tests/A+/JavaScript/JSAdapter.swift @@ -5,7 +5,7 @@ // Created by Lois Di Qual on 3/2/18. // -import Foundation +#if !os(Linux) && !os(watchOS) && !os(Windows) import JavaScriptCore import PromiseKit @@ -51,3 +51,5 @@ enum JSAdapter { return object } } + +#endif diff --git a/Tests/JS-A+/JSPromise.swift b/Tests/A+/JavaScript/JSPromise.swift similarity index 89% rename from Tests/JS-A+/JSPromise.swift rename to Tests/A+/JavaScript/JSPromise.swift index 70381fd86..2b30192d2 100644 --- a/Tests/JS-A+/JSPromise.swift +++ b/Tests/A+/JavaScript/JSPromise.swift @@ -5,44 +5,44 @@ // Created by Lois Di Qual on 3/1/18. // -import Foundation -import XCTest -import PromiseKit +#if !os(Linux) && !os(watchOS) && !os(Windows) import JavaScriptCore +import PromiseKit +import XCTest @objc protocol JSPromiseProtocol: JSExport { func then(_: JSValue, _: JSValue) -> JSPromise } class JSPromise: NSObject, JSPromiseProtocol { - + let promise: Promise - + init(promise: Promise) { self.promise = promise } - + func then(_ onFulfilled: JSValue, _ onRejected: JSValue) -> JSPromise { - + // Keep a reference to the returned promise so we can comply to 2.3.1 var returnedPromiseRef: Promise? - + let afterFulfill = promise.then { value -> Promise in - + // 2.2.1: ignored if not a function guard JSUtils.isFunction(value: onFulfilled) else { return .value(value) } - + // Call `onFulfilled` // 2.2.5: onFulfilled/onRejected must be called as functions (with no `this` value) guard let returnValue = try JSUtils.call(function: onFulfilled, arguments: [JSUtils.undefined, value]) else { return .value(value) } - + // Extract JSPromise.promise if available, or use plain return value if let jsPromise = returnValue.toObjectOf(JSPromise.self) as? JSPromise { - + // 2.3.1: if returned value is the promise that `then` returned, throw TypeError if jsPromise.promise === returnedPromiseRef { throw JSUtils.JSError(reason: JSUtils.typeError(message: "Returned self")) @@ -52,23 +52,23 @@ class JSPromise: NSObject, JSPromiseProtocol { return .value(returnValue) } } - + let afterReject = promise.recover { error -> Promise in - + // 2.2.1: ignored if not a function guard let jsError = error as? JSUtils.JSError, JSUtils.isFunction(value: onRejected) else { throw error } - + // Call `onRejected` // 2.2.5: onFulfilled/onRejected must be called as functions (with no `this` value) guard let returnValue = try JSUtils.call(function: onRejected, arguments: [JSUtils.undefined, jsError.reason]) else { throw error } - + // Extract JSPromise.promise if available, or use plain return value if let jsPromise = returnValue.toObjectOf(JSPromise.self) as? JSPromise { - + // 2.3.1: if returned value is the promise that `then` returned, throw TypeError if jsPromise.promise === returnedPromiseRef { throw JSUtils.JSError(reason: JSUtils.typeError(message: "Returned self")) @@ -78,17 +78,19 @@ class JSPromise: NSObject, JSPromiseProtocol { return .value(returnValue) } } - - let newPromise = Promise> { resolver in + + let newPromise = Promise> { resolver in _ = promise.tap(resolver.fulfill) }.then(on: nil) { result -> Promise in switch result { - case .fulfilled: return afterFulfill - case .rejected: return afterReject + case .success: return afterFulfill + case .failure: return afterReject } } returnedPromiseRef = newPromise - + return JSPromise(promise: newPromise) } } + +#endif diff --git a/Tests/JS-A+/JSUtils.swift b/Tests/A+/JavaScript/JSUtils.swift similarity index 91% rename from Tests/JS-A+/JSUtils.swift rename to Tests/A+/JavaScript/JSUtils.swift index d08a44b49..eb3e50476 100644 --- a/Tests/JS-A+/JSUtils.swift +++ b/Tests/A+/JavaScript/JSUtils.swift @@ -5,7 +5,7 @@ // Created by Lois Di Qual on 3/2/18. // -import Foundation +#if !os(Linux) && !os(watchOS) && !os(Windows) import JavaScriptCore enum JSUtils { @@ -103,14 +103,4 @@ enum JSUtils { } } -#if !swift(>=3.2) -extension String { - func split(separator: Character, omittingEmptySubsequences: Bool = true) -> [String] { - return characters.split(separator: separator, omittingEmptySubsequences: omittingEmptySubsequences).map(String.init) - } - - var first: Character? { - return characters.first - } -} #endif diff --git a/Tests/JS-A+/MockNodeEnvironment.swift b/Tests/A+/JavaScript/MockNodeEnvironment.swift similarity index 93% rename from Tests/JS-A+/MockNodeEnvironment.swift rename to Tests/A+/JavaScript/MockNodeEnvironment.swift index 82808fe51..b3017b151 100644 --- a/Tests/JS-A+/MockNodeEnvironment.swift +++ b/Tests/A+/JavaScript/MockNodeEnvironment.swift @@ -5,10 +5,9 @@ // Created by Lois Di Qual on 3/1/18. // -#if swift(>=3.2) - -import Foundation +#if !os(Linux) && !os(watchOS) && !os(Windows) import JavaScriptCore +import Foundation class MockNodeEnvironment { @@ -100,11 +99,7 @@ class MockNodeEnvironment { } let timer = Timer.scheduledTimer(timeInterval: interval, target: block, selector: #selector(Operation.main), userInfo: nil, repeats: repeats) let rawHash = UUID().uuidString.hashValue - #if swift(>=4.0) let hash = UInt32(truncatingIfNeeded: rawHash) - #else - let hash = UInt32(truncatingBitPattern: rawHash) - #endif timers[hash] = timer return hash } @@ -118,12 +113,4 @@ class MockNodeEnvironment { } } - -#if swift(>=4.0) && !swift(>=4.1) || !swift(>=3.3) -extension Sequence { - func compactMap(_ transform: (Self.Element) throws -> T?) rethrows -> [T] { - return try flatMap(transform) - } -} -#endif #endif diff --git a/Tests/JS-A+/README.md b/Tests/A+/JavaScript/README.md similarity index 100% rename from Tests/JS-A+/README.md rename to Tests/A+/JavaScript/README.md diff --git a/Tests/JS-A+/index.js b/Tests/A+/JavaScript/index.js similarity index 100% rename from Tests/JS-A+/index.js rename to Tests/A+/JavaScript/index.js diff --git a/Tests/A+/JavaScript/package-lock.json b/Tests/A+/JavaScript/package-lock.json new file mode 100644 index 000000000..47622a009 --- /dev/null +++ b/Tests/A+/JavaScript/package-lock.json @@ -0,0 +1,10293 @@ +{ + "name": "JavaScript", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "dependencies": { + "babel-core": "^6.26.0", + "babel-loader": "^7.1.3", + "babel-preset-env": "^1.6.1", + "lodash": "^4.17.21", + "mocha": "^5.0.1", + "promises-aplus-tests": "^2.1.2", + "sinon": "^4.4.2", + "webpack": "^4.0.1", + "webpack-cli": "^4.7.0" + } + }, + "node_modules/@discoveryjs/json-ext": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.3.tgz", + "integrity": "sha512-Fxt+AfXgjMoin2maPIYzFZnQjAXjAL0PHscM5pRTtatFqB+vZxAM9tLp2Optnuw3QOQC40jTNeGYFOMvyf7v9g==", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@sinonjs/commons": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", + "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/formatio": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-2.0.0.tgz", + "integrity": "sha512-ls6CAMA6/5gG+O/IdsBcblvnd8qcO/l1TYoNeAzp3wcISOxlPXQEus0mLcdwazEkWjaBdaJ3TaxmNgCLWwvWzg==", + "dependencies": { + "samsam": "1.3.0" + } + }, + "node_modules/@sinonjs/samsam": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-3.3.3.tgz", + "integrity": "sha512-bKCMKZvWIjYD0BLGnNrxVuw4dkWCYsLqFOUWw8VgKF/+5Y+mE7LfHWPIYoDXowH+3a9LsWDMo0uAP8YDosPvHQ==", + "dependencies": { + "@sinonjs/commons": "^1.3.0", + "array-from": "^2.1.1", + "lodash": "^4.17.15" + } + }, + "node_modules/@sinonjs/text-encoding": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz", + "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==" + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.9.0.tgz", + "integrity": "sha512-C6wW5L+b7ogSDVqymbkkvuW9kruN//YisMED04xzeBBqjHa2FYnmvOlS6Xj68xWQRgWvI9cIglsjFowH/RJyEA==", + "dependencies": { + "@webassemblyjs/helper-module-context": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/wast-parser": "1.9.0" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.9.0.tgz", + "integrity": "sha512-TG5qcFsS8QB4g4MhrxK5TqfdNe7Ey/7YL/xN+36rRjl/BlGE/NcBvJcqsRgCP6Z92mRE+7N50pRIi8SmKUbcQA==" + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.9.0.tgz", + "integrity": "sha512-NcMLjoFMXpsASZFxJ5h2HZRcEhDkvnNFOAKneP5RbKRzaWJN36NC4jqQHKwStIhGXu5mUWlUUk7ygdtrO8lbmw==" + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.9.0.tgz", + "integrity": "sha512-qZol43oqhq6yBPx7YM3m9Bv7WMV9Eevj6kMi6InKOuZxhw+q9hOkvq5e/PpKSiLfyetpaBnogSbNCfBwyB00CA==" + }, + "node_modules/@webassemblyjs/helper-code-frame": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.9.0.tgz", + "integrity": "sha512-ERCYdJBkD9Vu4vtjUYe8LZruWuNIToYq/ME22igL+2vj2dQ2OOujIZr3MEFvfEaqKoVqpsFKAGsRdBSBjrIvZA==", + "dependencies": { + "@webassemblyjs/wast-printer": "1.9.0" + } + }, + "node_modules/@webassemblyjs/helper-fsm": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-fsm/-/helper-fsm-1.9.0.tgz", + "integrity": "sha512-OPRowhGbshCb5PxJ8LocpdX9Kl0uB4XsAjl6jH/dWKlk/mzsANvhwbiULsaiqT5GZGT9qinTICdj6PLuM5gslw==" + }, + "node_modules/@webassemblyjs/helper-module-context": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-module-context/-/helper-module-context-1.9.0.tgz", + "integrity": "sha512-MJCW8iGC08tMk2enck1aPW+BE5Cw8/7ph/VGZxwyvGbJwjktKkDK7vy7gAmMDx88D7mhDTCNKAW5tED+gZ0W8g==", + "dependencies": { + "@webassemblyjs/ast": "1.9.0" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.9.0.tgz", + "integrity": "sha512-R7FStIzyNcd7xKxCZH5lE0Bqy+hGTwS3LJjuv1ZVxd9O7eHCedSdrId/hMOd20I+v8wDXEn+bjfKDLzTepoaUw==" + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.9.0.tgz", + "integrity": "sha512-XnMB8l3ek4tvrKUUku+IVaXNHz2YsJyOOmz+MMkZvh8h1uSJpSen6vYnw3IoQ7WwEuAhL8Efjms1ZWjqh2agvw==", + "dependencies": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-buffer": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/wasm-gen": "1.9.0" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.9.0.tgz", + "integrity": "sha512-dcX8JuYU/gvymzIHc9DgxTzUUTLexWwt8uCTWP3otys596io0L5aW02Gb1RjYpx2+0Jus1h4ZFqjla7umFniTg==", + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.9.0.tgz", + "integrity": "sha512-ENVzM5VwV1ojs9jam6vPys97B/S65YQtv/aanqnU7D8aSoHFX8GyhGg0CMfyKNIHBuAVjy3tlzd5QMMINa7wpw==", + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.9.0.tgz", + "integrity": "sha512-GZbQlWtopBTP0u7cHrEx+73yZKrQoBMpwkGEIqlacljhXCkVM1kMQge/Mf+csMJAjEdSwhOyLAS0AoR3AG5P8w==" + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.9.0.tgz", + "integrity": "sha512-FgHzBm80uwz5M8WKnMTn6j/sVbqilPdQXTWraSjBwFXSYGirpkSWE2R9Qvz9tNiTKQvoKILpCuTjBKzOIm0nxw==", + "dependencies": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-buffer": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/helper-wasm-section": "1.9.0", + "@webassemblyjs/wasm-gen": "1.9.0", + "@webassemblyjs/wasm-opt": "1.9.0", + "@webassemblyjs/wasm-parser": "1.9.0", + "@webassemblyjs/wast-printer": "1.9.0" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.9.0.tgz", + "integrity": "sha512-cPE3o44YzOOHvlsb4+E9qSqjc9Qf9Na1OO/BHFy4OI91XDE14MjFN4lTMezzaIWdPqHnsTodGGNP+iRSYfGkjA==", + "dependencies": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/ieee754": "1.9.0", + "@webassemblyjs/leb128": "1.9.0", + "@webassemblyjs/utf8": "1.9.0" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.9.0.tgz", + "integrity": "sha512-Qkjgm6Anhm+OMbIL0iokO7meajkzQD71ioelnfPEj6r4eOFuqm4YC3VBPqXjFyyNwowzbMD+hizmprP/Fwkl2A==", + "dependencies": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-buffer": "1.9.0", + "@webassemblyjs/wasm-gen": "1.9.0", + "@webassemblyjs/wasm-parser": "1.9.0" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.9.0.tgz", + "integrity": "sha512-9+wkMowR2AmdSWQzsPEjFU7njh8HTO5MqO8vjwEHuM+AMHioNqSBONRdr0NQQ3dVQrzp0s8lTcYqzUdb7YgELA==", + "dependencies": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-api-error": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/ieee754": "1.9.0", + "@webassemblyjs/leb128": "1.9.0", + "@webassemblyjs/utf8": "1.9.0" + } + }, + "node_modules/@webassemblyjs/wast-parser": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-parser/-/wast-parser-1.9.0.tgz", + "integrity": "sha512-qsqSAP3QQ3LyZjNC/0jBJ/ToSxfYJ8kYyuiGvtn/8MK89VrNEfwj7BPQzJVHi0jGTRK2dGdJ5PRqhtjzoww+bw==", + "dependencies": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/floating-point-hex-parser": "1.9.0", + "@webassemblyjs/helper-api-error": "1.9.0", + "@webassemblyjs/helper-code-frame": "1.9.0", + "@webassemblyjs/helper-fsm": "1.9.0", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.9.0.tgz", + "integrity": "sha512-2J0nE95rHXHyQ24cWjMKJ1tqB/ds8z/cyeOZxJhcb+rW+SQASVjuznUSmdz5GpVJTzU8JkhYut0D3siFDD6wsA==", + "dependencies": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/wast-parser": "1.9.0", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webpack-cli/configtest": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.0.3.tgz", + "integrity": "sha512-WQs0ep98FXX2XBAfQpRbY0Ma6ADw8JR6xoIkaIiJIzClGOMqVRvPCWqndTxf28DgFopWan0EKtHtg/5W1h0Zkw==", + "peerDependencies": { + "webpack": "4.x.x || 5.x.x", + "webpack-cli": "4.x.x" + } + }, + "node_modules/@webpack-cli/info": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.2.4.tgz", + "integrity": "sha512-ogE2T4+pLhTTPS/8MM3IjHn0IYplKM4HbVNMCWA9N4NrdPzunwenpCsqKEXyejMfRu6K8mhauIPYf8ZxWG5O6g==", + "dependencies": { + "envinfo": "^7.7.3" + }, + "peerDependencies": { + "webpack-cli": "4.x.x" + } + }, + "node_modules/@webpack-cli/serve": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.4.0.tgz", + "integrity": "sha512-xgT/HqJ+uLWGX+Mzufusl3cgjAcnqYYskaB7o0vRcwOEfuu6hMzSILQpnIzFMGsTaeaX4Nnekl+6fadLbl1/Vg==", + "peerDependencies": { + "webpack-cli": "4.x.x" + }, + "peerDependenciesMeta": { + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==" + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==" + }, + "node_modules/acorn": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", + "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.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/ajv-errors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.1.tgz", + "integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==", + "peerDependencies": { + "ajv": ">=5.0.0" + } + }, + "node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "optional": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" + }, + "node_modules/arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-from": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/array-from/-/array-from-2.1.1.tgz", + "integrity": "sha1-z+nYwmYoudxa7MYqn12PHzUsEZU=" + }, + "node_modules/array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/asn1.js": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", + "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", + "dependencies": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "safer-buffer": "^2.1.0" + } + }, + "node_modules/asn1.js/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + }, + "node_modules/assert": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz", + "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==", + "dependencies": { + "object-assign": "^4.1.1", + "util": "0.10.3" + } + }, + "node_modules/assert/node_modules/inherits": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", + "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=" + }, + "node_modules/assert/node_modules/util": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", + "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", + "dependencies": { + "inherits": "2.0.1" + } + }, + "node_modules/assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/async-each": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", + "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", + "optional": true + }, + "node_modules/atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "bin": { + "atob": "bin/atob.js" + }, + "engines": { + "node": ">= 4.5.0" + } + }, + "node_modules/babel-code-frame": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", + "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", + "dependencies": { + "chalk": "^1.1.3", + "esutils": "^2.0.2", + "js-tokens": "^3.0.2" + } + }, + "node_modules/babel-core": { + "version": "6.26.3", + "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.26.3.tgz", + "integrity": "sha512-6jyFLuDmeidKmUEb3NM+/yawG0M2bDZ9Z1qbZP59cyHLz8kYGKYwpJP0UwUKKUiTRNvxfLesJnTedqczP7cTDA==", + "dependencies": { + "babel-code-frame": "^6.26.0", + "babel-generator": "^6.26.0", + "babel-helpers": "^6.24.1", + "babel-messages": "^6.23.0", + "babel-register": "^6.26.0", + "babel-runtime": "^6.26.0", + "babel-template": "^6.26.0", + "babel-traverse": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "convert-source-map": "^1.5.1", + "debug": "^2.6.9", + "json5": "^0.5.1", + "lodash": "^4.17.4", + "minimatch": "^3.0.4", + "path-is-absolute": "^1.0.1", + "private": "^0.1.8", + "slash": "^1.0.0", + "source-map": "^0.5.7" + } + }, + "node_modules/babel-generator": { + "version": "6.26.1", + "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.1.tgz", + "integrity": "sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA==", + "dependencies": { + "babel-messages": "^6.23.0", + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "detect-indent": "^4.0.0", + "jsesc": "^1.3.0", + "lodash": "^4.17.4", + "source-map": "^0.5.7", + "trim-right": "^1.0.1" + } + }, + "node_modules/babel-helper-builder-binary-assignment-operator-visitor": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz", + "integrity": "sha1-zORReto1b0IgvK6KAsKzRvmlZmQ=", + "dependencies": { + "babel-helper-explode-assignable-expression": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" + } + }, + "node_modules/babel-helper-call-delegate": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz", + "integrity": "sha1-7Oaqzdx25Bw0YfiL/Fdb0Nqi340=", + "dependencies": { + "babel-helper-hoist-variables": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-traverse": "^6.24.1", + "babel-types": "^6.24.1" + } + }, + "node_modules/babel-helper-define-map": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz", + "integrity": "sha1-pfVtq0GiX5fstJjH66ypgZ+Vvl8=", + "dependencies": { + "babel-helper-function-name": "^6.24.1", + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "lodash": "^4.17.4" + } + }, + "node_modules/babel-helper-explode-assignable-expression": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz", + "integrity": "sha1-8luCz33BBDPFX3BZLVdGQArCLKo=", + "dependencies": { + "babel-runtime": "^6.22.0", + "babel-traverse": "^6.24.1", + "babel-types": "^6.24.1" + } + }, + "node_modules/babel-helper-function-name": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz", + "integrity": "sha1-00dbjAPtmCQqJbSDUasYOZ01gKk=", + "dependencies": { + "babel-helper-get-function-arity": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1", + "babel-traverse": "^6.24.1", + "babel-types": "^6.24.1" + } + }, + "node_modules/babel-helper-get-function-arity": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz", + "integrity": "sha1-j3eCqpNAfEHTqlCQj4mwMbG2hT0=", + "dependencies": { + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" + } + }, + "node_modules/babel-helper-hoist-variables": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz", + "integrity": "sha1-HssnaJydJVE+rbyZFKc/VAi+enY=", + "dependencies": { + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" + } + }, + "node_modules/babel-helper-optimise-call-expression": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz", + "integrity": "sha1-96E0J7qfc/j0+pk8VKl4gtEkQlc=", + "dependencies": { + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" + } + }, + "node_modules/babel-helper-regex": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz", + "integrity": "sha1-MlxZ+QL4LyS3T6zu0DY5VPZJXnI=", + "dependencies": { + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "lodash": "^4.17.4" + } + }, + "node_modules/babel-helper-remap-async-to-generator": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz", + "integrity": "sha1-XsWBgnrXI/7N04HxySg5BnbkVRs=", + "dependencies": { + "babel-helper-function-name": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1", + "babel-traverse": "^6.24.1", + "babel-types": "^6.24.1" + } + }, + "node_modules/babel-helper-replace-supers": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz", + "integrity": "sha1-v22/5Dk40XNpohPKiov3S2qQqxo=", + "dependencies": { + "babel-helper-optimise-call-expression": "^6.24.1", + "babel-messages": "^6.23.0", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1", + "babel-traverse": "^6.24.1", + "babel-types": "^6.24.1" + } + }, + "node_modules/babel-helpers": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz", + "integrity": "sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI=", + "dependencies": { + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1" + } + }, + "node_modules/babel-loader": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-7.1.5.tgz", + "integrity": "sha512-iCHfbieL5d1LfOQeeVJEUyD9rTwBcP/fcEbRCfempxTDuqrKpu0AZjLAQHEQa3Yqyj9ORKe2iHfoj4rHLf7xpw==", + "dependencies": { + "find-cache-dir": "^1.0.0", + "loader-utils": "^1.0.2", + "mkdirp": "^0.5.1" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "babel-core": "6", + "webpack": "2 || 3 || 4" + } + }, + "node_modules/babel-messages": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", + "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", + "dependencies": { + "babel-runtime": "^6.22.0" + } + }, + "node_modules/babel-plugin-check-es2015-constants": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz", + "integrity": "sha1-NRV7EBQm/S/9PaP3XH0ekYNbv4o=", + "dependencies": { + "babel-runtime": "^6.22.0" + } + }, + "node_modules/babel-plugin-syntax-async-functions": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz", + "integrity": "sha1-ytnK0RkbWtY0vzCuCHI5HgZHvpU=" + }, + "node_modules/babel-plugin-syntax-exponentiation-operator": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz", + "integrity": "sha1-nufoM3KQ2pUoggGmpX9BcDF4MN4=" + }, + "node_modules/babel-plugin-syntax-trailing-function-commas": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz", + "integrity": "sha1-ugNgk3+NBuQBgKQ/4NVhb/9TLPM=" + }, + "node_modules/babel-plugin-transform-async-to-generator": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz", + "integrity": "sha1-ZTbjeK/2yx1VF6wOQOs+n8jQh2E=", + "dependencies": { + "babel-helper-remap-async-to-generator": "^6.24.1", + "babel-plugin-syntax-async-functions": "^6.8.0", + "babel-runtime": "^6.22.0" + } + }, + "node_modules/babel-plugin-transform-es2015-arrow-functions": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz", + "integrity": "sha1-RSaSy3EdX3ncf4XkQM5BufJE0iE=", + "dependencies": { + "babel-runtime": "^6.22.0" + } + }, + "node_modules/babel-plugin-transform-es2015-block-scoped-functions": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz", + "integrity": "sha1-u8UbSflk1wy42OC5ToICRs46YUE=", + "dependencies": { + "babel-runtime": "^6.22.0" + } + }, + "node_modules/babel-plugin-transform-es2015-block-scoping": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz", + "integrity": "sha1-1w9SmcEwjQXBL0Y4E7CgnnOxiV8=", + "dependencies": { + "babel-runtime": "^6.26.0", + "babel-template": "^6.26.0", + "babel-traverse": "^6.26.0", + "babel-types": "^6.26.0", + "lodash": "^4.17.4" + } + }, + "node_modules/babel-plugin-transform-es2015-classes": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz", + "integrity": "sha1-WkxYpQyclGHlZLSyo7+ryXolhNs=", + "dependencies": { + "babel-helper-define-map": "^6.24.1", + "babel-helper-function-name": "^6.24.1", + "babel-helper-optimise-call-expression": "^6.24.1", + "babel-helper-replace-supers": "^6.24.1", + "babel-messages": "^6.23.0", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1", + "babel-traverse": "^6.24.1", + "babel-types": "^6.24.1" + } + }, + "node_modules/babel-plugin-transform-es2015-computed-properties": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz", + "integrity": "sha1-b+Ko0WiV1WNPTNmZttNICjCBWbM=", + "dependencies": { + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1" + } + }, + "node_modules/babel-plugin-transform-es2015-destructuring": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz", + "integrity": "sha1-mXux8auWf2gtKwh2/jWNYOdlxW0=", + "dependencies": { + "babel-runtime": "^6.22.0" + } + }, + "node_modules/babel-plugin-transform-es2015-duplicate-keys": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz", + "integrity": "sha1-c+s9MQypaePvnskcU3QabxV2Qj4=", + "dependencies": { + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" + } + }, + "node_modules/babel-plugin-transform-es2015-for-of": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz", + "integrity": "sha1-9HyVsrYT3x0+zC/bdXNiPHUkhpE=", + "dependencies": { + "babel-runtime": "^6.22.0" + } + }, + "node_modules/babel-plugin-transform-es2015-function-name": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz", + "integrity": "sha1-g0yJhTvDaxrw86TF26qU/Y6sqos=", + "dependencies": { + "babel-helper-function-name": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" + } + }, + "node_modules/babel-plugin-transform-es2015-literals": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz", + "integrity": "sha1-T1SgLWzWbPkVKAAZox0xklN3yi4=", + "dependencies": { + "babel-runtime": "^6.22.0" + } + }, + "node_modules/babel-plugin-transform-es2015-modules-amd": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz", + "integrity": "sha1-Oz5UAXI5hC1tGcMBHEvS8AoA0VQ=", + "dependencies": { + "babel-plugin-transform-es2015-modules-commonjs": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1" + } + }, + "node_modules/babel-plugin-transform-es2015-modules-commonjs": { + "version": "6.26.2", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.2.tgz", + "integrity": "sha512-CV9ROOHEdrjcwhIaJNBGMBCodN+1cfkwtM1SbUHmvyy35KGT7fohbpOxkE2uLz1o6odKK2Ck/tz47z+VqQfi9Q==", + "dependencies": { + "babel-plugin-transform-strict-mode": "^6.24.1", + "babel-runtime": "^6.26.0", + "babel-template": "^6.26.0", + "babel-types": "^6.26.0" + } + }, + "node_modules/babel-plugin-transform-es2015-modules-systemjs": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz", + "integrity": "sha1-/4mhQrkRmpBhlfXxBuzzBdlAfSM=", + "dependencies": { + "babel-helper-hoist-variables": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1" + } + }, + "node_modules/babel-plugin-transform-es2015-modules-umd": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz", + "integrity": "sha1-rJl+YoXNGO1hdq22B9YCNErThGg=", + "dependencies": { + "babel-plugin-transform-es2015-modules-amd": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1" + } + }, + "node_modules/babel-plugin-transform-es2015-object-super": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz", + "integrity": "sha1-JM72muIcuDp/hgPa0CH1cusnj40=", + "dependencies": { + "babel-helper-replace-supers": "^6.24.1", + "babel-runtime": "^6.22.0" + } + }, + "node_modules/babel-plugin-transform-es2015-parameters": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz", + "integrity": "sha1-V6w1GrScrxSpfNE7CfZv3wpiXys=", + "dependencies": { + "babel-helper-call-delegate": "^6.24.1", + "babel-helper-get-function-arity": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1", + "babel-traverse": "^6.24.1", + "babel-types": "^6.24.1" + } + }, + "node_modules/babel-plugin-transform-es2015-shorthand-properties": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz", + "integrity": "sha1-JPh11nIch2YbvZmkYi5R8U3jiqA=", + "dependencies": { + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" + } + }, + "node_modules/babel-plugin-transform-es2015-spread": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz", + "integrity": "sha1-1taKmfia7cRTbIGlQujdnxdG+NE=", + "dependencies": { + "babel-runtime": "^6.22.0" + } + }, + "node_modules/babel-plugin-transform-es2015-sticky-regex": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz", + "integrity": "sha1-AMHNsaynERLN8M9hJsLta0V8zbw=", + "dependencies": { + "babel-helper-regex": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" + } + }, + "node_modules/babel-plugin-transform-es2015-template-literals": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz", + "integrity": "sha1-qEs0UPfp+PH2g51taH2oS7EjbY0=", + "dependencies": { + "babel-runtime": "^6.22.0" + } + }, + "node_modules/babel-plugin-transform-es2015-typeof-symbol": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz", + "integrity": "sha1-3sCfHN3/lLUqxz1QXITfWdzOs3I=", + "dependencies": { + "babel-runtime": "^6.22.0" + } + }, + "node_modules/babel-plugin-transform-es2015-unicode-regex": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz", + "integrity": "sha1-04sS9C6nMj9yk4fxinxa4frrNek=", + "dependencies": { + "babel-helper-regex": "^6.24.1", + "babel-runtime": "^6.22.0", + "regexpu-core": "^2.0.0" + } + }, + "node_modules/babel-plugin-transform-exponentiation-operator": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz", + "integrity": "sha1-KrDJx/MJj6SJB3cruBP+QejeOg4=", + "dependencies": { + "babel-helper-builder-binary-assignment-operator-visitor": "^6.24.1", + "babel-plugin-syntax-exponentiation-operator": "^6.8.0", + "babel-runtime": "^6.22.0" + } + }, + "node_modules/babel-plugin-transform-regenerator": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz", + "integrity": "sha1-4HA2lvveJ/Cj78rPi03KL3s6jy8=", + "dependencies": { + "regenerator-transform": "^0.10.0" + } + }, + "node_modules/babel-plugin-transform-strict-mode": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz", + "integrity": "sha1-1fr3qleKZbvlkc9e2uBKDGcCB1g=", + "dependencies": { + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" + } + }, + "node_modules/babel-preset-env": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/babel-preset-env/-/babel-preset-env-1.7.0.tgz", + "integrity": "sha512-9OR2afuKDneX2/q2EurSftUYM0xGu4O2D9adAhVfADDhrYDaxXV0rBbevVYoY9n6nyX1PmQW/0jtpJvUNr9CHg==", + "dependencies": { + "babel-plugin-check-es2015-constants": "^6.22.0", + "babel-plugin-syntax-trailing-function-commas": "^6.22.0", + "babel-plugin-transform-async-to-generator": "^6.22.0", + "babel-plugin-transform-es2015-arrow-functions": "^6.22.0", + "babel-plugin-transform-es2015-block-scoped-functions": "^6.22.0", + "babel-plugin-transform-es2015-block-scoping": "^6.23.0", + "babel-plugin-transform-es2015-classes": "^6.23.0", + "babel-plugin-transform-es2015-computed-properties": "^6.22.0", + "babel-plugin-transform-es2015-destructuring": "^6.23.0", + "babel-plugin-transform-es2015-duplicate-keys": "^6.22.0", + "babel-plugin-transform-es2015-for-of": "^6.23.0", + "babel-plugin-transform-es2015-function-name": "^6.22.0", + "babel-plugin-transform-es2015-literals": "^6.22.0", + "babel-plugin-transform-es2015-modules-amd": "^6.22.0", + "babel-plugin-transform-es2015-modules-commonjs": "^6.23.0", + "babel-plugin-transform-es2015-modules-systemjs": "^6.23.0", + "babel-plugin-transform-es2015-modules-umd": "^6.23.0", + "babel-plugin-transform-es2015-object-super": "^6.22.0", + "babel-plugin-transform-es2015-parameters": "^6.23.0", + "babel-plugin-transform-es2015-shorthand-properties": "^6.22.0", + "babel-plugin-transform-es2015-spread": "^6.22.0", + "babel-plugin-transform-es2015-sticky-regex": "^6.22.0", + "babel-plugin-transform-es2015-template-literals": "^6.22.0", + "babel-plugin-transform-es2015-typeof-symbol": "^6.23.0", + "babel-plugin-transform-es2015-unicode-regex": "^6.22.0", + "babel-plugin-transform-exponentiation-operator": "^6.22.0", + "babel-plugin-transform-regenerator": "^6.22.0", + "browserslist": "^3.2.6", + "invariant": "^2.2.2", + "semver": "^5.3.0" + } + }, + "node_modules/babel-register": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz", + "integrity": "sha1-btAhFz4vy0htestFxgCahW9kcHE=", + "dependencies": { + "babel-core": "^6.26.0", + "babel-runtime": "^6.26.0", + "core-js": "^2.5.0", + "home-or-tmp": "^2.0.0", + "lodash": "^4.17.4", + "mkdirp": "^0.5.1", + "source-map-support": "^0.4.15" + } + }, + "node_modules/babel-runtime": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", + "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", + "dependencies": { + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" + } + }, + "node_modules/babel-template": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", + "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", + "dependencies": { + "babel-runtime": "^6.26.0", + "babel-traverse": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "lodash": "^4.17.4" + } + }, + "node_modules/babel-traverse": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", + "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", + "dependencies": { + "babel-code-frame": "^6.26.0", + "babel-messages": "^6.23.0", + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "debug": "^2.6.8", + "globals": "^9.18.0", + "invariant": "^2.2.2", + "lodash": "^4.17.4" + } + }, + "node_modules/babel-types": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", + "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", + "dependencies": { + "babel-runtime": "^6.26.0", + "esutils": "^2.0.2", + "lodash": "^4.17.4", + "to-fast-properties": "^1.0.3" + } + }, + "node_modules/babylon": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", + "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", + "bin": { + "babylon": "bin/babylon.js" + } + }, + "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/base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "dependencies": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/base/node_modules/define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dependencies": { + "is-descriptor": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "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/big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "engines": { + "node": "*" + } + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "optional": true, + "dependencies": { + "file-uri-to-path": "1.0.0" + } + }, + "node_modules/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" + }, + "node_modules/bn.js": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.0.tgz", + "integrity": "sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw==" + }, + "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": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dependencies": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/braces/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/braces/node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" + }, + "node_modules/browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==" + }, + "node_modules/browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "dependencies": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/browserify-cipher": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", + "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", + "dependencies": { + "browserify-aes": "^1.0.4", + "browserify-des": "^1.0.0", + "evp_bytestokey": "^1.0.0" + } + }, + "node_modules/browserify-des": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", + "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", + "dependencies": { + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/browserify-rsa": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.0.tgz", + "integrity": "sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==", + "dependencies": { + "bn.js": "^5.0.0", + "randombytes": "^2.0.1" + } + }, + "node_modules/browserify-sign": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.1.tgz", + "integrity": "sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg==", + "dependencies": { + "bn.js": "^5.1.1", + "browserify-rsa": "^4.0.1", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "elliptic": "^6.5.3", + "inherits": "^2.0.4", + "parse-asn1": "^5.1.5", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + } + }, + "node_modules/browserify-sign/node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/browserify-sign/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "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/browserify-zlib": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", + "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", + "dependencies": { + "pako": "~1.0.5" + } + }, + "node_modules/browserslist": { + "version": "3.2.8", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-3.2.8.tgz", + "integrity": "sha512-WHVocJYavUwVgVViC0ORikPHQquXwVh939TaelZ4WDqpWgTX/FsGhl/+P4qBUAGcRvtOgDgC+xftNWWp2RUTAQ==", + "dependencies": { + "caniuse-lite": "^1.0.30000844", + "electron-to-chromium": "^1.3.47" + }, + "bin": { + "browserslist": "cli.js" + } + }, + "node_modules/buffer": { + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", + "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", + "dependencies": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" + } + }, + "node_modules/buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" + }, + "node_modules/buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=" + }, + "node_modules/buffer/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "node_modules/builtin-status-codes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", + "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=" + }, + "node_modules/cacache": { + "version": "12.0.4", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.4.tgz", + "integrity": "sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ==", + "dependencies": { + "bluebird": "^3.5.5", + "chownr": "^1.1.1", + "figgy-pudding": "^3.5.1", + "glob": "^7.1.4", + "graceful-fs": "^4.1.15", + "infer-owner": "^1.0.3", + "lru-cache": "^5.1.1", + "mississippi": "^3.0.0", + "mkdirp": "^0.5.1", + "move-concurrently": "^1.0.1", + "promise-inflight": "^1.0.1", + "rimraf": "^2.6.3", + "ssri": "^6.0.1", + "unique-filename": "^1.1.1", + "y18n": "^4.0.0" + } + }, + "node_modules/cacache/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/cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "dependencies": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001233", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001233.tgz", + "integrity": "sha512-BmkbxLfStqiPA7IEzQpIk0UFZFf3A4E6fzjPJ6OR+bFC2L8ES9J8zGA/asoi47p8XDVkev+WJo2I2Nc8c/34Yg==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + } + }, + "node_modules/chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dependencies": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/chokidar": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.1.tgz", + "integrity": "sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw==", + "optional": true, + "dependencies": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.5.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.1" + } + }, + "node_modules/chokidar/node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "optional": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/chokidar/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==", + "optional": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/chokidar/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==", + "optional": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/chokidar/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==", + "optional": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" + }, + "node_modules/chrome-trace-event": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", + "engines": { + "node": ">=6.0" + } + }, + "node_modules/cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "dependencies": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/class-utils/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/class-utils/node_modules/is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/class-utils/node_modules/is-accessor-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/class-utils/node_modules/is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/class-utils/node_modules/is-data-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/class-utils/node_modules/is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dependencies": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/class-utils/node_modules/kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "dependencies": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/colorette": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz", + "integrity": "sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==" + }, + "node_modules/commander": { + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", + "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==" + }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=" + }, + "node_modules/component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "node_modules/concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "engines": [ + "node >= 0.8" + ], + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/console-browserify": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz", + "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==" + }, + "node_modules/constants-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", + "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=" + }, + "node_modules/convert-source-map": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", + "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", + "dependencies": { + "safe-buffer": "~5.1.1" + } + }, + "node_modules/copy-concurrently": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz", + "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==", + "dependencies": { + "aproba": "^1.1.1", + "fs-write-stream-atomic": "^1.0.8", + "iferr": "^0.1.5", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.0" + } + }, + "node_modules/copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/core-js": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", + "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", + "deprecated": "core-js@<3.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Please, upgrade your dependencies to the actual version of core-js.", + "hasInstallScript": true + }, + "node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "node_modules/create-ecdh": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", + "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", + "dependencies": { + "bn.js": "^4.1.0", + "elliptic": "^6.5.3" + } + }, + "node_modules/create-ecdh/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + }, + "node_modules/create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "dependencies": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "node_modules/create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "dependencies": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "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/crypto-browserify": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", + "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", + "dependencies": { + "browserify-cipher": "^1.0.0", + "browserify-sign": "^4.0.0", + "create-ecdh": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.0", + "diffie-hellman": "^5.0.0", + "inherits": "^2.0.1", + "pbkdf2": "^3.0.3", + "public-encrypt": "^4.0.0", + "randombytes": "^2.0.0", + "randomfill": "^1.0.3" + }, + "engines": { + "node": "*" + } + }, + "node_modules/cyclist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz", + "integrity": "sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=" + }, + "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/decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dependencies": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/des.js": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz", + "integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==", + "dependencies": { + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/detect-indent": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", + "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=", + "dependencies": { + "repeating": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/diffie-hellman": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", + "dependencies": { + "bn.js": "^4.1.0", + "miller-rabin": "^4.0.0", + "randombytes": "^2.0.0" + } + }, + "node_modules/diffie-hellman/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + }, + "node_modules/domain-browser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", + "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==", + "engines": { + "node": ">=0.4", + "npm": ">=1.2" + } + }, + "node_modules/duplexify": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", + "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", + "dependencies": { + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.3.745", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.745.tgz", + "integrity": "sha512-ZZCx4CS3kYT3BREYiIXocDqlNPT56KfdTS1Ogo4yvxRriBqiEXCDTLIQZT/zNVtby91xTWMMxW2NBiXh8bpLHw==" + }, + "node_modules/elliptic": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "dependencies": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/elliptic/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + }, + "node_modules/emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "engines": { + "node": ">= 4" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/enhanced-resolve": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.5.0.tgz", + "integrity": "sha512-Nv9m36S/vxpsI+Hc4/ZGRs0n9mXqSWGGq49zxb/cJfPAQMbUtttJAlNPS4AQzaBdw/pKskw5bMbekT/Y7W/Wlg==", + "dependencies": { + "graceful-fs": "^4.1.2", + "memory-fs": "^0.5.0", + "tapable": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/enhanced-resolve/node_modules/memory-fs": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.5.0.tgz", + "integrity": "sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==", + "dependencies": { + "errno": "^0.1.3", + "readable-stream": "^2.0.1" + }, + "engines": { + "node": ">=4.3.0 <5.0.0 || >=5.10" + } + }, + "node_modules/envinfo": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz", + "integrity": "sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==", + "bin": { + "envinfo": "dist/cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/errno": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", + "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", + "dependencies": { + "prr": "~1.0.1" + }, + "bin": { + "errno": "cli.js" + } + }, + "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": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/eslint-scope": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", + "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", + "dependencies": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "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/esrecurse/node_modules/estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "engines": { + "node": ">=4.0" + } + }, + "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/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/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "dependencies": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "node_modules/execa": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.0.tgz", + "integrity": "sha512-CkdUB7s2y6S+d4y+OM/+ZtQcJCiKUCth4cNImGMqrt2zEVtW2rfHGspQBE1GDo6LjeNIQmTPKXqTCKjqFKyu3A==", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "dependencies": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/is-accessor-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/is-data-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dependencies": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dependencies": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob/node_modules/define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dependencies": { + "is-descriptor": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob/node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "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-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/fastest-levenshtein": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz", + "integrity": "sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow==" + }, + "node_modules/figgy-pudding": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.2.tgz", + "integrity": "sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw==" + }, + "node_modules/file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "optional": true + }, + "node_modules/fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dependencies": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fill-range/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fill-range/node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/find-cache-dir": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-1.0.0.tgz", + "integrity": "sha1-kojj6ePMN0hxfTnq3hfPcfww7m8=", + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^1.0.0", + "pkg-dir": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dependencies": { + "locate-path": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/flush-write-stream": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", + "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==", + "dependencies": { + "inherits": "^2.0.3", + "readable-stream": "^2.3.6" + } + }, + "node_modules/for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/formatio": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/formatio/-/formatio-1.1.1.tgz", + "integrity": "sha1-XtPM1jZVEJc4NGXZlhmRAOhhYek=", + "deprecated": "This package is unmaintained. Use @sinonjs/formatio instead", + "dependencies": { + "samsam": "~1.1" + } + }, + "node_modules/formatio/node_modules/samsam": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/samsam/-/samsam-1.1.3.tgz", + "integrity": "sha1-n1CHQZtNCR8jJXHn+lLpCw9VJiE=", + "deprecated": "This package has been deprecated in favour of @sinonjs/samsam" + }, + "node_modules/fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "dependencies": { + "map-cache": "^0.2.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/from2": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", + "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", + "dependencies": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" + } + }, + "node_modules/fs-write-stream-atomic": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz", + "integrity": "sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=", + "dependencies": { + "graceful-fs": "^4.1.2", + "iferr": "^0.1.5", + "imurmurhash": "^0.1.4", + "readable-stream": "1 || 2" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "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/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "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": "*" + } + }, + "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==", + "optional": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/globals": { + "version": "9.18.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", + "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", + "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==" + }, + "node_modules/growl": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", + "engines": { + "node": ">=4.x" + } + }, + "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-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "engines": { + "node": ">=4" + } + }, + "node_modules/has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "dependencies": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "dependencies": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-values/node_modules/kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/hash-base": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", + "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", + "dependencies": { + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/hash-base/node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/hash-base/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "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/hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "node_modules/he": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", + "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", + "bin": { + "he": "bin/he" + } + }, + "node_modules/hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", + "dependencies": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/home-or-tmp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz", + "integrity": "sha1-42w/LSyufXRqhX440Y1fMqeILbg=", + "dependencies": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/https-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", + "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=" + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "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/iferr": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz", + "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=" + }, + "node_modules/import-local": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.0.2.tgz", + "integrity": "sha512-vjL3+w0oulAVZ0hBHnxa/Nm5TAurf9YLQJDhqRZyqb+VKGOB6LU8t9H1Nr5CIo16vh9XfJTOoHwU0B71S557gA==", + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/import-local/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/import-local/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/import-local/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-local/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/import-local/node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/import-local/node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "engines": { + "node": ">=8" + } + }, + "node_modules/import-local/node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/infer-owner": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==" + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "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/interpret": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz", + "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, + "node_modules/is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "optional": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + }, + "node_modules/is-core-module": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.4.0.tgz", + "integrity": "sha512-6A2fkfq1rfeQZjxrZJGerpLCTHRNEBiSgnu0+obeJpEPZRUooHgsizvzv0ZjJwOz3iWIHdJtVWJ/tmPr3D21/A==", + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dependencies": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-finite": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.1.0.tgz", + "integrity": "sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w==", + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "optional": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", + "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", + "engines": { + "node": ">=4" + } + }, + "node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jade": { + "version": "0.26.3", + "resolved": "https://registry.npmjs.org/jade/-/jade-0.26.3.tgz", + "integrity": "sha1-jxDXl32NefL2/4YqgbBRPMslaGw=", + "deprecated": "Jade has been renamed to pug, please install the latest version of pug instead of jade", + "dependencies": { + "commander": "0.6.1", + "mkdirp": "0.3.0" + }, + "bin": { + "jade": "bin/jade" + } + }, + "node_modules/jade/node_modules/commander": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-0.6.1.tgz", + "integrity": "sha1-+mihT2qUXVTbvlDYzbMyDp47GgY=", + "engines": { + "node": ">= 0.4.x" + } + }, + "node_modules/jade/node_modules/mkdirp": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.0.tgz", + "integrity": "sha1-G79asbqCevI1dRQ0kEJkVfSB/h4=", + "deprecated": "Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.)", + "engines": { + "node": "*" + } + }, + "node_modules/js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=" + }, + "node_modules/jsesc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", + "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=", + "bin": { + "jsesc": "bin/jsesc" + } + }, + "node_modules/json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==" + }, + "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/json5": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", + "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/just-extend": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.2.1.tgz", + "integrity": "sha512-g3UB796vUFIY90VIv/WX3L2c8CS2MdWUww3CNrYmqza1Fg0DURc2K/O4YrnklBdQarSJ/y8JnJYDGc+1iumQjg==" + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/loader-runner": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.4.0.tgz", + "integrity": "sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==", + "engines": { + "node": ">=4.3.0 <5.0.0 || >=5.10" + } + }, + "node_modules/loader-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", + "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/loader-utils/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/locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dependencies": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=" + }, + "node_modules/lolex": { + "version": "2.7.5", + "resolved": "https://registry.npmjs.org/lolex/-/lolex-2.7.5.tgz", + "integrity": "sha512-l9x0+1offnKKIzYVjyXU2SiwhXDLekRzKyhnbyldPHvC7BvLPVpdNUNR2KeMAiCN2D/kLNttZgQD5WjSxuBx3Q==" + }, + "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": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/make-dir": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", + "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", + "dependencies": { + "pify": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "dependencies": { + "object-visit": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/memory-fs": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", + "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=", + "dependencies": { + "errno": "^0.1.3", + "readable-stream": "^2.0.1" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" + }, + "node_modules/micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dependencies": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/miller-rabin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", + "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", + "dependencies": { + "bn.js": "^4.0.0", + "brorand": "^1.0.1" + }, + "bin": { + "miller-rabin": "bin/miller-rabin" + } + }, + "node_modules/miller-rabin/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" + }, + "node_modules/minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=" + }, + "node_modules/minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + }, + "node_modules/mississippi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz", + "integrity": "sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==", + "dependencies": { + "concat-stream": "^1.5.0", + "duplexify": "^3.4.2", + "end-of-stream": "^1.1.0", + "flush-write-stream": "^1.0.0", + "from2": "^2.1.0", + "parallel-transform": "^1.1.0", + "pump": "^3.0.0", + "pumpify": "^1.3.3", + "stream-each": "^1.1.0", + "through2": "^2.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/mixin-deep": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", + "dependencies": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dependencies": { + "minimist": "^1.2.5" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/mocha": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-5.2.0.tgz", + "integrity": "sha512-2IUgKDhc3J7Uug+FxMXuqIyYzH7gJjXECKe/w43IGgQHTSj3InJi+yAA7T24L9bQMRKiUEHxEX37G5JpVUGLcQ==", + "dependencies": { + "browser-stdout": "1.3.1", + "commander": "2.15.1", + "debug": "3.1.0", + "diff": "3.5.0", + "escape-string-regexp": "1.0.5", + "glob": "7.1.2", + "growl": "1.10.5", + "he": "1.1.1", + "minimatch": "3.0.4", + "mkdirp": "0.5.1", + "supports-color": "5.4.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/mocha/node_modules/debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/mocha/node_modules/minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + }, + "node_modules/mocha/node_modules/mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "deprecated": "Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.)", + "dependencies": { + "minimist": "0.0.8" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/mocha/node_modules/supports-color": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", + "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/move-concurrently": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", + "integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=", + "dependencies": { + "aproba": "^1.1.1", + "copy-concurrently": "^1.0.0", + "fs-write-stream-atomic": "^1.0.8", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.3" + } + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "node_modules/nan": { + "version": "2.14.2", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.2.tgz", + "integrity": "sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==", + "optional": true + }, + "node_modules/nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "dependencies": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" + }, + "node_modules/nise": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/nise/-/nise-1.5.3.tgz", + "integrity": "sha512-Ymbac/94xeIrMf59REBPOv0thr+CJVFMhrlAkW/gjCIE58BGQdCj0x7KRCb3yz+Ga2Rz3E9XXSvUyyxqqhjQAQ==", + "dependencies": { + "@sinonjs/formatio": "^3.2.1", + "@sinonjs/text-encoding": "^0.7.1", + "just-extend": "^4.0.2", + "lolex": "^5.0.1", + "path-to-regexp": "^1.7.0" + } + }, + "node_modules/nise/node_modules/@sinonjs/formatio": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-3.2.2.tgz", + "integrity": "sha512-B8SEsgd8gArBLMD6zpRw3juQ2FVSsmdd7qlevyDqzS9WTCtvF55/gAL+h6gue8ZvPYcdiPdvueM/qm//9XzyTQ==", + "dependencies": { + "@sinonjs/commons": "^1", + "@sinonjs/samsam": "^3.1.0" + } + }, + "node_modules/nise/node_modules/lolex": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/lolex/-/lolex-5.1.2.tgz", + "integrity": "sha512-h4hmjAvHTmd+25JSwrtTIuwbKdwg5NzZVRMLn9saij4SZaepCrTCxPr35H/3bjwfMJtN+t3CX8672UIkglz28A==", + "dependencies": { + "@sinonjs/commons": "^1.7.0" + } + }, + "node_modules/node-libs-browser": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.1.tgz", + "integrity": "sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==", + "dependencies": { + "assert": "^1.1.1", + "browserify-zlib": "^0.2.0", + "buffer": "^4.3.0", + "console-browserify": "^1.1.0", + "constants-browserify": "^1.0.0", + "crypto-browserify": "^3.11.0", + "domain-browser": "^1.1.1", + "events": "^3.0.0", + "https-browserify": "^1.0.0", + "os-browserify": "^0.3.0", + "path-browserify": "0.0.1", + "process": "^0.11.10", + "punycode": "^1.2.4", + "querystring-es3": "^0.2.0", + "readable-stream": "^2.3.3", + "stream-browserify": "^2.0.1", + "stream-http": "^2.7.2", + "string_decoder": "^1.0.0", + "timers-browserify": "^2.0.4", + "tty-browserify": "0.0.0", + "url": "^0.11.0", + "util": "^0.11.0", + "vm-browserify": "^1.0.1" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "dependencies": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy/node_modules/is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy/node_modules/is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy/node_modules/is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dependencies": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy/node_modules/is-descriptor/node_modules/kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "dependencies": { + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/os-browserify": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", + "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=" + }, + "node_modules/os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dependencies": { + "p-try": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dependencies": { + "p-limit": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "engines": { + "node": ">=4" + } + }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" + }, + "node_modules/parallel-transform": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.2.0.tgz", + "integrity": "sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg==", + "dependencies": { + "cyclist": "^1.0.1", + "inherits": "^2.0.3", + "readable-stream": "^2.1.5" + } + }, + "node_modules/parse-asn1": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz", + "integrity": "sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==", + "dependencies": { + "asn1.js": "^5.2.0", + "browserify-aes": "^1.0.0", + "evp_bytestokey": "^1.0.0", + "pbkdf2": "^3.0.3", + "safe-buffer": "^5.1.1" + } + }, + "node_modules/pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-browserify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz", + "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==" + }, + "node_modules/path-dirname": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", + "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", + "optional": true + }, + "node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "engines": { + "node": ">=4" + } + }, + "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": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "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-to-regexp": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", + "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", + "dependencies": { + "isarray": "0.0.1" + } + }, + "node_modules/pbkdf2": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", + "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", + "dependencies": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/picomatch": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", + "optional": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "engines": { + "node": ">=4" + } + }, + "node_modules/pkg-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", + "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", + "dependencies": { + "find-up": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/private": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", + "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "node_modules/promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=" + }, + "node_modules/promises-aplus-tests": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/promises-aplus-tests/-/promises-aplus-tests-2.1.2.tgz", + "integrity": "sha1-drfFY4locghhlpz7zYeVr9J0iFw=", + "dependencies": { + "mocha": "^2.5.3", + "sinon": "^1.10.3", + "underscore": "~1.8.3" + }, + "bin": { + "promises-aplus-tests": "lib/cli.js" + } + }, + "node_modules/promises-aplus-tests/node_modules/commander": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.3.0.tgz", + "integrity": "sha1-/UMOiJgy7DU7ms0d4hfBHLPu+HM=", + "engines": { + "node": ">= 0.6.x" + } + }, + "node_modules/promises-aplus-tests/node_modules/debug": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", + "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", + "dependencies": { + "ms": "0.7.1" + } + }, + "node_modules/promises-aplus-tests/node_modules/diff": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-1.4.0.tgz", + "integrity": "sha1-fyjS657nsVqX79ic5j3P2qPMur8=", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/promises-aplus-tests/node_modules/escape-string-regexp": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.2.tgz", + "integrity": "sha1-Tbwv5nTnGUnK8/smlc5/LcHZqNE=", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/promises-aplus-tests/node_modules/glob": { + "version": "3.2.11", + "resolved": "https://registry.npmjs.org/glob/-/glob-3.2.11.tgz", + "integrity": "sha1-Spc/Y1uRkPcV0QmH1cAP0oFevj0=", + "dependencies": { + "inherits": "2", + "minimatch": "0.3" + }, + "engines": { + "node": "*" + } + }, + "node_modules/promises-aplus-tests/node_modules/growl": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.9.2.tgz", + "integrity": "sha1-Dqd0NxXbjY3ixe3hd14bRayFwC8=" + }, + "node_modules/promises-aplus-tests/node_modules/lolex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/lolex/-/lolex-1.3.2.tgz", + "integrity": "sha1-fD2mL/yzDw9agKJWbKJORdigHzE=" + }, + "node_modules/promises-aplus-tests/node_modules/lru-cache": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", + "integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI=" + }, + "node_modules/promises-aplus-tests/node_modules/minimatch": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.3.0.tgz", + "integrity": "sha1-J12O2qxPG7MyZHIInnlJyDlGmd0=", + "deprecated": "Please update to minimatch 3.0.2 or higher to avoid a RegExp DoS issue", + "dependencies": { + "lru-cache": "2", + "sigmund": "~1.0.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/promises-aplus-tests/node_modules/minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + }, + "node_modules/promises-aplus-tests/node_modules/mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "deprecated": "Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.)", + "dependencies": { + "minimist": "0.0.8" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/promises-aplus-tests/node_modules/mocha": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-2.5.3.tgz", + "integrity": "sha1-FhvlvetJZ3HrmzV0UFC2IrWu/Fg=", + "dependencies": { + "commander": "2.3.0", + "debug": "2.2.0", + "diff": "1.4.0", + "escape-string-regexp": "1.0.2", + "glob": "3.2.11", + "growl": "1.9.2", + "jade": "0.26.3", + "mkdirp": "0.5.1", + "supports-color": "1.2.0", + "to-iso-string": "0.0.2" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha" + }, + "engines": { + "node": ">= 0.8.x" + } + }, + "node_modules/promises-aplus-tests/node_modules/ms": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", + "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=" + }, + "node_modules/promises-aplus-tests/node_modules/samsam": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/samsam/-/samsam-1.1.2.tgz", + "integrity": "sha1-vsEf3IOp/aBjQBIQ5AF2wwJNFWc=", + "deprecated": "This package has been deprecated in favour of @sinonjs/samsam" + }, + "node_modules/promises-aplus-tests/node_modules/sinon": { + "version": "1.17.7", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-1.17.7.tgz", + "integrity": "sha1-RUKk9JugxFwF6y6d2dID4rjv4L8=", + "dependencies": { + "formatio": "1.1.1", + "lolex": "1.3.2", + "samsam": "1.1.2", + "util": ">=0.10.3 <1" + }, + "engines": { + "node": ">=0.1.103" + } + }, + "node_modules/promises-aplus-tests/node_modules/supports-color": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-1.2.0.tgz", + "integrity": "sha1-/x7R5hFp0Gs88tWI4YixjYhH4X4=", + "bin": { + "supports-color": "cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/prr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=" + }, + "node_modules/public-encrypt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", + "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", + "dependencies": { + "bn.js": "^4.1.0", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "parse-asn1": "^5.0.0", + "randombytes": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/public-encrypt/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/pumpify": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", + "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", + "dependencies": { + "duplexify": "^3.6.0", + "inherits": "^2.0.3", + "pump": "^2.0.0" + } + }, + "node_modules/pumpify/node_modules/pump": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", + "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" + }, + "node_modules/querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", + "engines": { + "node": ">=0.4.x" + } + }, + "node_modules/querystring-es3": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", + "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=", + "engines": { + "node": ">=0.4.x" + } + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/randomfill": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", + "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", + "dependencies": { + "randombytes": "^2.0.5", + "safe-buffer": "^5.1.0" + } + }, + "node_modules/readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/readable-stream/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "node_modules/readable-stream/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/readdirp": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz", + "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==", + "optional": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/rechoir": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.0.tgz", + "integrity": "sha512-ADsDEH2bvbjltXEP+hTIAmeFekTFK0V2BTxMkok6qILyAJEXV0AFfoWcAq4yfll5VdIMd/RVXq0lR+wQi5ZU3Q==", + "dependencies": { + "resolve": "^1.9.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==" + }, + "node_modules/regenerator-runtime": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" + }, + "node_modules/regenerator-transform": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.10.1.tgz", + "integrity": "sha512-PJepbvDbuK1xgIgnau7Y90cwaAmO/LCLMI2mPvaXq2heGMR3aWW5/BQvYrhJ8jgmQjXewXvBjzfqKcVOmhjZ6Q==", + "dependencies": { + "babel-runtime": "^6.18.0", + "babel-types": "^6.19.0", + "private": "^0.1.6" + } + }, + "node_modules/regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "dependencies": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/regexpu-core": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-2.0.0.tgz", + "integrity": "sha1-SdA4g3uNz4v6W5pCE5k45uoq4kA=", + "dependencies": { + "regenerate": "^1.2.1", + "regjsgen": "^0.2.0", + "regjsparser": "^0.1.4" + } + }, + "node_modules/regjsgen": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz", + "integrity": "sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc=" + }, + "node_modules/regjsparser": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz", + "integrity": "sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw=", + "dependencies": { + "jsesc": "~0.5.0" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/regjsparser/node_modules/jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", + "bin": { + "jsesc": "bin/jsesc" + } + }, + "node_modules/remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", + "optional": true + }, + "node_modules/repeat-element": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz", + "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/repeating": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", + "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", + "dependencies": { + "is-finite": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", + "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", + "dependencies": { + "is-core-module": "^2.2.0", + "path-parse": "^1.0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", + "deprecated": "https://github.com/lydell/resolve-url#deprecated" + }, + "node_modules/ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "engines": { + "node": ">=0.12" + } + }, + "node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/rimraf/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/ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "node_modules/run-queue": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz", + "integrity": "sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=", + "dependencies": { + "aproba": "^1.1.1" + } + }, + "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==" + }, + "node_modules/safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "dependencies": { + "ret": "~0.1.10" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/samsam": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/samsam/-/samsam-1.3.0.tgz", + "integrity": "sha512-1HwIYD/8UlOtFS3QO3w7ey+SdSDFE4HRNLZoZRYVQefrOY3l17epswImeB1ijgJFQJodIaHcwkp3r/myBjFVbg==", + "deprecated": "This package has been deprecated in favour of @sinonjs/samsam" + }, + "node_modules/schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "dependencies": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/serialize-javascript": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", + "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/set-value": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "dependencies": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/set-value/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/set-value/node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=" + }, + "node_modules/sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + }, + "bin": { + "sha.js": "bin.js" + } + }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "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/sigmund": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", + "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=" + }, + "node_modules/signal-exit": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", + "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==" + }, + "node_modules/sinon": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-4.5.0.tgz", + "integrity": "sha512-trdx+mB0VBBgoYucy6a9L7/jfQOmvGeaKZT4OOJ+lPAtI8623xyGr8wLiE4eojzBS8G9yXbhx42GHUOVLr4X2w==", + "hasInstallScript": true, + "dependencies": { + "@sinonjs/formatio": "^2.0.0", + "diff": "^3.1.0", + "lodash.get": "^4.4.2", + "lolex": "^2.2.0", + "nise": "^1.2.0", + "supports-color": "^5.1.0", + "type-detect": "^4.0.5" + } + }, + "node_modules/sinon/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/slash": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", + "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "dependencies": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "dependencies": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-node/node_modules/define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dependencies": { + "is-descriptor": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "dependencies": { + "kind-of": "^3.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-util/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/is-accessor-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/is-data-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dependencies": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-list-map": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", + "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==" + }, + "node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-resolve": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", + "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", + "dependencies": { + "atob": "^2.1.2", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "node_modules/source-map-support": { + "version": "0.4.18", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", + "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", + "dependencies": { + "source-map": "^0.5.6" + } + }, + "node_modules/source-map-url": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz", + "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==" + }, + "node_modules/split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "dependencies": { + "extend-shallow": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ssri": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.2.tgz", + "integrity": "sha512-cepbSq/neFK7xB6A50KHN0xHDotYzq58wWCa5LeWqnPrHG8GzfEjO/4O8kpmcGW+oaxkvhEJCWgbgNk4/ZV93Q==", + "dependencies": { + "figgy-pudding": "^3.5.1" + } + }, + "node_modules/static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "dependencies": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/static-extend/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/static-extend/node_modules/is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/static-extend/node_modules/is-accessor-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/static-extend/node_modules/is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/static-extend/node_modules/is-data-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/static-extend/node_modules/is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dependencies": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/static-extend/node_modules/kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stream-browserify": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz", + "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==", + "dependencies": { + "inherits": "~2.0.1", + "readable-stream": "^2.0.2" + } + }, + "node_modules/stream-each": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.3.tgz", + "integrity": "sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==", + "dependencies": { + "end-of-stream": "^1.1.0", + "stream-shift": "^1.0.0" + } + }, + "node_modules/stream-http": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz", + "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==", + "dependencies": { + "builtin-status-codes": "^3.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.3.6", + "to-arraybuffer": "^1.0.0", + "xtend": "^4.0.0" + } + }, + "node_modules/stream-shift": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", + "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==" + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "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/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/tapable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", + "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/terser": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-4.8.0.tgz", + "integrity": "sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw==", + "dependencies": { + "commander": "^2.20.0", + "source-map": "~0.6.1", + "source-map-support": "~0.5.12" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.5.tgz", + "integrity": "sha512-04Rfe496lN8EYruwi6oPQkG0vo8C+HT49X687FZnpPF0qMAIHONI6HEXYPKDOE8e5HjXTyKfqRd/agHtH0kOtw==", + "dependencies": { + "cacache": "^12.0.2", + "find-cache-dir": "^2.1.0", + "is-wsl": "^1.1.0", + "schema-utils": "^1.0.0", + "serialize-javascript": "^4.0.0", + "source-map": "^0.6.1", + "terser": "^4.1.2", + "webpack-sources": "^1.4.0", + "worker-farm": "^1.7.0" + }, + "engines": { + "node": ">= 6.9.0" + }, + "peerDependencies": { + "webpack": "^4.0.0" + } + }, + "node_modules/terser-webpack-plugin/node_modules/find-cache-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", + "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^2.0.0", + "pkg-dir": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/terser-webpack-plugin/node_modules/find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/terser-webpack-plugin/node_modules/locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dependencies": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/terser-webpack-plugin/node_modules/make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dependencies": { + "pify": "^4.0.1", + "semver": "^5.6.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/terser-webpack-plugin/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/terser-webpack-plugin/node_modules/p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dependencies": { + "p-limit": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/terser-webpack-plugin/node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/terser-webpack-plugin/node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "engines": { + "node": ">=6" + } + }, + "node_modules/terser-webpack-plugin/node_modules/pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "dependencies": { + "find-up": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/terser-webpack-plugin/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + }, + "node_modules/terser/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/terser/node_modules/source-map-support": { + "version": "0.5.19", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", + "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/timers-browserify": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.12.tgz", + "integrity": "sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==", + "dependencies": { + "setimmediate": "^1.0.4" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/to-arraybuffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", + "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=" + }, + "node_modules/to-fast-properties": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", + "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-iso-string": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/to-iso-string/-/to-iso-string-0.0.2.tgz", + "integrity": "sha1-TcGeZk38y+Jb2NtQiwDG2hWCVdE=", + "deprecated": "to-iso-string has been deprecated, use @segment/to-iso-string instead." + }, + "node_modules/to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-object-path/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "dependencies": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dependencies": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/trim-right": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", + "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/tty-browserify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", + "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=" + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "engines": { + "node": ">=4" + } + }, + "node_modules/typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" + }, + "node_modules/underscore": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz", + "integrity": "sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI=" + }, + "node_modules/union-value": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "dependencies": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/union-value/node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unique-filename": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", + "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", + "dependencies": { + "unique-slug": "^2.0.0" + } + }, + "node_modules/unique-slug": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", + "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", + "dependencies": { + "imurmurhash": "^0.1.4" + } + }, + "node_modules/unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "dependencies": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value/node_modules/has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "dependencies": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value/node_modules/has-value/node_modules/isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dependencies": { + "isarray": "1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value/node_modules/has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "node_modules/upath": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", + "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", + "optional": true, + "engines": { + "node": ">=4", + "yarn": "*" + } + }, + "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/uri-js/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/urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", + "deprecated": "Please see https://github.com/lydell/urix#deprecated" + }, + "node_modules/url": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", + "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", + "dependencies": { + "punycode": "1.3.2", + "querystring": "0.2.0" + } + }, + "node_modules/url/node_modules/punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=" + }, + "node_modules/use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/util": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz", + "integrity": "sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==", + "dependencies": { + "inherits": "2.0.3" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "node_modules/util/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "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/vm-browserify": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", + "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==" + }, + "node_modules/watchpack": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.7.5.tgz", + "integrity": "sha512-9P3MWk6SrKjHsGkLT2KHXdQ/9SNkyoJbabxnKOoJepsvJjJG8uYTR3yTPxPQvNDI3w4Nz1xnE0TLHK4RIVe/MQ==", + "dependencies": { + "graceful-fs": "^4.1.2", + "neo-async": "^2.5.0" + }, + "optionalDependencies": { + "chokidar": "^3.4.1", + "watchpack-chokidar2": "^2.0.1" + } + }, + "node_modules/watchpack-chokidar2": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/watchpack-chokidar2/-/watchpack-chokidar2-2.0.1.tgz", + "integrity": "sha512-nCFfBIPKr5Sh61s4LPpy1Wtfi0HE8isJ3d2Yb5/Ppw2P2B/3eVSEBjKfN0fmHJSK14+31KwMKmcrzs2GM4P0Ww==", + "optional": true, + "dependencies": { + "chokidar": "^2.1.8" + } + }, + "node_modules/watchpack-chokidar2/node_modules/anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "optional": true, + "dependencies": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + } + }, + "node_modules/watchpack-chokidar2/node_modules/anymatch/node_modules/normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "optional": true, + "dependencies": { + "remove-trailing-separator": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/watchpack-chokidar2/node_modules/binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/watchpack-chokidar2/node_modules/chokidar": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", + "deprecated": "Chokidar 2 will break on node v14+. Upgrade to chokidar 3 with 15x less dependencies.", + "optional": true, + "dependencies": { + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "glob-parent": "^3.1.0", + "inherits": "^2.0.3", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "normalize-path": "^3.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.2.1", + "upath": "^1.1.1" + }, + "optionalDependencies": { + "fsevents": "^1.2.7" + } + }, + "node_modules/watchpack-chokidar2/node_modules/fsevents": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", + "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", + "deprecated": "fsevents 1 will break on node v14+ and could be using insecure binaries. Upgrade to fsevents 2.", + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "dependencies": { + "bindings": "^1.5.0", + "nan": "^2.12.1" + }, + "engines": { + "node": ">= 4.0" + } + }, + "node_modules/watchpack-chokidar2/node_modules/glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "optional": true, + "dependencies": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + } + }, + "node_modules/watchpack-chokidar2/node_modules/glob-parent/node_modules/is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "optional": true, + "dependencies": { + "is-extglob": "^2.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/watchpack-chokidar2/node_modules/is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "optional": true, + "dependencies": { + "binary-extensions": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/watchpack-chokidar2/node_modules/readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "optional": true, + "dependencies": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/webpack": { + "version": "4.46.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.46.0.tgz", + "integrity": "sha512-6jJuJjg8znb/xRItk7bkT0+Q7AHCYjjFnvKIWQPkNIOyRqoCGvkOs0ipeQzrqz4l5FtN5ZI/ukEHroeX/o1/5Q==", + "dependencies": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-module-context": "1.9.0", + "@webassemblyjs/wasm-edit": "1.9.0", + "@webassemblyjs/wasm-parser": "1.9.0", + "acorn": "^6.4.1", + "ajv": "^6.10.2", + "ajv-keywords": "^3.4.1", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^4.5.0", + "eslint-scope": "^4.0.3", + "json-parse-better-errors": "^1.0.2", + "loader-runner": "^2.4.0", + "loader-utils": "^1.2.3", + "memory-fs": "^0.4.1", + "micromatch": "^3.1.10", + "mkdirp": "^0.5.3", + "neo-async": "^2.6.1", + "node-libs-browser": "^2.2.1", + "schema-utils": "^1.0.0", + "tapable": "^1.1.3", + "terser-webpack-plugin": "^1.4.3", + "watchpack": "^1.7.4", + "webpack-sources": "^1.4.1" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=6.11.5" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + }, + "webpack-command": { + "optional": true + } + } + }, + "node_modules/webpack-cli": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.7.0.tgz", + "integrity": "sha512-7bKr9182/sGfjFm+xdZSwgQuFjgEcy0iCTIBxRUeteJ2Kr8/Wz0qNJX+jw60LU36jApt4nmMkep6+W5AKhok6g==", + "dependencies": { + "@discoveryjs/json-ext": "^0.5.0", + "@webpack-cli/configtest": "^1.0.3", + "@webpack-cli/info": "^1.2.4", + "@webpack-cli/serve": "^1.4.0", + "colorette": "^1.2.1", + "commander": "^7.0.0", + "execa": "^5.0.0", + "fastest-levenshtein": "^1.0.12", + "import-local": "^3.0.2", + "interpret": "^2.2.0", + "rechoir": "^0.7.0", + "v8-compile-cache": "^2.2.0", + "webpack-merge": "^5.7.3" + }, + "bin": { + "webpack-cli": "bin/cli.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "peerDependencies": { + "webpack": "4.x.x || 5.x.x" + }, + "peerDependenciesMeta": { + "@webpack-cli/generators": { + "optional": true + }, + "@webpack-cli/migrate": { + "optional": true + }, + "webpack-bundle-analyzer": { + "optional": true + }, + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/webpack-cli/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "engines": { + "node": ">= 10" + } + }, + "node_modules/webpack-merge": { + "version": "5.7.3", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.7.3.tgz", + "integrity": "sha512-6/JUQv0ELQ1igjGDzHkXbVDRxkfA57Zw7PfiupdLFJYrgFqY5ZP8xxbpp2lU3EPwYx89ht5Z/aDkD40hFCm5AA==", + "dependencies": { + "clone-deep": "^4.0.1", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/webpack-sources": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz", + "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", + "dependencies": { + "source-list-map": "^2.0.0", + "source-map": "~0.6.1" + } + }, + "node_modules/webpack-sources/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "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/wildcard": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz", + "integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==" + }, + "node_modules/worker-farm": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.7.0.tgz", + "integrity": "sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw==", + "dependencies": { + "errno": "~0.1.7" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==" + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + } + }, + "dependencies": { + "@discoveryjs/json-ext": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.3.tgz", + "integrity": "sha512-Fxt+AfXgjMoin2maPIYzFZnQjAXjAL0PHscM5pRTtatFqB+vZxAM9tLp2Optnuw3QOQC40jTNeGYFOMvyf7v9g==" + }, + "@sinonjs/commons": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", + "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", + "requires": { + "type-detect": "4.0.8" + } + }, + "@sinonjs/formatio": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-2.0.0.tgz", + "integrity": "sha512-ls6CAMA6/5gG+O/IdsBcblvnd8qcO/l1TYoNeAzp3wcISOxlPXQEus0mLcdwazEkWjaBdaJ3TaxmNgCLWwvWzg==", + "requires": { + "samsam": "1.3.0" + } + }, + "@sinonjs/samsam": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-3.3.3.tgz", + "integrity": "sha512-bKCMKZvWIjYD0BLGnNrxVuw4dkWCYsLqFOUWw8VgKF/+5Y+mE7LfHWPIYoDXowH+3a9LsWDMo0uAP8YDosPvHQ==", + "requires": { + "@sinonjs/commons": "^1.3.0", + "array-from": "^2.1.1", + "lodash": "^4.17.15" + } + }, + "@sinonjs/text-encoding": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz", + "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==" + }, + "@webassemblyjs/ast": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.9.0.tgz", + "integrity": "sha512-C6wW5L+b7ogSDVqymbkkvuW9kruN//YisMED04xzeBBqjHa2FYnmvOlS6Xj68xWQRgWvI9cIglsjFowH/RJyEA==", + "requires": { + "@webassemblyjs/helper-module-context": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/wast-parser": "1.9.0" + } + }, + "@webassemblyjs/floating-point-hex-parser": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.9.0.tgz", + "integrity": "sha512-TG5qcFsS8QB4g4MhrxK5TqfdNe7Ey/7YL/xN+36rRjl/BlGE/NcBvJcqsRgCP6Z92mRE+7N50pRIi8SmKUbcQA==" + }, + "@webassemblyjs/helper-api-error": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.9.0.tgz", + "integrity": "sha512-NcMLjoFMXpsASZFxJ5h2HZRcEhDkvnNFOAKneP5RbKRzaWJN36NC4jqQHKwStIhGXu5mUWlUUk7ygdtrO8lbmw==" + }, + "@webassemblyjs/helper-buffer": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.9.0.tgz", + "integrity": "sha512-qZol43oqhq6yBPx7YM3m9Bv7WMV9Eevj6kMi6InKOuZxhw+q9hOkvq5e/PpKSiLfyetpaBnogSbNCfBwyB00CA==" + }, + "@webassemblyjs/helper-code-frame": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.9.0.tgz", + "integrity": "sha512-ERCYdJBkD9Vu4vtjUYe8LZruWuNIToYq/ME22igL+2vj2dQ2OOujIZr3MEFvfEaqKoVqpsFKAGsRdBSBjrIvZA==", + "requires": { + "@webassemblyjs/wast-printer": "1.9.0" + } + }, + "@webassemblyjs/helper-fsm": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-fsm/-/helper-fsm-1.9.0.tgz", + "integrity": "sha512-OPRowhGbshCb5PxJ8LocpdX9Kl0uB4XsAjl6jH/dWKlk/mzsANvhwbiULsaiqT5GZGT9qinTICdj6PLuM5gslw==" + }, + "@webassemblyjs/helper-module-context": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-module-context/-/helper-module-context-1.9.0.tgz", + "integrity": "sha512-MJCW8iGC08tMk2enck1aPW+BE5Cw8/7ph/VGZxwyvGbJwjktKkDK7vy7gAmMDx88D7mhDTCNKAW5tED+gZ0W8g==", + "requires": { + "@webassemblyjs/ast": "1.9.0" + } + }, + "@webassemblyjs/helper-wasm-bytecode": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.9.0.tgz", + "integrity": "sha512-R7FStIzyNcd7xKxCZH5lE0Bqy+hGTwS3LJjuv1ZVxd9O7eHCedSdrId/hMOd20I+v8wDXEn+bjfKDLzTepoaUw==" + }, + "@webassemblyjs/helper-wasm-section": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.9.0.tgz", + "integrity": "sha512-XnMB8l3ek4tvrKUUku+IVaXNHz2YsJyOOmz+MMkZvh8h1uSJpSen6vYnw3IoQ7WwEuAhL8Efjms1ZWjqh2agvw==", + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-buffer": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/wasm-gen": "1.9.0" + } + }, + "@webassemblyjs/ieee754": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.9.0.tgz", + "integrity": "sha512-dcX8JuYU/gvymzIHc9DgxTzUUTLexWwt8uCTWP3otys596io0L5aW02Gb1RjYpx2+0Jus1h4ZFqjla7umFniTg==", + "requires": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "@webassemblyjs/leb128": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.9.0.tgz", + "integrity": "sha512-ENVzM5VwV1ojs9jam6vPys97B/S65YQtv/aanqnU7D8aSoHFX8GyhGg0CMfyKNIHBuAVjy3tlzd5QMMINa7wpw==", + "requires": { + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/utf8": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.9.0.tgz", + "integrity": "sha512-GZbQlWtopBTP0u7cHrEx+73yZKrQoBMpwkGEIqlacljhXCkVM1kMQge/Mf+csMJAjEdSwhOyLAS0AoR3AG5P8w==" + }, + "@webassemblyjs/wasm-edit": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.9.0.tgz", + "integrity": "sha512-FgHzBm80uwz5M8WKnMTn6j/sVbqilPdQXTWraSjBwFXSYGirpkSWE2R9Qvz9tNiTKQvoKILpCuTjBKzOIm0nxw==", + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-buffer": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/helper-wasm-section": "1.9.0", + "@webassemblyjs/wasm-gen": "1.9.0", + "@webassemblyjs/wasm-opt": "1.9.0", + "@webassemblyjs/wasm-parser": "1.9.0", + "@webassemblyjs/wast-printer": "1.9.0" + } + }, + "@webassemblyjs/wasm-gen": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.9.0.tgz", + "integrity": "sha512-cPE3o44YzOOHvlsb4+E9qSqjc9Qf9Na1OO/BHFy4OI91XDE14MjFN4lTMezzaIWdPqHnsTodGGNP+iRSYfGkjA==", + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/ieee754": "1.9.0", + "@webassemblyjs/leb128": "1.9.0", + "@webassemblyjs/utf8": "1.9.0" + } + }, + "@webassemblyjs/wasm-opt": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.9.0.tgz", + "integrity": "sha512-Qkjgm6Anhm+OMbIL0iokO7meajkzQD71ioelnfPEj6r4eOFuqm4YC3VBPqXjFyyNwowzbMD+hizmprP/Fwkl2A==", + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-buffer": "1.9.0", + "@webassemblyjs/wasm-gen": "1.9.0", + "@webassemblyjs/wasm-parser": "1.9.0" + } + }, + "@webassemblyjs/wasm-parser": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.9.0.tgz", + "integrity": "sha512-9+wkMowR2AmdSWQzsPEjFU7njh8HTO5MqO8vjwEHuM+AMHioNqSBONRdr0NQQ3dVQrzp0s8lTcYqzUdb7YgELA==", + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-api-error": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/ieee754": "1.9.0", + "@webassemblyjs/leb128": "1.9.0", + "@webassemblyjs/utf8": "1.9.0" + } + }, + "@webassemblyjs/wast-parser": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-parser/-/wast-parser-1.9.0.tgz", + "integrity": "sha512-qsqSAP3QQ3LyZjNC/0jBJ/ToSxfYJ8kYyuiGvtn/8MK89VrNEfwj7BPQzJVHi0jGTRK2dGdJ5PRqhtjzoww+bw==", + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/floating-point-hex-parser": "1.9.0", + "@webassemblyjs/helper-api-error": "1.9.0", + "@webassemblyjs/helper-code-frame": "1.9.0", + "@webassemblyjs/helper-fsm": "1.9.0", + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/wast-printer": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.9.0.tgz", + "integrity": "sha512-2J0nE95rHXHyQ24cWjMKJ1tqB/ds8z/cyeOZxJhcb+rW+SQASVjuznUSmdz5GpVJTzU8JkhYut0D3siFDD6wsA==", + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/wast-parser": "1.9.0", + "@xtuc/long": "4.2.2" + } + }, + "@webpack-cli/configtest": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.0.3.tgz", + "integrity": "sha512-WQs0ep98FXX2XBAfQpRbY0Ma6ADw8JR6xoIkaIiJIzClGOMqVRvPCWqndTxf28DgFopWan0EKtHtg/5W1h0Zkw==", + "requires": {} + }, + "@webpack-cli/info": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.2.4.tgz", + "integrity": "sha512-ogE2T4+pLhTTPS/8MM3IjHn0IYplKM4HbVNMCWA9N4NrdPzunwenpCsqKEXyejMfRu6K8mhauIPYf8ZxWG5O6g==", + "requires": { + "envinfo": "^7.7.3" + } + }, + "@webpack-cli/serve": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.4.0.tgz", + "integrity": "sha512-xgT/HqJ+uLWGX+Mzufusl3cgjAcnqYYskaB7o0vRcwOEfuu6hMzSILQpnIzFMGsTaeaX4Nnekl+6fadLbl1/Vg==", + "requires": {} + }, + "@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==" + }, + "@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==" + }, + "acorn": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", + "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==" + }, + "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" + } + }, + "ajv-errors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.1.tgz", + "integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==", + "requires": {} + }, + "ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "requires": {} + }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" + }, + "anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "optional": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" + }, + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=" + }, + "arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==" + }, + "arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=" + }, + "array-from": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/array-from/-/array-from-2.1.1.tgz", + "integrity": "sha1-z+nYwmYoudxa7MYqn12PHzUsEZU=" + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=" + }, + "asn1.js": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", + "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", + "requires": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "safer-buffer": "^2.1.0" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + } + } + }, + "assert": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz", + "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==", + "requires": { + "object-assign": "^4.1.1", + "util": "0.10.3" + }, + "dependencies": { + "inherits": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", + "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=" + }, + "util": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", + "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", + "requires": { + "inherits": "2.0.1" + } + } + } + }, + "assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=" + }, + "async-each": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", + "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", + "optional": true + }, + "atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==" + }, + "babel-code-frame": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", + "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", + "requires": { + "chalk": "^1.1.3", + "esutils": "^2.0.2", + "js-tokens": "^3.0.2" + } + }, + "babel-core": { + "version": "6.26.3", + "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.26.3.tgz", + "integrity": "sha512-6jyFLuDmeidKmUEb3NM+/yawG0M2bDZ9Z1qbZP59cyHLz8kYGKYwpJP0UwUKKUiTRNvxfLesJnTedqczP7cTDA==", + "requires": { + "babel-code-frame": "^6.26.0", + "babel-generator": "^6.26.0", + "babel-helpers": "^6.24.1", + "babel-messages": "^6.23.0", + "babel-register": "^6.26.0", + "babel-runtime": "^6.26.0", + "babel-template": "^6.26.0", + "babel-traverse": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "convert-source-map": "^1.5.1", + "debug": "^2.6.9", + "json5": "^0.5.1", + "lodash": "^4.17.4", + "minimatch": "^3.0.4", + "path-is-absolute": "^1.0.1", + "private": "^0.1.8", + "slash": "^1.0.0", + "source-map": "^0.5.7" + } + }, + "babel-generator": { + "version": "6.26.1", + "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.1.tgz", + "integrity": "sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA==", + "requires": { + "babel-messages": "^6.23.0", + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "detect-indent": "^4.0.0", + "jsesc": "^1.3.0", + "lodash": "^4.17.4", + "source-map": "^0.5.7", + "trim-right": "^1.0.1" + } + }, + "babel-helper-builder-binary-assignment-operator-visitor": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz", + "integrity": "sha1-zORReto1b0IgvK6KAsKzRvmlZmQ=", + "requires": { + "babel-helper-explode-assignable-expression": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" + } + }, + "babel-helper-call-delegate": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz", + "integrity": "sha1-7Oaqzdx25Bw0YfiL/Fdb0Nqi340=", + "requires": { + "babel-helper-hoist-variables": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-traverse": "^6.24.1", + "babel-types": "^6.24.1" + } + }, + "babel-helper-define-map": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz", + "integrity": "sha1-pfVtq0GiX5fstJjH66ypgZ+Vvl8=", + "requires": { + "babel-helper-function-name": "^6.24.1", + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "lodash": "^4.17.4" + } + }, + "babel-helper-explode-assignable-expression": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz", + "integrity": "sha1-8luCz33BBDPFX3BZLVdGQArCLKo=", + "requires": { + "babel-runtime": "^6.22.0", + "babel-traverse": "^6.24.1", + "babel-types": "^6.24.1" + } + }, + "babel-helper-function-name": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz", + "integrity": "sha1-00dbjAPtmCQqJbSDUasYOZ01gKk=", + "requires": { + "babel-helper-get-function-arity": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1", + "babel-traverse": "^6.24.1", + "babel-types": "^6.24.1" + } + }, + "babel-helper-get-function-arity": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz", + "integrity": "sha1-j3eCqpNAfEHTqlCQj4mwMbG2hT0=", + "requires": { + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" + } + }, + "babel-helper-hoist-variables": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz", + "integrity": "sha1-HssnaJydJVE+rbyZFKc/VAi+enY=", + "requires": { + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" + } + }, + "babel-helper-optimise-call-expression": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz", + "integrity": "sha1-96E0J7qfc/j0+pk8VKl4gtEkQlc=", + "requires": { + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" + } + }, + "babel-helper-regex": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz", + "integrity": "sha1-MlxZ+QL4LyS3T6zu0DY5VPZJXnI=", + "requires": { + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "lodash": "^4.17.4" + } + }, + "babel-helper-remap-async-to-generator": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz", + "integrity": "sha1-XsWBgnrXI/7N04HxySg5BnbkVRs=", + "requires": { + "babel-helper-function-name": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1", + "babel-traverse": "^6.24.1", + "babel-types": "^6.24.1" + } + }, + "babel-helper-replace-supers": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz", + "integrity": "sha1-v22/5Dk40XNpohPKiov3S2qQqxo=", + "requires": { + "babel-helper-optimise-call-expression": "^6.24.1", + "babel-messages": "^6.23.0", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1", + "babel-traverse": "^6.24.1", + "babel-types": "^6.24.1" + } + }, + "babel-helpers": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz", + "integrity": "sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI=", + "requires": { + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1" + } + }, + "babel-loader": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-7.1.5.tgz", + "integrity": "sha512-iCHfbieL5d1LfOQeeVJEUyD9rTwBcP/fcEbRCfempxTDuqrKpu0AZjLAQHEQa3Yqyj9ORKe2iHfoj4rHLf7xpw==", + "requires": { + "find-cache-dir": "^1.0.0", + "loader-utils": "^1.0.2", + "mkdirp": "^0.5.1" + } + }, + "babel-messages": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", + "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-check-es2015-constants": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz", + "integrity": "sha1-NRV7EBQm/S/9PaP3XH0ekYNbv4o=", + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-syntax-async-functions": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz", + "integrity": "sha1-ytnK0RkbWtY0vzCuCHI5HgZHvpU=" + }, + "babel-plugin-syntax-exponentiation-operator": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz", + "integrity": "sha1-nufoM3KQ2pUoggGmpX9BcDF4MN4=" + }, + "babel-plugin-syntax-trailing-function-commas": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz", + "integrity": "sha1-ugNgk3+NBuQBgKQ/4NVhb/9TLPM=" + }, + "babel-plugin-transform-async-to-generator": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz", + "integrity": "sha1-ZTbjeK/2yx1VF6wOQOs+n8jQh2E=", + "requires": { + "babel-helper-remap-async-to-generator": "^6.24.1", + "babel-plugin-syntax-async-functions": "^6.8.0", + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-transform-es2015-arrow-functions": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz", + "integrity": "sha1-RSaSy3EdX3ncf4XkQM5BufJE0iE=", + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-transform-es2015-block-scoped-functions": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz", + "integrity": "sha1-u8UbSflk1wy42OC5ToICRs46YUE=", + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-transform-es2015-block-scoping": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz", + "integrity": "sha1-1w9SmcEwjQXBL0Y4E7CgnnOxiV8=", + "requires": { + "babel-runtime": "^6.26.0", + "babel-template": "^6.26.0", + "babel-traverse": "^6.26.0", + "babel-types": "^6.26.0", + "lodash": "^4.17.4" + } + }, + "babel-plugin-transform-es2015-classes": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz", + "integrity": "sha1-WkxYpQyclGHlZLSyo7+ryXolhNs=", + "requires": { + "babel-helper-define-map": "^6.24.1", + "babel-helper-function-name": "^6.24.1", + "babel-helper-optimise-call-expression": "^6.24.1", + "babel-helper-replace-supers": "^6.24.1", + "babel-messages": "^6.23.0", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1", + "babel-traverse": "^6.24.1", + "babel-types": "^6.24.1" + } + }, + "babel-plugin-transform-es2015-computed-properties": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz", + "integrity": "sha1-b+Ko0WiV1WNPTNmZttNICjCBWbM=", + "requires": { + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1" + } + }, + "babel-plugin-transform-es2015-destructuring": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz", + "integrity": "sha1-mXux8auWf2gtKwh2/jWNYOdlxW0=", + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-transform-es2015-duplicate-keys": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz", + "integrity": "sha1-c+s9MQypaePvnskcU3QabxV2Qj4=", + "requires": { + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" + } + }, + "babel-plugin-transform-es2015-for-of": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz", + "integrity": "sha1-9HyVsrYT3x0+zC/bdXNiPHUkhpE=", + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-transform-es2015-function-name": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz", + "integrity": "sha1-g0yJhTvDaxrw86TF26qU/Y6sqos=", + "requires": { + "babel-helper-function-name": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" + } + }, + "babel-plugin-transform-es2015-literals": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz", + "integrity": "sha1-T1SgLWzWbPkVKAAZox0xklN3yi4=", + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-transform-es2015-modules-amd": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz", + "integrity": "sha1-Oz5UAXI5hC1tGcMBHEvS8AoA0VQ=", + "requires": { + "babel-plugin-transform-es2015-modules-commonjs": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1" + } + }, + "babel-plugin-transform-es2015-modules-commonjs": { + "version": "6.26.2", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.2.tgz", + "integrity": "sha512-CV9ROOHEdrjcwhIaJNBGMBCodN+1cfkwtM1SbUHmvyy35KGT7fohbpOxkE2uLz1o6odKK2Ck/tz47z+VqQfi9Q==", + "requires": { + "babel-plugin-transform-strict-mode": "^6.24.1", + "babel-runtime": "^6.26.0", + "babel-template": "^6.26.0", + "babel-types": "^6.26.0" + } + }, + "babel-plugin-transform-es2015-modules-systemjs": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz", + "integrity": "sha1-/4mhQrkRmpBhlfXxBuzzBdlAfSM=", + "requires": { + "babel-helper-hoist-variables": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1" + } + }, + "babel-plugin-transform-es2015-modules-umd": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz", + "integrity": "sha1-rJl+YoXNGO1hdq22B9YCNErThGg=", + "requires": { + "babel-plugin-transform-es2015-modules-amd": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1" + } + }, + "babel-plugin-transform-es2015-object-super": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz", + "integrity": "sha1-JM72muIcuDp/hgPa0CH1cusnj40=", + "requires": { + "babel-helper-replace-supers": "^6.24.1", + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-transform-es2015-parameters": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz", + "integrity": "sha1-V6w1GrScrxSpfNE7CfZv3wpiXys=", + "requires": { + "babel-helper-call-delegate": "^6.24.1", + "babel-helper-get-function-arity": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1", + "babel-traverse": "^6.24.1", + "babel-types": "^6.24.1" + } + }, + "babel-plugin-transform-es2015-shorthand-properties": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz", + "integrity": "sha1-JPh11nIch2YbvZmkYi5R8U3jiqA=", + "requires": { + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" + } + }, + "babel-plugin-transform-es2015-spread": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz", + "integrity": "sha1-1taKmfia7cRTbIGlQujdnxdG+NE=", + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-transform-es2015-sticky-regex": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz", + "integrity": "sha1-AMHNsaynERLN8M9hJsLta0V8zbw=", + "requires": { + "babel-helper-regex": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" + } + }, + "babel-plugin-transform-es2015-template-literals": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz", + "integrity": "sha1-qEs0UPfp+PH2g51taH2oS7EjbY0=", + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-transform-es2015-typeof-symbol": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz", + "integrity": "sha1-3sCfHN3/lLUqxz1QXITfWdzOs3I=", + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-transform-es2015-unicode-regex": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz", + "integrity": "sha1-04sS9C6nMj9yk4fxinxa4frrNek=", + "requires": { + "babel-helper-regex": "^6.24.1", + "babel-runtime": "^6.22.0", + "regexpu-core": "^2.0.0" + } + }, + "babel-plugin-transform-exponentiation-operator": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz", + "integrity": "sha1-KrDJx/MJj6SJB3cruBP+QejeOg4=", + "requires": { + "babel-helper-builder-binary-assignment-operator-visitor": "^6.24.1", + "babel-plugin-syntax-exponentiation-operator": "^6.8.0", + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-transform-regenerator": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz", + "integrity": "sha1-4HA2lvveJ/Cj78rPi03KL3s6jy8=", + "requires": { + "regenerator-transform": "^0.10.0" + } + }, + "babel-plugin-transform-strict-mode": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz", + "integrity": "sha1-1fr3qleKZbvlkc9e2uBKDGcCB1g=", + "requires": { + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" + } + }, + "babel-preset-env": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/babel-preset-env/-/babel-preset-env-1.7.0.tgz", + "integrity": "sha512-9OR2afuKDneX2/q2EurSftUYM0xGu4O2D9adAhVfADDhrYDaxXV0rBbevVYoY9n6nyX1PmQW/0jtpJvUNr9CHg==", + "requires": { + "babel-plugin-check-es2015-constants": "^6.22.0", + "babel-plugin-syntax-trailing-function-commas": "^6.22.0", + "babel-plugin-transform-async-to-generator": "^6.22.0", + "babel-plugin-transform-es2015-arrow-functions": "^6.22.0", + "babel-plugin-transform-es2015-block-scoped-functions": "^6.22.0", + "babel-plugin-transform-es2015-block-scoping": "^6.23.0", + "babel-plugin-transform-es2015-classes": "^6.23.0", + "babel-plugin-transform-es2015-computed-properties": "^6.22.0", + "babel-plugin-transform-es2015-destructuring": "^6.23.0", + "babel-plugin-transform-es2015-duplicate-keys": "^6.22.0", + "babel-plugin-transform-es2015-for-of": "^6.23.0", + "babel-plugin-transform-es2015-function-name": "^6.22.0", + "babel-plugin-transform-es2015-literals": "^6.22.0", + "babel-plugin-transform-es2015-modules-amd": "^6.22.0", + "babel-plugin-transform-es2015-modules-commonjs": "^6.23.0", + "babel-plugin-transform-es2015-modules-systemjs": "^6.23.0", + "babel-plugin-transform-es2015-modules-umd": "^6.23.0", + "babel-plugin-transform-es2015-object-super": "^6.22.0", + "babel-plugin-transform-es2015-parameters": "^6.23.0", + "babel-plugin-transform-es2015-shorthand-properties": "^6.22.0", + "babel-plugin-transform-es2015-spread": "^6.22.0", + "babel-plugin-transform-es2015-sticky-regex": "^6.22.0", + "babel-plugin-transform-es2015-template-literals": "^6.22.0", + "babel-plugin-transform-es2015-typeof-symbol": "^6.23.0", + "babel-plugin-transform-es2015-unicode-regex": "^6.22.0", + "babel-plugin-transform-exponentiation-operator": "^6.22.0", + "babel-plugin-transform-regenerator": "^6.22.0", + "browserslist": "^3.2.6", + "invariant": "^2.2.2", + "semver": "^5.3.0" + } + }, + "babel-register": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz", + "integrity": "sha1-btAhFz4vy0htestFxgCahW9kcHE=", + "requires": { + "babel-core": "^6.26.0", + "babel-runtime": "^6.26.0", + "core-js": "^2.5.0", + "home-or-tmp": "^2.0.0", + "lodash": "^4.17.4", + "mkdirp": "^0.5.1", + "source-map-support": "^0.4.15" + } + }, + "babel-runtime": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", + "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", + "requires": { + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" + } + }, + "babel-template": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", + "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", + "requires": { + "babel-runtime": "^6.26.0", + "babel-traverse": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "lodash": "^4.17.4" + } + }, + "babel-traverse": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", + "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", + "requires": { + "babel-code-frame": "^6.26.0", + "babel-messages": "^6.23.0", + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "debug": "^2.6.8", + "globals": "^9.18.0", + "invariant": "^2.2.2", + "lodash": "^4.17.4" + } + }, + "babel-types": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", + "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", + "requires": { + "babel-runtime": "^6.26.0", + "esutils": "^2.0.2", + "lodash": "^4.17.4", + "to-fast-properties": "^1.0.3" + } + }, + "babylon": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", + "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==" + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "requires": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "requires": { + "is-descriptor": "^1.0.0" + } + } + } + }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" + }, + "big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==" + }, + "binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "optional": true + }, + "bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "optional": true, + "requires": { + "file-uri-to-path": "1.0.0" + } + }, + "bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" + }, + "bn.js": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.0.tgz", + "integrity": "sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw==" + }, + "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": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=" + } + } + }, + "brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" + }, + "browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==" + }, + "browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "requires": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "browserify-cipher": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", + "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", + "requires": { + "browserify-aes": "^1.0.4", + "browserify-des": "^1.0.0", + "evp_bytestokey": "^1.0.0" + } + }, + "browserify-des": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", + "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", + "requires": { + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "browserify-rsa": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.0.tgz", + "integrity": "sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==", + "requires": { + "bn.js": "^5.0.0", + "randombytes": "^2.0.1" + } + }, + "browserify-sign": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.1.tgz", + "integrity": "sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg==", + "requires": { + "bn.js": "^5.1.1", + "browserify-rsa": "^4.0.1", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "elliptic": "^6.5.3", + "inherits": "^2.0.4", + "parse-asn1": "^5.1.5", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + } + } + }, + "browserify-zlib": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", + "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", + "requires": { + "pako": "~1.0.5" + } + }, + "browserslist": { + "version": "3.2.8", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-3.2.8.tgz", + "integrity": "sha512-WHVocJYavUwVgVViC0ORikPHQquXwVh939TaelZ4WDqpWgTX/FsGhl/+P4qBUAGcRvtOgDgC+xftNWWp2RUTAQ==", + "requires": { + "caniuse-lite": "^1.0.30000844", + "electron-to-chromium": "^1.3.47" + } + }, + "buffer": { + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", + "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + } + } + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" + }, + "buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=" + }, + "builtin-status-codes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", + "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=" + }, + "cacache": { + "version": "12.0.4", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.4.tgz", + "integrity": "sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ==", + "requires": { + "bluebird": "^3.5.5", + "chownr": "^1.1.1", + "figgy-pudding": "^3.5.1", + "glob": "^7.1.4", + "graceful-fs": "^4.1.15", + "infer-owner": "^1.0.3", + "lru-cache": "^5.1.1", + "mississippi": "^3.0.0", + "mkdirp": "^0.5.1", + "move-concurrently": "^1.0.1", + "promise-inflight": "^1.0.1", + "rimraf": "^2.6.3", + "ssri": "^6.0.1", + "unique-filename": "^1.1.1", + "y18n": "^4.0.0" + }, + "dependencies": { + "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" + } + } + } + }, + "cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "requires": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + } + }, + "caniuse-lite": { + "version": "1.0.30001233", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001233.tgz", + "integrity": "sha512-BmkbxLfStqiPA7IEzQpIk0UFZFf3A4E6fzjPJ6OR+bFC2L8ES9J8zGA/asoi47p8XDVkev+WJo2I2Nc8c/34Yg==" + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "chokidar": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.1.tgz", + "integrity": "sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw==", + "optional": true, + "requires": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "fsevents": "~2.3.1", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.5.0" + }, + "dependencies": { + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "optional": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "optional": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "optional": 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==", + "optional": true, + "requires": { + "is-number": "^7.0.0" + } + } + } + }, + "chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" + }, + "chrome-trace-event": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==" + }, + "cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "requires": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + } + }, + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" + } + } + }, + "clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "requires": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + } + }, + "collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "requires": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + } + }, + "colorette": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz", + "integrity": "sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==" + }, + "commander": { + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", + "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==" + }, + "commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=" + }, + "component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "console-browserify": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz", + "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==" + }, + "constants-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", + "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=" + }, + "convert-source-map": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", + "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", + "requires": { + "safe-buffer": "~5.1.1" + } + }, + "copy-concurrently": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz", + "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==", + "requires": { + "aproba": "^1.1.1", + "fs-write-stream-atomic": "^1.0.8", + "iferr": "^0.1.5", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.0" + } + }, + "copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=" + }, + "core-js": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", + "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==" + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "create-ecdh": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", + "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", + "requires": { + "bn.js": "^4.1.0", + "elliptic": "^6.5.3" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + } + } + }, + "create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "requires": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "requires": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "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" + } + }, + "crypto-browserify": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", + "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", + "requires": { + "browserify-cipher": "^1.0.0", + "browserify-sign": "^4.0.0", + "create-ecdh": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.0", + "diffie-hellman": "^5.0.0", + "inherits": "^2.0.1", + "pbkdf2": "^3.0.3", + "public-encrypt": "^4.0.0", + "randombytes": "^2.0.0", + "randomfill": "^1.0.3" + } + }, + "cyclist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz", + "integrity": "sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=" + }, + "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" + } + }, + "decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=" + }, + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + } + }, + "des.js": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz", + "integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==", + "requires": { + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "detect-indent": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", + "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=", + "requires": { + "repeating": "^2.0.0" + } + }, + "diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==" + }, + "diffie-hellman": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", + "requires": { + "bn.js": "^4.1.0", + "miller-rabin": "^4.0.0", + "randombytes": "^2.0.0" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + } + } + }, + "domain-browser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", + "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==" + }, + "duplexify": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", + "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", + "requires": { + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + } + }, + "electron-to-chromium": { + "version": "1.3.745", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.745.tgz", + "integrity": "sha512-ZZCx4CS3kYT3BREYiIXocDqlNPT56KfdTS1Ogo4yvxRriBqiEXCDTLIQZT/zNVtby91xTWMMxW2NBiXh8bpLHw==" + }, + "elliptic": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "requires": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + } + } + }, + "emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==" + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "requires": { + "once": "^1.4.0" + } + }, + "enhanced-resolve": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.5.0.tgz", + "integrity": "sha512-Nv9m36S/vxpsI+Hc4/ZGRs0n9mXqSWGGq49zxb/cJfPAQMbUtttJAlNPS4AQzaBdw/pKskw5bMbekT/Y7W/Wlg==", + "requires": { + "graceful-fs": "^4.1.2", + "memory-fs": "^0.5.0", + "tapable": "^1.0.0" + }, + "dependencies": { + "memory-fs": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.5.0.tgz", + "integrity": "sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==", + "requires": { + "errno": "^0.1.3", + "readable-stream": "^2.0.1" + } + } + } + }, + "envinfo": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz", + "integrity": "sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==" + }, + "errno": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", + "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", + "requires": { + "prr": "~1.0.1" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + }, + "eslint-scope": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", + "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "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" + }, + "dependencies": { + "estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==" + } + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==" + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" + }, + "events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==" + }, + "evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "requires": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "execa": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.0.tgz", + "integrity": "sha512-CkdUB7s2y6S+d4y+OM/+ZtQcJCiKUCth4cNImGMqrt2zEVtW2rfHGspQBE1GDo6LjeNIQmTPKXqTCKjqFKyu3A==", + "requires": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + } + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "requires": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=" + }, + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" + } + } + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=" + } + } + }, + "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-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==" + }, + "fastest-levenshtein": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz", + "integrity": "sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow==" + }, + "figgy-pudding": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.2.tgz", + "integrity": "sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw==" + }, + "file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "optional": true + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=" + } + } + }, + "find-cache-dir": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-1.0.0.tgz", + "integrity": "sha1-kojj6ePMN0hxfTnq3hfPcfww7m8=", + "requires": { + "commondir": "^1.0.1", + "make-dir": "^1.0.0", + "pkg-dir": "^2.0.0" + } + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "requires": { + "locate-path": "^2.0.0" + } + }, + "flush-write-stream": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", + "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==", + "requires": { + "inherits": "^2.0.3", + "readable-stream": "^2.3.6" + } + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=" + }, + "formatio": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/formatio/-/formatio-1.1.1.tgz", + "integrity": "sha1-XtPM1jZVEJc4NGXZlhmRAOhhYek=", + "requires": { + "samsam": "~1.1" + }, + "dependencies": { + "samsam": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/samsam/-/samsam-1.1.3.tgz", + "integrity": "sha1-n1CHQZtNCR8jJXHn+lLpCw9VJiE=" + } + } + }, + "fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "requires": { + "map-cache": "^0.2.2" + } + }, + "from2": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", + "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" + } + }, + "fs-write-stream-atomic": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz", + "integrity": "sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=", + "requires": { + "graceful-fs": "^4.1.2", + "iferr": "^0.1.5", + "imurmurhash": "^0.1.4", + "readable-stream": "1 || 2" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "optional": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==" + }, + "get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=" + }, + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "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==", + "optional": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "globals": { + "version": "9.18.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", + "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==" + }, + "graceful-fs": { + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", + "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==" + }, + "growl": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==" + }, + "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-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + }, + "has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "requires": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + } + }, + "has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "requires": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "dependencies": { + "kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "hash-base": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", + "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", + "requires": { + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + } + } + }, + "hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "he": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", + "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=" + }, + "hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", + "requires": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "home-or-tmp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz", + "integrity": "sha1-42w/LSyufXRqhX440Y1fMqeILbg=", + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.1" + } + }, + "https-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", + "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=" + }, + "human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==" + }, + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" + }, + "iferr": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz", + "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=" + }, + "import-local": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.0.2.tgz", + "integrity": "sha512-vjL3+w0oulAVZ0hBHnxa/Nm5TAurf9YLQJDhqRZyqb+VKGOB6LU8t9H1Nr5CIo16vh9XfJTOoHwU0B71S557gA==", + "requires": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "dependencies": { + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "requires": { + "p-locate": "^4.1.0" + } + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "requires": { + "p-limit": "^2.2.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" + }, + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "requires": { + "find-up": "^4.0.0" + } + } + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" + }, + "infer-owner": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==" + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "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==" + }, + "interpret": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz", + "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==" + }, + "invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "requires": { + "loose-envify": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "optional": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + }, + "is-core-module": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.4.0.tgz", + "integrity": "sha512-6A2fkfq1rfeQZjxrZJGerpLCTHRNEBiSgnu0+obeJpEPZRUooHgsizvzv0ZjJwOz3iWIHdJtVWJ/tmPr3D21/A==", + "requires": { + "has": "^1.0.3" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "requires": { + "is-plain-object": "^2.0.4" + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "optional": true + }, + "is-finite": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.1.0.tgz", + "integrity": "sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w==" + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "optional": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "requires": { + "isobject": "^3.0.1" + } + }, + "is-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", + "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==" + }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==" + }, + "is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=" + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" + }, + "jade": { + "version": "0.26.3", + "resolved": "https://registry.npmjs.org/jade/-/jade-0.26.3.tgz", + "integrity": "sha1-jxDXl32NefL2/4YqgbBRPMslaGw=", + "requires": { + "commander": "0.6.1", + "mkdirp": "0.3.0" + }, + "dependencies": { + "commander": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-0.6.1.tgz", + "integrity": "sha1-+mihT2qUXVTbvlDYzbMyDp47GgY=" + }, + "mkdirp": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.0.tgz", + "integrity": "sha1-G79asbqCevI1dRQ0kEJkVfSB/h4=" + } + } + }, + "js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=" + }, + "jsesc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", + "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=" + }, + "json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==" + }, + "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==" + }, + "json5": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", + "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=" + }, + "just-extend": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.2.1.tgz", + "integrity": "sha512-g3UB796vUFIY90VIv/WX3L2c8CS2MdWUww3CNrYmqza1Fg0DURc2K/O4YrnklBdQarSJ/y8JnJYDGc+1iumQjg==" + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" + }, + "loader-runner": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.4.0.tgz", + "integrity": "sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==" + }, + "loader-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", + "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + }, + "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" + } + } + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=" + }, + "lolex": { + "version": "2.7.5", + "resolved": "https://registry.npmjs.org/lolex/-/lolex-2.7.5.tgz", + "integrity": "sha512-l9x0+1offnKKIzYVjyXU2SiwhXDLekRzKyhnbyldPHvC7BvLPVpdNUNR2KeMAiCN2D/kLNttZgQD5WjSxuBx3Q==" + }, + "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": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "requires": { + "yallist": "^3.0.2" + } + }, + "make-dir": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", + "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", + "requires": { + "pify": "^3.0.0" + } + }, + "map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=" + }, + "map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "requires": { + "object-visit": "^1.0.0" + } + }, + "md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "memory-fs": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", + "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=", + "requires": { + "errno": "^0.1.3", + "readable-stream": "^2.0.1" + } + }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "miller-rabin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", + "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", + "requires": { + "bn.js": "^4.0.0", + "brorand": "^1.0.1" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + } + } + }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==" + }, + "minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" + }, + "minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=" + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + }, + "mississippi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz", + "integrity": "sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==", + "requires": { + "concat-stream": "^1.5.0", + "duplexify": "^3.4.2", + "end-of-stream": "^1.1.0", + "flush-write-stream": "^1.0.0", + "from2": "^2.1.0", + "parallel-transform": "^1.1.0", + "pump": "^3.0.0", + "pumpify": "^1.3.3", + "stream-each": "^1.1.0", + "through2": "^2.0.0" + } + }, + "mixin-deep": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", + "requires": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + } + }, + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "requires": { + "minimist": "^1.2.5" + } + }, + "mocha": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-5.2.0.tgz", + "integrity": "sha512-2IUgKDhc3J7Uug+FxMXuqIyYzH7gJjXECKe/w43IGgQHTSj3InJi+yAA7T24L9bQMRKiUEHxEX37G5JpVUGLcQ==", + "requires": { + "browser-stdout": "1.3.1", + "commander": "2.15.1", + "debug": "3.1.0", + "diff": "3.5.0", + "escape-string-regexp": "1.0.5", + "glob": "7.1.2", + "growl": "1.10.5", + "he": "1.1.1", + "minimatch": "3.0.4", + "mkdirp": "0.5.1", + "supports-color": "5.4.0" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "requires": { + "minimist": "0.0.8" + } + }, + "supports-color": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", + "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "move-concurrently": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", + "integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=", + "requires": { + "aproba": "^1.1.1", + "copy-concurrently": "^1.0.0", + "fs-write-stream-atomic": "^1.0.8", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.3" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "nan": { + "version": "2.14.2", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.2.tgz", + "integrity": "sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==", + "optional": true + }, + "nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + } + }, + "neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" + }, + "nise": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/nise/-/nise-1.5.3.tgz", + "integrity": "sha512-Ymbac/94xeIrMf59REBPOv0thr+CJVFMhrlAkW/gjCIE58BGQdCj0x7KRCb3yz+Ga2Rz3E9XXSvUyyxqqhjQAQ==", + "requires": { + "@sinonjs/formatio": "^3.2.1", + "@sinonjs/text-encoding": "^0.7.1", + "just-extend": "^4.0.2", + "lolex": "^5.0.1", + "path-to-regexp": "^1.7.0" + }, + "dependencies": { + "@sinonjs/formatio": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-3.2.2.tgz", + "integrity": "sha512-B8SEsgd8gArBLMD6zpRw3juQ2FVSsmdd7qlevyDqzS9WTCtvF55/gAL+h6gue8ZvPYcdiPdvueM/qm//9XzyTQ==", + "requires": { + "@sinonjs/commons": "^1", + "@sinonjs/samsam": "^3.1.0" + } + }, + "lolex": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/lolex/-/lolex-5.1.2.tgz", + "integrity": "sha512-h4hmjAvHTmd+25JSwrtTIuwbKdwg5NzZVRMLn9saij4SZaepCrTCxPr35H/3bjwfMJtN+t3CX8672UIkglz28A==", + "requires": { + "@sinonjs/commons": "^1.7.0" + } + } + } + }, + "node-libs-browser": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.1.tgz", + "integrity": "sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==", + "requires": { + "assert": "^1.1.1", + "browserify-zlib": "^0.2.0", + "buffer": "^4.3.0", + "console-browserify": "^1.1.0", + "constants-browserify": "^1.0.0", + "crypto-browserify": "^3.11.0", + "domain-browser": "^1.1.1", + "events": "^3.0.0", + "https-browserify": "^1.0.0", + "os-browserify": "^0.3.0", + "path-browserify": "0.0.1", + "process": "^0.11.10", + "punycode": "^1.2.4", + "querystring-es3": "^0.2.0", + "readable-stream": "^2.3.3", + "stream-browserify": "^2.0.1", + "stream-http": "^2.7.2", + "string_decoder": "^1.0.0", + "timers-browserify": "^2.0.4", + "tty-browserify": "0.0.0", + "url": "^0.11.0", + "util": "^0.11.0", + "vm-browserify": "^1.0.1" + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "optional": true + }, + "npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "requires": { + "path-key": "^3.0.0" + } + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + }, + "object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "requires": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "requires": { + "kind-of": "^3.0.2" + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "requires": { + "kind-of": "^3.0.2" + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" + } + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "requires": { + "isobject": "^3.0.0" + } + }, + "object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "requires": { + "isobject": "^3.0.1" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, + "onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "os-browserify": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", + "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=" + }, + "os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=" + }, + "pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" + }, + "parallel-transform": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.2.0.tgz", + "integrity": "sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg==", + "requires": { + "cyclist": "^1.0.1", + "inherits": "^2.0.3", + "readable-stream": "^2.1.5" + } + }, + "parse-asn1": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz", + "integrity": "sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==", + "requires": { + "asn1.js": "^5.2.0", + "browserify-aes": "^1.0.0", + "evp_bytestokey": "^1.0.0", + "pbkdf2": "^3.0.3", + "safe-buffer": "^5.1.1" + } + }, + "pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=" + }, + "path-browserify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz", + "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==" + }, + "path-dirname": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", + "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", + "optional": true + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, + "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-to-regexp": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", + "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", + "requires": { + "isarray": "0.0.1" + } + }, + "pbkdf2": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", + "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", + "requires": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "picomatch": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", + "optional": true + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" + }, + "pkg-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", + "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", + "requires": { + "find-up": "^2.1.0" + } + }, + "posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=" + }, + "private": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", + "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==" + }, + "process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=" + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=" + }, + "promises-aplus-tests": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/promises-aplus-tests/-/promises-aplus-tests-2.1.2.tgz", + "integrity": "sha1-drfFY4locghhlpz7zYeVr9J0iFw=", + "requires": { + "mocha": "^2.5.3", + "sinon": "^1.10.3", + "underscore": "~1.8.3" + }, + "dependencies": { + "commander": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.3.0.tgz", + "integrity": "sha1-/UMOiJgy7DU7ms0d4hfBHLPu+HM=" + }, + "debug": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", + "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", + "requires": { + "ms": "0.7.1" + } + }, + "diff": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-1.4.0.tgz", + "integrity": "sha1-fyjS657nsVqX79ic5j3P2qPMur8=" + }, + "escape-string-regexp": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.2.tgz", + "integrity": "sha1-Tbwv5nTnGUnK8/smlc5/LcHZqNE=" + }, + "glob": { + "version": "3.2.11", + "resolved": "https://registry.npmjs.org/glob/-/glob-3.2.11.tgz", + "integrity": "sha1-Spc/Y1uRkPcV0QmH1cAP0oFevj0=", + "requires": { + "inherits": "2", + "minimatch": "0.3" + } + }, + "growl": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.9.2.tgz", + "integrity": "sha1-Dqd0NxXbjY3ixe3hd14bRayFwC8=" + }, + "lolex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/lolex/-/lolex-1.3.2.tgz", + "integrity": "sha1-fD2mL/yzDw9agKJWbKJORdigHzE=" + }, + "lru-cache": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", + "integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI=" + }, + "minimatch": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.3.0.tgz", + "integrity": "sha1-J12O2qxPG7MyZHIInnlJyDlGmd0=", + "requires": { + "lru-cache": "2", + "sigmund": "~1.0.0" + } + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "requires": { + "minimist": "0.0.8" + } + }, + "mocha": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-2.5.3.tgz", + "integrity": "sha1-FhvlvetJZ3HrmzV0UFC2IrWu/Fg=", + "requires": { + "commander": "2.3.0", + "debug": "2.2.0", + "diff": "1.4.0", + "escape-string-regexp": "1.0.2", + "glob": "3.2.11", + "growl": "1.9.2", + "jade": "0.26.3", + "mkdirp": "0.5.1", + "supports-color": "1.2.0", + "to-iso-string": "0.0.2" + } + }, + "ms": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", + "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=" + }, + "samsam": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/samsam/-/samsam-1.1.2.tgz", + "integrity": "sha1-vsEf3IOp/aBjQBIQ5AF2wwJNFWc=" + }, + "sinon": { + "version": "1.17.7", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-1.17.7.tgz", + "integrity": "sha1-RUKk9JugxFwF6y6d2dID4rjv4L8=", + "requires": { + "formatio": "1.1.1", + "lolex": "1.3.2", + "samsam": "1.1.2", + "util": ">=0.10.3 <1" + } + }, + "supports-color": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-1.2.0.tgz", + "integrity": "sha1-/x7R5hFp0Gs88tWI4YixjYhH4X4=" + } + } + }, + "prr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=" + }, + "public-encrypt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", + "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", + "requires": { + "bn.js": "^4.1.0", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "parse-asn1": "^5.0.0", + "randombytes": "^2.0.1", + "safe-buffer": "^5.1.2" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + } + } + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "pumpify": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", + "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", + "requires": { + "duplexify": "^3.6.0", + "inherits": "^2.0.3", + "pump": "^2.0.0" + }, + "dependencies": { + "pump": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", + "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + } + } + }, + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" + }, + "querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=" + }, + "querystring-es3": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", + "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=" + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "randomfill": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", + "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", + "requires": { + "randombytes": "^2.0.5", + "safe-buffer": "^5.1.0" + } + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "readdirp": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz", + "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==", + "optional": true, + "requires": { + "picomatch": "^2.2.1" + } + }, + "rechoir": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.0.tgz", + "integrity": "sha512-ADsDEH2bvbjltXEP+hTIAmeFekTFK0V2BTxMkok6qILyAJEXV0AFfoWcAq4yfll5VdIMd/RVXq0lR+wQi5ZU3Q==", + "requires": { + "resolve": "^1.9.0" + } + }, + "regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==" + }, + "regenerator-runtime": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" + }, + "regenerator-transform": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.10.1.tgz", + "integrity": "sha512-PJepbvDbuK1xgIgnau7Y90cwaAmO/LCLMI2mPvaXq2heGMR3aWW5/BQvYrhJ8jgmQjXewXvBjzfqKcVOmhjZ6Q==", + "requires": { + "babel-runtime": "^6.18.0", + "babel-types": "^6.19.0", + "private": "^0.1.6" + } + }, + "regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "requires": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + } + }, + "regexpu-core": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-2.0.0.tgz", + "integrity": "sha1-SdA4g3uNz4v6W5pCE5k45uoq4kA=", + "requires": { + "regenerate": "^1.2.1", + "regjsgen": "^0.2.0", + "regjsparser": "^0.1.4" + } + }, + "regjsgen": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz", + "integrity": "sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc=" + }, + "regjsparser": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz", + "integrity": "sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw=", + "requires": { + "jsesc": "~0.5.0" + }, + "dependencies": { + "jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=" + } + } + }, + "remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", + "optional": true + }, + "repeat-element": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz", + "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==" + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=" + }, + "repeating": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", + "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", + "requires": { + "is-finite": "^1.0.0" + } + }, + "resolve": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", + "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", + "requires": { + "is-core-module": "^2.2.0", + "path-parse": "^1.0.6" + } + }, + "resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "requires": { + "resolve-from": "^5.0.0" + } + }, + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==" + }, + "resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=" + }, + "ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==" + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "requires": { + "glob": "^7.1.3" + }, + "dependencies": { + "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" + } + } + } + }, + "ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "run-queue": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz", + "integrity": "sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=", + "requires": { + "aproba": "^1.1.1" + } + }, + "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==" + }, + "safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "requires": { + "ret": "~0.1.10" + } + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "samsam": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/samsam/-/samsam-1.3.0.tgz", + "integrity": "sha512-1HwIYD/8UlOtFS3QO3w7ey+SdSDFE4HRNLZoZRYVQefrOY3l17epswImeB1ijgJFQJodIaHcwkp3r/myBjFVbg==" + }, + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + }, + "serialize-javascript": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", + "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", + "requires": { + "randombytes": "^2.1.0" + } + }, + "set-value": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=" + } + } + }, + "setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=" + }, + "sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "requires": { + "kind-of": "^6.0.2" + } + }, + "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==" + }, + "sigmund": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", + "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=" + }, + "signal-exit": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", + "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==" + }, + "sinon": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-4.5.0.tgz", + "integrity": "sha512-trdx+mB0VBBgoYucy6a9L7/jfQOmvGeaKZT4OOJ+lPAtI8623xyGr8wLiE4eojzBS8G9yXbhx42GHUOVLr4X2w==", + "requires": { + "@sinonjs/formatio": "^2.0.0", + "diff": "^3.1.0", + "lodash.get": "^4.4.2", + "lolex": "^2.2.0", + "nise": "^1.2.0", + "supports-color": "^5.1.0", + "type-detect": "^4.0.5" + }, + "dependencies": { + "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" + } + } + } + }, + "slash": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", + "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=" + }, + "snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "requires": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=" + }, + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" + } + } + }, + "snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "requires": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "requires": { + "is-descriptor": "^1.0.0" + } + } + } + }, + "snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "requires": { + "kind-of": "^3.2.0" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "source-list-map": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", + "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==" + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + }, + "source-map-resolve": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", + "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", + "requires": { + "atob": "^2.1.2", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "source-map-support": { + "version": "0.4.18", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", + "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", + "requires": { + "source-map": "^0.5.6" + } + }, + "source-map-url": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz", + "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==" + }, + "split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "requires": { + "extend-shallow": "^3.0.0" + } + }, + "ssri": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.2.tgz", + "integrity": "sha512-cepbSq/neFK7xB6A50KHN0xHDotYzq58wWCa5LeWqnPrHG8GzfEjO/4O8kpmcGW+oaxkvhEJCWgbgNk4/ZV93Q==", + "requires": { + "figgy-pudding": "^3.5.1" + } + }, + "static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "requires": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + } + }, + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" + } + } + }, + "stream-browserify": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz", + "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==", + "requires": { + "inherits": "~2.0.1", + "readable-stream": "^2.0.2" + } + }, + "stream-each": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.3.tgz", + "integrity": "sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==", + "requires": { + "end-of-stream": "^1.1.0", + "stream-shift": "^1.0.0" + } + }, + "stream-http": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz", + "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==", + "requires": { + "builtin-status-codes": "^3.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.3.6", + "to-arraybuffer": "^1.0.0", + "xtend": "^4.0.0" + } + }, + "stream-shift": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", + "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==" + }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "requires": { + "safe-buffer": "~5.2.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + } + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==" + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" + }, + "tapable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", + "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==" + }, + "terser": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-4.8.0.tgz", + "integrity": "sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw==", + "requires": { + "commander": "^2.20.0", + "source-map": "~0.6.1", + "source-map-support": "~0.5.12" + }, + "dependencies": { + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, + "source-map-support": { + "version": "0.5.19", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", + "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + } + } + }, + "terser-webpack-plugin": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.5.tgz", + "integrity": "sha512-04Rfe496lN8EYruwi6oPQkG0vo8C+HT49X687FZnpPF0qMAIHONI6HEXYPKDOE8e5HjXTyKfqRd/agHtH0kOtw==", + "requires": { + "cacache": "^12.0.2", + "find-cache-dir": "^2.1.0", + "is-wsl": "^1.1.0", + "schema-utils": "^1.0.0", + "serialize-javascript": "^4.0.0", + "source-map": "^0.6.1", + "terser": "^4.1.2", + "webpack-sources": "^1.4.0", + "worker-farm": "^1.7.0" + }, + "dependencies": { + "find-cache-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", + "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", + "requires": { + "commondir": "^1.0.1", + "make-dir": "^2.0.0", + "pkg-dir": "^3.0.0" + } + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "requires": { + "locate-path": "^3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "requires": { + "pify": "^4.0.1", + "semver": "^5.6.0" + } + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==" + }, + "pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "requires": { + "find-up": "^3.0.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "requires": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "timers-browserify": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.12.tgz", + "integrity": "sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==", + "requires": { + "setimmediate": "^1.0.4" + } + }, + "to-arraybuffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", + "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=" + }, + "to-fast-properties": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", + "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=" + }, + "to-iso-string": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/to-iso-string/-/to-iso-string-0.0.2.tgz", + "integrity": "sha1-TcGeZk38y+Jb2NtQiwDG2hWCVdE=" + }, + "to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "requires": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + }, + "trim-right": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", + "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=" + }, + "tty-browserify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", + "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=" + }, + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==" + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" + }, + "underscore": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz", + "integrity": "sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI=" + }, + "union-value": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "requires": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=" + } + } + }, + "unique-filename": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", + "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", + "requires": { + "unique-slug": "^2.0.0" + } + }, + "unique-slug": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", + "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", + "requires": { + "imurmurhash": "^0.1.4" + } + }, + "unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "requires": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "dependencies": { + "has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "requires": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "dependencies": { + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "requires": { + "isarray": "1.0.0" + } + } + } + }, + "has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=" + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + } + } + }, + "upath": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", + "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", + "optional": true + }, + "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" + }, + "dependencies": { + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + } + } + }, + "urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=" + }, + "url": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", + "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", + "requires": { + "punycode": "1.3.2", + "querystring": "0.2.0" + }, + "dependencies": { + "punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=" + } + } + }, + "use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==" + }, + "util": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz", + "integrity": "sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==", + "requires": { + "inherits": "2.0.3" + }, + "dependencies": { + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + } + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "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==" + }, + "vm-browserify": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", + "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==" + }, + "watchpack": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.7.5.tgz", + "integrity": "sha512-9P3MWk6SrKjHsGkLT2KHXdQ/9SNkyoJbabxnKOoJepsvJjJG8uYTR3yTPxPQvNDI3w4Nz1xnE0TLHK4RIVe/MQ==", + "requires": { + "chokidar": "^3.4.1", + "graceful-fs": "^4.1.2", + "neo-async": "^2.5.0", + "watchpack-chokidar2": "^2.0.1" + } + }, + "watchpack-chokidar2": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/watchpack-chokidar2/-/watchpack-chokidar2-2.0.1.tgz", + "integrity": "sha512-nCFfBIPKr5Sh61s4LPpy1Wtfi0HE8isJ3d2Yb5/Ppw2P2B/3eVSEBjKfN0fmHJSK14+31KwMKmcrzs2GM4P0Ww==", + "optional": true, + "requires": { + "chokidar": "^2.1.8" + }, + "dependencies": { + "anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "optional": true, + "requires": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + }, + "dependencies": { + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "optional": true, + "requires": { + "remove-trailing-separator": "^1.0.1" + } + } + } + }, + "binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", + "optional": true + }, + "chokidar": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", + "optional": true, + "requires": { + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "fsevents": "^1.2.7", + "glob-parent": "^3.1.0", + "inherits": "^2.0.3", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "normalize-path": "^3.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.2.1", + "upath": "^1.1.1" + } + }, + "fsevents": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", + "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", + "optional": true, + "requires": { + "bindings": "^1.5.0", + "nan": "^2.12.1" + } + }, + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "optional": true, + "requires": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + }, + "dependencies": { + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "optional": true, + "requires": { + "is-extglob": "^2.1.0" + } + } + } + }, + "is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "optional": true, + "requires": { + "binary-extensions": "^1.0.0" + } + }, + "readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "optional": true, + "requires": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + } + } + } + }, + "webpack": { + "version": "4.46.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.46.0.tgz", + "integrity": "sha512-6jJuJjg8znb/xRItk7bkT0+Q7AHCYjjFnvKIWQPkNIOyRqoCGvkOs0ipeQzrqz4l5FtN5ZI/ukEHroeX/o1/5Q==", + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-module-context": "1.9.0", + "@webassemblyjs/wasm-edit": "1.9.0", + "@webassemblyjs/wasm-parser": "1.9.0", + "acorn": "^6.4.1", + "ajv": "^6.10.2", + "ajv-keywords": "^3.4.1", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^4.5.0", + "eslint-scope": "^4.0.3", + "json-parse-better-errors": "^1.0.2", + "loader-runner": "^2.4.0", + "loader-utils": "^1.2.3", + "memory-fs": "^0.4.1", + "micromatch": "^3.1.10", + "mkdirp": "^0.5.3", + "neo-async": "^2.6.1", + "node-libs-browser": "^2.2.1", + "schema-utils": "^1.0.0", + "tapable": "^1.1.3", + "terser-webpack-plugin": "^1.4.3", + "watchpack": "^1.7.4", + "webpack-sources": "^1.4.1" + } + }, + "webpack-cli": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.7.0.tgz", + "integrity": "sha512-7bKr9182/sGfjFm+xdZSwgQuFjgEcy0iCTIBxRUeteJ2Kr8/Wz0qNJX+jw60LU36jApt4nmMkep6+W5AKhok6g==", + "requires": { + "@discoveryjs/json-ext": "^0.5.0", + "@webpack-cli/configtest": "^1.0.3", + "@webpack-cli/info": "^1.2.4", + "@webpack-cli/serve": "^1.4.0", + "colorette": "^1.2.1", + "commander": "^7.0.0", + "execa": "^5.0.0", + "fastest-levenshtein": "^1.0.12", + "import-local": "^3.0.2", + "interpret": "^2.2.0", + "rechoir": "^0.7.0", + "v8-compile-cache": "^2.2.0", + "webpack-merge": "^5.7.3" + }, + "dependencies": { + "commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==" + } + } + }, + "webpack-merge": { + "version": "5.7.3", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.7.3.tgz", + "integrity": "sha512-6/JUQv0ELQ1igjGDzHkXbVDRxkfA57Zw7PfiupdLFJYrgFqY5ZP8xxbpp2lU3EPwYx89ht5Z/aDkD40hFCm5AA==", + "requires": { + "clone-deep": "^4.0.1", + "wildcard": "^2.0.0" + } + }, + "webpack-sources": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz", + "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", + "requires": { + "source-list-map": "^2.0.0", + "source-map": "~0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "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" + } + }, + "wildcard": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz", + "integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==" + }, + "worker-farm": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.7.0.tgz", + "integrity": "sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw==", + "requires": { + "errno": "~0.1.7" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" + }, + "y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==" + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + } + } +} diff --git a/Tests/JS-A+/package.json b/Tests/A+/JavaScript/package.json similarity index 86% rename from Tests/JS-A+/package.json rename to Tests/A+/JavaScript/package.json index 6d2b0e6e5..8063140a9 100644 --- a/Tests/JS-A+/package.json +++ b/Tests/A+/JavaScript/package.json @@ -7,11 +7,11 @@ "babel-core": "^6.26.0", "babel-loader": "^7.1.3", "babel-preset-env": "^1.6.1", - "lodash": "^4.17.5", + "lodash": "^4.17.21", "mocha": "^5.0.1", "promises-aplus-tests": "^2.1.2", "sinon": "^4.4.2", "webpack": "^4.0.1", - "webpack-cli": "^2.0.9" + "webpack-cli": "^4.7.0" } } diff --git a/Tests/JS-A+/webpack.config.js b/Tests/A+/JavaScript/webpack.config.js similarity index 100% rename from Tests/JS-A+/webpack.config.js rename to Tests/A+/JavaScript/webpack.config.js diff --git a/Tests/A+/0.0.0.swift b/Tests/A+/Swift/0.0.0.swift similarity index 95% rename from Tests/A+/0.0.0.swift rename to Tests/A+/Swift/0.0.0.swift index 5962caa0a..8db18017c 100644 --- a/Tests/A+/0.0.0.swift +++ b/Tests/A+/Swift/0.0.0.swift @@ -26,7 +26,7 @@ extension XCTestCase { let (pending, seal) = Promise.pending() do { - try body((pending, seal.fulfill_, seal.reject), expectation) + try body((pending, seal.fulfill, seal.reject), expectation) waitForExpectations(timeout: timeout) { err in if let _ = err { XCTFail("wait failed: \(description)", file: file, line: line) @@ -143,9 +143,9 @@ extension Promise { func test(onFulfilled: @escaping () -> Void, onRejected: @escaping () -> Void) { tap { result in switch result { - case .fulfilled: + case .success: onFulfilled() - case .rejected: + case .failure: onRejected() } }.silenceWarning() @@ -167,7 +167,15 @@ import func Glibc.random func arc4random() -> UInt32 { return UInt32(random()) } +#endif + +#if os(Windows) +func arc4random() -> UInt32 { + return UInt32.random(in: UInt32.min...UInt32.max) +} +#endif +#if os(Linux) || os(Windows) extension XCTestExpectation { func fulfill() { fulfill(#file, line: #line) @@ -176,10 +184,7 @@ extension XCTestExpectation { extension XCTestCase { func wait(for: [XCTestExpectation], timeout: TimeInterval, file: StaticString = #file, line: UInt = #line) { - #if !(swift(>=4.0) && !swift(>=4.1)) - let line = Int(line) - #endif - waitForExpectations(timeout: timeout, file: file, line: line) + waitForExpectations(timeout: timeout, file: file, line: Int(line)) } } #endif diff --git a/Tests/A+/2.1.2.swift b/Tests/A+/Swift/2.1.2.swift similarity index 100% rename from Tests/A+/2.1.2.swift rename to Tests/A+/Swift/2.1.2.swift diff --git a/Tests/A+/2.1.3.swift b/Tests/A+/Swift/2.1.3.swift similarity index 100% rename from Tests/A+/2.1.3.swift rename to Tests/A+/Swift/2.1.3.swift diff --git a/Tests/A+/2.2.2.swift b/Tests/A+/Swift/2.2.2.swift similarity index 100% rename from Tests/A+/2.2.2.swift rename to Tests/A+/Swift/2.2.2.swift diff --git a/Tests/A+/2.2.3.swift b/Tests/A+/Swift/2.2.3.swift similarity index 100% rename from Tests/A+/2.2.3.swift rename to Tests/A+/Swift/2.2.3.swift diff --git a/Tests/A+/2.2.4.swift b/Tests/A+/Swift/2.2.4.swift similarity index 100% rename from Tests/A+/2.2.4.swift rename to Tests/A+/Swift/2.2.4.swift diff --git a/Tests/A+/2.2.6.swift b/Tests/A+/Swift/2.2.6.swift similarity index 99% rename from Tests/A+/2.2.6.swift rename to Tests/A+/Swift/2.2.6.swift index 95cfe7b23..8b938e17f 100644 --- a/Tests/A+/2.2.6.swift +++ b/Tests/A+/Swift/2.2.6.swift @@ -6,7 +6,7 @@ class Test226: XCTestCase { describe("2.2.6: `then` may be called multiple times on the same promise.") { describe("2.2.6.1: If/when `promise` is fulfilled, all respective `onFulfilled` callbacks must execute in the order of their originating calls to `then`.") { describe("multiple boring fulfillment handlers") { - testFulfilled(withExpectationCount: 4) { promise, exes, sentinel -> Void in + testFulfilled(withExpectationCount: 4) { promise, exes, sentinel -> () in var orderValidator = 0 promise.done { XCTAssertEqual($0, sentinel) diff --git a/Tests/A+/2.2.7.swift b/Tests/A+/Swift/2.2.7.swift similarity index 100% rename from Tests/A+/2.2.7.swift rename to Tests/A+/Swift/2.2.7.swift diff --git a/Tests/A+/2.3.1.swift b/Tests/A+/Swift/2.3.1.swift similarity index 100% rename from Tests/A+/2.3.1.swift rename to Tests/A+/Swift/2.3.1.swift diff --git a/Tests/A+/2.3.2.swift b/Tests/A+/Swift/2.3.2.swift similarity index 100% rename from Tests/A+/2.3.2.swift rename to Tests/A+/Swift/2.3.2.swift diff --git a/Tests/A+/2.3.4.swift b/Tests/A+/Swift/2.3.4.swift similarity index 100% rename from Tests/A+/2.3.4.swift rename to Tests/A+/Swift/2.3.4.swift diff --git a/Tests/A+/XCTestManifests.swift b/Tests/A+/XCTestManifests.swift deleted file mode 100644 index 5f78de59e..000000000 --- a/Tests/A+/XCTestManifests.swift +++ /dev/null @@ -1,108 +0,0 @@ -#if !canImport(ObjectiveC) -import XCTest - -extension Test212 { - // DO NOT MODIFY: This is autogenerated, use: - // `swift test --generate-linuxmain` - // to regenerate. - static let __allTests__Test212 = [ - ("test", test), - ] -} - -extension Test213 { - // DO NOT MODIFY: This is autogenerated, use: - // `swift test --generate-linuxmain` - // to regenerate. - static let __allTests__Test213 = [ - ("test", test), - ] -} - -extension Test222 { - // DO NOT MODIFY: This is autogenerated, use: - // `swift test --generate-linuxmain` - // to regenerate. - static let __allTests__Test222 = [ - ("test", test), - ] -} - -extension Test223 { - // DO NOT MODIFY: This is autogenerated, use: - // `swift test --generate-linuxmain` - // to regenerate. - static let __allTests__Test223 = [ - ("test", test), - ] -} - -extension Test224 { - // DO NOT MODIFY: This is autogenerated, use: - // `swift test --generate-linuxmain` - // to regenerate. - static let __allTests__Test224 = [ - ("test", test), - ] -} - -extension Test226 { - // DO NOT MODIFY: This is autogenerated, use: - // `swift test --generate-linuxmain` - // to regenerate. - static let __allTests__Test226 = [ - ("test", test), - ] -} - -extension Test227 { - // DO NOT MODIFY: This is autogenerated, use: - // `swift test --generate-linuxmain` - // to regenerate. - static let __allTests__Test227 = [ - ("test", test), - ] -} - -extension Test231 { - // DO NOT MODIFY: This is autogenerated, use: - // `swift test --generate-linuxmain` - // to regenerate. - static let __allTests__Test231 = [ - ("test", test), - ] -} - -extension Test232 { - // DO NOT MODIFY: This is autogenerated, use: - // `swift test --generate-linuxmain` - // to regenerate. - static let __allTests__Test232 = [ - ("test", test), - ] -} - -extension Test234 { - // DO NOT MODIFY: This is autogenerated, use: - // `swift test --generate-linuxmain` - // to regenerate. - static let __allTests__Test234 = [ - ("test", test), - ] -} - -public func __allTests() -> [XCTestCaseEntry] { - return [ - testCase(Test212.__allTests__Test212), - testCase(Test213.__allTests__Test213), - testCase(Test222.__allTests__Test222), - testCase(Test223.__allTests__Test223), - testCase(Test224.__allTests__Test224), - testCase(Test226.__allTests__Test226), - testCase(Test227.__allTests__Test227), - testCase(Test231.__allTests__Test231), - testCase(Test232.__allTests__Test232), - testCase(Test234.__allTests__Test234), - ] -} -#endif diff --git a/Tests/Bridging/BridgingTests.m b/Tests/Bridging/BridgingTests.m deleted file mode 100644 index 928c0481a..000000000 --- a/Tests/Bridging/BridgingTests.m +++ /dev/null @@ -1,34 +0,0 @@ -@import PromiseKit; -@import XCTest; -#import "Infrastructure.h" - - -@interface BridgingTests: XCTestCase @end @implementation BridgingTests - -- (void)testChainAnyPromiseFromSwiftCode { - XCTestExpectation *ex = [self expectationWithDescription:@""]; - AnyPromise *promise = PMKAfter(0.02); - for (int x = 0; x < 100; ++x) { - promise = promise.then(^{ - return [[[PromiseBridgeHelper alloc] init] bridge1]; - }); - } - promise.then(^{ - [ex fulfill]; - }); - [self waitForExpectationsWithTimeout:20 handler:nil]; -} - -- (void)test626 { - XCTestExpectation *ex = [self expectationWithDescription:@""]; - - testCase626().then(^{ - XCTFail(); - }).ensure(^{ - [ex fulfill]; - }); - - [self waitForExpectationsWithTimeout:20 handler:nil]; -} - -@end diff --git a/Tests/Bridging/BridgingTests.swift b/Tests/Bridging/BridgingTests.swift deleted file mode 100644 index 0e0433461..000000000 --- a/Tests/Bridging/BridgingTests.swift +++ /dev/null @@ -1,280 +0,0 @@ -import Foundation -import PromiseKit -import XCTest - -class BridgingTests: XCTestCase { - - func testCanBridgeAnyObject() { - let sentinel = NSURLRequest() - let p = Promise.value(sentinel) - let ap = AnyPromise(p) - - XCTAssertEqual(ap.value(forKey: "value") as? NSURLRequest, sentinel) - } - - func testCanBridgeOptional() { - let sentinel: NSURLRequest? = NSURLRequest() - let p = Promise.value(sentinel) - let ap = AnyPromise(p) - - XCTAssertEqual(ap.value(forKey: "value") as? NSURLRequest, sentinel) - } - - func testCanBridgeSwiftArray() { - let sentinel = [NSString(), NSString(), NSString()] - let p = Promise.value(sentinel) - let ap = AnyPromise(p) - - guard let foo = ap.value(forKey: "value") as? [NSString] else { return XCTFail() } - XCTAssertEqual(foo, sentinel) - } - - func testCanBridgeSwiftDictionary() { - let sentinel = [NSString(): NSString()] - let p = Promise.value(sentinel) - let ap = AnyPromise(p) - - guard let foo = ap.value(forKey: "value") as? [NSString: NSString] else { return XCTFail() } - XCTAssertEqual(foo, sentinel) - } - - func testCanBridgeInt() { - let sentinel = 3 - let p = Promise.value(sentinel) - let ap = AnyPromise(p) - XCTAssertEqual(ap.value(forKey: "value") as? Int, sentinel) - } - - func testCanBridgeString() { - let sentinel = "a" - let p = Promise.value(sentinel) - let ap = AnyPromise(p) - XCTAssertEqual(ap.value(forKey: "value") as? String, sentinel) - } - - func testCanBridgeBool() { - let sentinel = true - let p = Promise.value(sentinel) - let ap = AnyPromise(p) - XCTAssertEqual(ap.value(forKey: "value") as? Bool, sentinel) - } - - func testCanChainOffAnyPromiseFromObjC() { - let ex = expectation(description: "") - - firstly { - .value(1) - }.then { _ -> AnyPromise in - return PromiseBridgeHelper().value(forKey: "bridge2") as! AnyPromise - }.done { value in - XCTAssertEqual(123, value as? Int) - ex.fulfill() - }.silenceWarning() - - waitForExpectations(timeout: 1) - } - - func testCanThenOffAnyPromise() { - let ex = expectation(description: "") - - PMKDummyAnyPromise_YES().then { obj -> Promise in - if let value = obj as? NSNumber { - XCTAssertEqual(value, NSNumber(value: true)) - ex.fulfill() - } - return Promise() - }.silenceWarning() - - waitForExpectations(timeout: 1) - } - - func testCanThenOffManifoldAnyPromise() { - let ex = expectation(description: "") - - PMKDummyAnyPromise_Manifold().then { obj -> Promise in - defer { ex.fulfill() } - XCTAssertEqual(obj as? NSNumber, NSNumber(value: true), "\(obj ?? "nil") is not @YES") - return Promise() - }.silenceWarning() - - waitForExpectations(timeout: 1) - } - - func testCanAlwaysOffAnyPromise() { - let ex = expectation(description: "") - - PMKDummyAnyPromise_YES().then { obj -> Promise in - ex.fulfill() - return Promise() - }.silenceWarning() - - waitForExpectations(timeout: 1) - } - - func testCanCatchOffAnyPromise() { - let ex = expectation(description: "") - PMKDummyAnyPromise_Error().catch { err in - ex.fulfill() - } - waitForExpectations(timeout: 1) - } - - func testAsPromise() { - #if swift(>=3.1) - XCTAssertTrue(Promise(PMKDummyAnyPromise_Error()).isRejected) - XCTAssertEqual(Promise(PMKDummyAnyPromise_YES()).value as? NSNumber, NSNumber(value: true)) - #else - XCTAssertTrue(PMKDummyAnyPromise_Error().asPromise().isRejected) - XCTAssertEqual(PMKDummyAnyPromise_YES().asPromise().value as? NSNumber, NSNumber(value: true)) - #endif - } - - func testFirstlyReturningAnyPromiseSuccess() { - let ex = expectation(description: "") - firstly { - PMKDummyAnyPromise_Error() - }.catch { error in - ex.fulfill() - } - waitForExpectations(timeout: 1) - } - - func testFirstlyReturningAnyPromiseError() { - let ex = expectation(description: "") - firstly { - PMKDummyAnyPromise_YES() - }.done { _ in - ex.fulfill() - }.silenceWarning() - waitForExpectations(timeout: 1) - } - - func test1() { - let ex = expectation(description: "") - - // AnyPromise.then { return x } - - let input = after(seconds: 0).map{ 1 } - - AnyPromise(input).then { obj -> Promise in - XCTAssertEqual(obj as? Int, 1) - return .value(2) - }.done { value in - XCTAssertEqual(value, 2) - ex.fulfill() - }.silenceWarning() - - waitForExpectations(timeout: 1) - } - - func test2() { - let ex = expectation(description: "") - - // AnyPromise.then { return AnyPromise } - - let input = after(seconds: 0).map{ 1 } - - AnyPromise(input).then { obj -> AnyPromise in - XCTAssertEqual(obj as? Int, 1) - return AnyPromise(after(seconds: 0).map{ 2 }) - }.done { obj in - XCTAssertEqual(obj as? Int, 2) - ex.fulfill() - }.silenceWarning() - - waitForExpectations(timeout: 1) - } - - func test3() { - let ex = expectation(description: "") - - // AnyPromise.then { return Promise } - - let input = after(seconds: 0).map{ 1 } - - AnyPromise(input).then { obj -> Promise in - XCTAssertEqual(obj as? Int, 1) - return after(seconds: 0).map{ 2 } - }.done { value in - XCTAssertEqual(value, 2) - ex.fulfill() - }.silenceWarning() - - waitForExpectations(timeout: 1, handler: nil) - } - - - // can return AnyPromise (that fulfills) in then handler - func test4() { - let ex = expectation(description: "") - Promise.value(1).then { _ -> AnyPromise in - return AnyPromise(after(seconds: 0).map{ 1 }) - }.done { x in - XCTAssertEqual(x as? Int, 1) - ex.fulfill() - }.silenceWarning() - waitForExpectations(timeout: 1, handler: nil) - } - - // can return AnyPromise (that rejects) in then handler - func test5() { - let ex = expectation(description: "") - - Promise.value(1).then { _ -> AnyPromise in - let promise = after(.milliseconds(100)).done{ throw Error.dummy } - return AnyPromise(promise) - }.catch { err in - ex.fulfill() - } - waitForExpectations(timeout: 1) - } - - func testStandardSwiftBridgeIsUnambiguous() { - let p = Promise.value(1) - let q = Promise(p) - - XCTAssertEqual(p.value, q.value) - } - - /// testing NSError to Error for cancelledError types - func testErrorCancellationBridging() { - let ex = expectation(description: "") - - let p = Promise().done { - throw LocalError.cancel as NSError - } - p.catch { _ in - XCTFail() - } - p.catch(policy: .allErrors) { - XCTAssertTrue($0.isCancelled) - ex.fulfill() - } - waitForExpectations(timeout: 1) - - // here we verify that Swift’s NSError bridging works as advertised - - XCTAssertTrue(LocalError.cancel.isCancelled) - XCTAssertTrue((LocalError.cancel as NSError).isCancelled) - } -} - -private enum Error: Swift.Error { - case dummy -} - -extension Promise { - func silenceWarning() {} -} - -private enum LocalError: CancellableError { - case notCancel - case cancel - - var isCancelled: Bool { - switch self { - case .notCancel: return false - case .cancel: return true - } - } -} diff --git a/Tests/Bridging/Infrastructure.h b/Tests/Bridging/Infrastructure.h deleted file mode 100644 index 104378fa6..000000000 --- a/Tests/Bridging/Infrastructure.h +++ /dev/null @@ -1,14 +0,0 @@ -@import Foundation; -@class AnyPromise; - -AnyPromise *PMKDummyAnyPromise_YES(void); -AnyPromise *PMKDummyAnyPromise_Manifold(void); -AnyPromise *PMKDummyAnyPromise_Error(void); - -__attribute__((objc_runtime_name("PMKPromiseBridgeHelper"))) -__attribute__((objc_subclassing_restricted)) -@interface PromiseBridgeHelper: NSObject -- (AnyPromise *)bridge1; -@end - -AnyPromise *testCase626(void); diff --git a/Tests/Bridging/Infrastructure.m b/Tests/Bridging/Infrastructure.m deleted file mode 100644 index 5049310ae..000000000 --- a/Tests/Bridging/Infrastructure.m +++ /dev/null @@ -1,38 +0,0 @@ -@import Foundation; -@import PromiseKit; -#import "Infrastructure.h" - -AnyPromise *PMKDummyAnyPromise_YES() { - return [AnyPromise promiseWithValue:@YES]; -} - -AnyPromise *PMKDummyAnyPromise_Manifold() { - return [AnyPromise promiseWithValue:PMKManifold(@YES, @NO, @NO)]; -} - -AnyPromise *PMKDummyAnyPromise_Error() { - return [AnyPromise promiseWithValue:[NSError errorWithDomain:@"a" code:1 userInfo:nil]]; -} - -@implementation PromiseBridgeHelper (objc) - -- (AnyPromise *)bridge2 { - return [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) { - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ - resolve(@123); - }); - }]; -} - -@end - -#import "PMKBridgeTests-Swift.h" - -AnyPromise *testCase626() { - return PMKWhen(@[[TestPromise626 promise], [TestPromise626 promise]]).then(^(id value){ - NSLog(@"Success: %@", value); - }).catch(^(NSError *error) { - NSLog(@"Error: %@", error); - @throw error; - }); -} diff --git a/Tests/Bridging/Infrastructure.swift b/Tests/Bridging/Infrastructure.swift deleted file mode 100644 index 775fd31cb..000000000 --- a/Tests/Bridging/Infrastructure.swift +++ /dev/null @@ -1,24 +0,0 @@ -import PromiseKit - -// for BridgingTests.m -@objc(PMKPromiseBridgeHelper) class PromiseBridgeHelper: NSObject { - @objc func bridge1() -> AnyPromise { - let p = after(.milliseconds(10)) - return AnyPromise(p) - } -} - -enum MyError: Error { - case PromiseError -} - -@objc class TestPromise626: NSObject { - - @objc class func promise() -> AnyPromise { - let promise: Promise = Promise { seal in - seal.reject(MyError.PromiseError) - } - - return AnyPromise(promise) - } -} diff --git a/Tests/Cancel/AfterTests.swift b/Tests/Cancel/AfterTests.swift new file mode 100644 index 000000000..1501fe5e0 --- /dev/null +++ b/Tests/Cancel/AfterTests.swift @@ -0,0 +1,121 @@ +import Foundation +import XCTest +import PromiseKit + +extension XCTestExpectation { + open func fulfill(error: Error) { + fulfill() + } +} + +class AfterTests: XCTestCase { + func fail() { XCTFail() } + + func testZero() { + let ex2 = expectation(description: "") + let cc2 = after(seconds: 0).cancellize().done(fail).catch(policy: .allErrors, ex2.fulfill) + cc2.cancel() + waitForExpectations(timeout: 5, handler: nil) + + let ex3 = expectation(description: "") + let cc3 = after(.seconds(0)).cancellize().done(fail).catch(policy: .allErrors, ex3.fulfill) + cc3.cancel() + waitForExpectations(timeout: 5, handler: nil) + } + + func testNegative() { + let ex2 = expectation(description: "") + let cc2 = after(seconds: -1).cancellize().done(fail).catch(policy: .allErrors, ex2.fulfill) + cc2.cancel() + waitForExpectations(timeout: 5, handler: nil) + + let ex3 = expectation(description: "") + let cc3 = after(.seconds(-1)).cancellize().done(fail).catch(policy: .allErrors, ex3.fulfill) + cc3.cancel() + waitForExpectations(timeout: 5, handler: nil) + } + + func testPositive() { + let ex2 = expectation(description: "") + let cc2 = after(seconds: 1).cancellize().done(fail).catch(policy: .allErrors, ex2.fulfill) + cc2.cancel() + waitForExpectations(timeout: 5, handler: nil) + + let ex3 = expectation(description: "") + let cc3 = after(.seconds(1)).cancellize().done(fail).catch(policy: .allErrors, ex3.fulfill) + cc3.cancel() + waitForExpectations(timeout: 5, handler: nil) + } + + func testCancellableAfter() { + // This is an example of a functional test case. + // Use XCTAssert and related functions to verify your tests produce the correct results. + + // Test the normal 'after' function + let exComplete = expectation(description: "after completes") + let afterPromise = after(seconds: 0) + afterPromise.done { + exComplete.fulfill() + }.catch { error in + XCTFail("afterPromise failed with error: \(error)") + } + + let exCancelComplete = expectation(description: "after completes") + + // Test cancellable `after` to ensure it is fulfilled if not cancelled + let cancelIgnoreAfterPromise = after(seconds: 0).cancellize() + cancelIgnoreAfterPromise.done { + exCancelComplete.fulfill() + }.catch(policy: .allErrors) { error in + XCTFail("cancelIgnoreAfterPromise failed with error: \(error)") + } + + // Test cancellable `after` to ensure it is cancelled + let cancellableAfterPromise = after(seconds: 0).cancellize() + cancellableAfterPromise.done { + XCTFail("cancellableAfter not cancelled") + }.catch(policy: .allErrorsExceptCancellation) { error in + XCTFail("cancellableAfterPromise failed with error: \(error)") + }.cancel() + + // Test cancellable `after` to ensure it is cancelled and throws a `CancellableError` + let exCancel = expectation(description: "after cancels") + let cancellableAfterPromiseWithError = after(seconds: 0).cancellize() + cancellableAfterPromiseWithError.done { + XCTFail("cancellableAfterWithError not cancelled") + }.catch(policy: .allErrors) { error in + error.isCancelled ? exCancel.fulfill() : XCTFail("unexpected error \(error)") + }.cancel() + + wait(for: [exComplete, exCancelComplete, exCancel], timeout: 5) + } + + func testCancelForPromise_Done() { + let exComplete = expectation(description: "done is cancelled") + + let promise = CancellablePromise { seal in + seal.fulfill(()) + } + promise.done { _ in + XCTFail("done not cancelled") + }.catch(policy: .allErrors) { error in + error.isCancelled ? exComplete.fulfill() : XCTFail("error: \(error)") + } + + promise.cancel() + + wait(for: [exComplete], timeout: 5) + } + + func testCancelForGuarantee_Done() { + let exComplete = expectation(description: "done is cancelled") + + after(seconds: 0).cancellize().done { _ in + XCTFail("done not cancelled") + }.catch(policy: .allErrors) { error in + error.isCancelled ? exComplete.fulfill() : XCTFail("error: \(error)") + }.cancel() + + wait(for: [exComplete], timeout: 5) + } +} diff --git a/Tests/Cancel/CancelChain.swift b/Tests/Cancel/CancelChain.swift new file mode 100644 index 000000000..12c57a207 --- /dev/null +++ b/Tests/Cancel/CancelChain.swift @@ -0,0 +1,242 @@ +import XCTest +import PromiseKit + +class CancelChain: XCTestCase { + // Using a distinct type for each promise so we can tell which promise is which when using trace messages inside Thenable + struct A { } + struct B { } + struct C { } + struct D { } + struct E { } + + struct Chain { + let pA: CancellablePromise + let pB: CancellablePromise + let pC: CancellablePromise + let pD: CancellablePromise + let pE: CancellablePromise + } + + func trace(_ message: String) { + // print(message) + } + + func cancelChainPromises() -> Chain { + let pA = CancellablePromise { seal in + self.trace("A IN") + after(seconds: 0.05).cancellize().done { + self.trace("A FULFILL") + seal.fulfill(A()) + }.catch(policy: .allErrors) { + self.trace("A ERR") + seal.reject($0) + } + } + + let pB = CancellablePromise { seal in + self.trace("B IN") + after(seconds: 0.1).cancellize().done { + self.trace("B FULFILL") + seal.fulfill(B()) + }.catch(policy: .allErrors) { + self.trace("B ERR") + seal.reject($0) + } + } + + let pC = CancellablePromise { seal in + self.trace("C IN") + after(seconds: 0.15).cancellize().done { + self.trace("C FULFILL") + seal.fulfill(C()) + }.catch(policy: .allErrors) { + self.trace("C ERR") + seal.reject($0) + } + } + + let pD = CancellablePromise { seal in + self.trace("D IN") + after(seconds: 0.2).cancellize().done { + self.trace("D FULFILL") + seal.fulfill(D()) + }.catch(policy: .allErrors) { + self.trace("D ERR") + seal.reject($0) + } + } + + let pE = CancellablePromise { seal in + self.trace("E IN") + after(seconds: 0.25).cancellize().done { + self.trace("E FULFILL") + seal.fulfill(E()) + }.catch(policy: .allErrors) { + self.trace("E ERR") + seal.reject($0) + } + } + + return Chain(pA: pA, pB: pB, pC: pC, pD: pD, pE: pE) + } + + struct exABCDE { + let a: XCTestExpectation? + let b: XCTestExpectation? + let c: XCTestExpectation? + let d: XCTestExpectation? + let e: XCTestExpectation? + let cancelled: XCTestExpectation? + + let cancelA: Bool + let cancelB: Bool + let cancelC: Bool + let cancelD: Bool + let cancelE: Bool + } + + func cancelChainSetup(ex: exABCDE) { + { + let c = cancelChainPromises() + + c.pA.then { (_: A) -> CancellablePromise in + self.trace("pA.then") + return firstly { () -> CancellablePromise in + self.trace("pB.firstly") + return c.pB + }.then { (_: B) -> CancellablePromise in + self.trace("pB.then") + return firstly { () -> CancellablePromise in + self.trace("pC.firstly") + if ex.cancelB { + self.trace("CANCEL") + c.pA.cancel() + } + ex.b?.fulfill() ?? XCTFail("pB.then") + return c.pC + }.then { (_: C) -> CancellablePromise in + ex.c?.fulfill() ?? XCTFail("pC.then") + if ex.cancelC { + self.trace("CANCEL") + c.pA.cancel() + } + self.trace("pC.then") + return c.pD + } + }.then { (_: D) -> CancellablePromise in + ex.d?.fulfill() ?? XCTFail("pD.done") + if ex.cancelD { + self.trace("CANCEL") + c.pA.cancel() + } + return c.pA // Intentional reuse of pA -- causes a loop that CancelContext must detect + } + }.then { (_: A) -> CancellablePromise in + self.trace("pA.then") + ex.a?.fulfill() ?? XCTFail("pA completed") + if ex.cancelA { + self.trace("CANCEL") + c.pA.cancel() + } + return c.pE + }.done { _ in + ex.e?.fulfill() ?? XCTFail("pE completed") + if ex.cancelE { + self.trace("CANCEL") + c.pA.cancel() + } + self.trace("pE.done") + }.catch(policy: .allErrors) { + self.trace("Error: \($0)") + $0.isCancelled ? ex.cancelled?.fulfill() : XCTFail("Error: \($0)") + } + + self.trace("SETUP COMPLETE") + + let expectations = [ex.a, ex.b, ex.c, ex.d, ex.e, ex.cancelled].compactMap { $0 } + wait(for: expectations, timeout: 5) + + XCTAssert(c.pA.cancelContext.cancelAttempted) + XCTAssert(ex.a == nil || isFulfilled(c.pB) || c.pB.cancelContext.cancelAttempted) + XCTAssert(ex.b == nil || isFulfilled(c.pC) || c.pC.cancelContext.cancelAttempted) + XCTAssert(ex.c == nil || isFulfilled(c.pD) || c.pD.cancelContext.cancelAttempted) + XCTAssert(ex.d == nil || isFulfilled(c.pE) || c.pE.cancelContext.cancelAttempted) + }() + + self.trace("DONE") + + return + } + + func isFulfilled(_ p: CancellablePromise) -> Bool { + if let result = p.promise.result { + if case .success = result { + return true + } else { + return false + } + } else { + return false + } + } + + func testCancelChainPB() { + let ex = exABCDE(a: nil, + b: expectation(description: "pB completed"), + c: nil, + d: nil, + e: nil, + cancelled: expectation(description: "cancelled"), + cancelA: false, + cancelB: true, + cancelC: false, + cancelD: false, + cancelE: false) + cancelChainSetup(ex: ex) + } + + func testCancelChainPC() { + let ex = exABCDE(a: nil, + b: expectation(description: "pB completed"), + c: expectation(description: "pC completed"), + d: nil, + e: nil, + cancelled: expectation(description: "cancelled"), + cancelA: false, + cancelB: false, + cancelC: true, + cancelD: false, + cancelE: false) + cancelChainSetup(ex: ex) + } + + func testCancelChainPAD() { + let ex = exABCDE(a: expectation(description: "pA completed"), + b: expectation(description: "pB completed"), + c: expectation(description: "pC completed"), + d: expectation(description: "pD completed"), + e: nil, + cancelled: expectation(description: "cancelled"), + cancelA: true, + cancelB: false, + cancelC: false, + cancelD: false, + cancelE: false) + cancelChainSetup(ex: ex) + } + + func testCancelChainSuccess() { + let ex = exABCDE(a: expectation(description: "pA completed"), + b: expectation(description: "pB completed"), + c: expectation(description: "pC completed"), + d: expectation(description: "pD completed"), + e: expectation(description: "pE completed"), + cancelled: nil, + cancelA: false, + cancelB: false, + cancelC: false, + cancelD: false, + cancelE: true) + cancelChainSetup(ex: ex) + } +} diff --git a/Tests/Cancel/CancellableErrorTests.swift b/Tests/Cancel/CancellableErrorTests.swift new file mode 100644 index 000000000..4e74fef7b --- /dev/null +++ b/Tests/Cancel/CancellableErrorTests.swift @@ -0,0 +1,134 @@ +import Foundation +import PromiseKit +import XCTest + +class CancellationTests: XCTestCase { + func testCancellation() { + let ex1 = expectation(description: "") + + let p = after(seconds: 0).cancellize().done { _ in + XCTFail() + } + p.catch { _ in + XCTFail() + } + p.catch(policy: .allErrors) { + XCTAssertTrue($0.isCancelled) + ex1.fulfill() + } + + p.cancel(with: LocalError.cancel) + + waitForExpectations(timeout: 5) + } + + func testThrowCancellableErrorThatIsNotCancelled() { + let expect = expectation(description: "") + + let cc = after(seconds: 0).cancellize().done { + XCTFail() + }.catch { + XCTAssertFalse($0.isCancelled) + expect.fulfill() + } + + cc.cancel(with: LocalError.notCancel) + + waitForExpectations(timeout: 5) + } + + func testRecoverWithCancellation() { + let ex1 = expectation(description: "") + let ex2 = expectation(description: "") + + let p = after(seconds: 0).cancellize().done { _ in + XCTFail() + }.recover(policy: .allErrors) { err -> CancellablePromise in + ex1.fulfill() + XCTAssertTrue(err.isCancelled) + throw err + }.done { _ in + XCTFail() + } + p.catch { _ in + XCTFail() + } + p.catch(policy: .allErrors) { + XCTAssertTrue($0.isCancelled) + ex2.fulfill() + } + + p.cancel(with: CocoaError.cancelled) + + waitForExpectations(timeout: 5) + } + + func testFoundationBridging1() { + let ex = expectation(description: "") + + let p = after(seconds: 0).cancellize().done { _ in + XCTFail() + } + p.catch { _ in + XCTFail() + } + p.catch(policy: .allErrors) { + XCTAssertTrue($0.isCancelled) + ex.fulfill() + } + + p.cancel(with: CocoaError.cancelled) + + waitForExpectations(timeout: 5) + } + + func testFoundationBridging2() { + let ex = expectation(description: "") + + let p = CancellablePromise().done { + XCTFail() + } + p.catch { _ in + XCTFail() + } + p.catch(policy: .allErrors) { + XCTAssertTrue($0.isCancelled) + ex.fulfill() + } + + p.cancel(with: URLError.cancelled) + + waitForExpectations(timeout: 5) + } + + func testIsCancelled() { + XCTAssertTrue(PMKError.cancelled.isCancelled) + XCTAssertTrue(URLError.cancelled.isCancelled) + XCTAssertTrue(CocoaError.cancelled.isCancelled) + XCTAssertFalse(CocoaError(_nsError: NSError(domain: NSCocoaErrorDomain, code: CocoaError.Code.coderInvalidValue.rawValue)).isCancelled) + } +} + +private enum LocalError: CancellableError { + case notCancel + case cancel + + var isCancelled: Bool { + switch self { + case .notCancel: return false + case .cancel: return true + } + } +} + +private extension URLError { + static var cancelled: URLError { + return .init(_nsError: NSError(domain: NSURLErrorDomain, code: URLError.Code.cancelled.rawValue)) + } +} + +private extension CocoaError { + static var cancelled: CocoaError { + return .init(_nsError: NSError(domain: NSCocoaErrorDomain, code: CocoaError.Code.userCancelled.rawValue)) + } +} diff --git a/Tests/Cancel/CancellablePromiseTests.swift b/Tests/Cancel/CancellablePromiseTests.swift new file mode 100644 index 000000000..4e5b7c0de --- /dev/null +++ b/Tests/Cancel/CancellablePromiseTests.swift @@ -0,0 +1,205 @@ +import Foundation +import PromiseKit +import XCTest + +class CancellablePromiseTests: XCTestCase { + func login() -> Promise { + return Promise.value(1) + } + + func fetch(avatar: Int) -> CancellablePromise { + return Promise.value(avatar + 2).cancellize() + } + + func testCancellablePromiseEmbeddedInStandardPromiseChain() { + let ex = expectation(description: "") + var imageView: Int? + let promise = firstly { /// <-- ERROR: Ambiguous reference to member 'firstly(execute:)' + /* The 'cancellize' method initiates a cancellable promise chain by + returning a 'CancellablePromise'. */ + login().cancellize() /// CHANGE TO: "login().cancellize()" + }.then { creds in + self.fetch(avatar: creds) + }.done { image in + imageView = image + XCTAssert(imageView == 3) + XCTFail() + }.catch(policy: .allErrors) { error in + if error.isCancelled { + // the chain has been cancelled! + ex.fulfill() + } else { + XCTFail() + } + } + + // … + + promise.cancel() + + waitForExpectations(timeout: 5) + } + + func testReturnTypeForAMultiLineClosureIsNotExplicitlyStated() { + let ex = expectation(description: "") + var imageView: Int? + firstly { + login() + }.cancellize().then { creds -> CancellablePromise in + let f = self.fetch(avatar: creds) + return f + }.done { image in + imageView = image + XCTAssert(imageView == 3) + ex.fulfill() + }.catch(policy: .allErrors) { error in + XCTFail() + } + + waitForExpectations(timeout: 5) + } + + func testTryingToCancelAStandardPromiseChain() { + let ex = expectation(description: "") + var imageView: Int? + let promise = firstly { + login() + }.cancellize().then { creds in + self.fetch(avatar: creds) + }.done { image in + imageView = image + XCTAssert(imageView == 3) + XCTFail() + }.catch(policy: .allErrors) { error in + if error.isCancelled { + // the chain has been cancelled! + ex.fulfill() + } else { + XCTFail() + } + } + + // … + + promise.cancel() /// <-- ERROR: Value of type 'PMKFinalizer' has no member 'cancel' + + waitForExpectations(timeout: 5) + } + + func testCancel() { + let ex = expectation(description: "") + let p = CancellablePromise.pending() + p.promise.then { (val: Int) -> Promise in + Promise.value("hi") + }.done { _ in + XCTFail() + ex.fulfill() + }.catch(policy: .allErrors) { + $0.isCancelled ? ex.fulfill() : XCTFail() + } + p.resolver.fulfill(3) + p.promise.cancel() + + wait(for: [ex], timeout: 5) + } + + func testFirstly() { + let ex = expectation(description: "") + firstly { + Promise.value(3) + }.cancellize().then { (_: Int) -> Promise in + XCTFail() + return Promise.value("hi") + }.done { _ in + XCTFail() + }.catch(policy: .allErrors) { + $0.isCancelled ? ex.fulfill() : XCTFail() + }.cancel() + + wait(for: [ex], timeout: 5) + } + + func testFirstlyWithPromise() { + let ex = expectation(description: "") + firstly { + return Promise.value(3) + }.cancellize().then { (_: Int) -> Promise in + XCTFail() + return Promise.value("hi") + }.done { _ in + XCTFail() + }.catch(policy: .allErrors) { + $0.isCancelled ? ex.fulfill() : XCTFail("\($0)") + }.cancel() + + wait(for: [ex], timeout: 5) + } + + func testThenMapSuccess() { + let ex = expectation(description: "") + firstly { + Promise.value([1,2,3]) + }.cancellize().thenMap { (integer: Int) -> Promise in + return Promise.value(integer * 2) + }.done { _ in + ex.fulfill() + // $0 => [2,4,6] + }.catch(policy: .allErrors) { _ in + XCTFail() + } + waitForExpectations(timeout: 5) + } + + func testThenMapCancel() { + let ex = expectation(description: "") + firstly { + Promise.value([1,2,3]) + }.cancellize().thenMap { (integer: Int) -> Promise in + XCTFail() + return Promise.value(integer * 2) + }.done { _ in + XCTFail() + // $0 => [2,4,6] + }.catch(policy: .allErrors) { + $0.isCancelled ? ex.fulfill() : XCTFail() + }.cancel() + waitForExpectations(timeout: 5) + } + + func testChain() { + let ex = expectation(description: "") + firstly { + Promise.value(1) + }.cancellize().then { (integer: Int) -> Promise in + XCTFail() + return Promise.value(integer * 2) + }.done { _ in + // $0 => [2,4,6] + }.catch(policy: .allErrors) { + $0.isCancelled ? ex.fulfill() : XCTFail() + }.cancel() + waitForExpectations(timeout: 5) + } + + func testBridge() { + let ex1 = expectation(description: "") + let ex2 = expectation(description: "") + + let (promise, seal) = Promise.pending() + DispatchQueue.global(qos: .default).asyncAfter(deadline: DispatchTime.now() + 0.2) { seal.fulfill(()) } + + CancellablePromise(promise).done { _ in + XCTFail() + }.catch(policy: .allErrors) { + $0.isCancelled ? ex2.fulfill() : XCTFail() + }.cancel() + + promise.done { _ in + ex1.fulfill() + }.catch(policy: .allErrors) { _ in + XCTFail() + } + + waitForExpectations(timeout: 5) + } +} diff --git a/Tests/Cancel/CatchableTests.swift b/Tests/Cancel/CatchableTests.swift new file mode 100644 index 000000000..60caee55c --- /dev/null +++ b/Tests/Cancel/CatchableTests.swift @@ -0,0 +1,895 @@ +import PromiseKit +import Dispatch +import XCTest + +class CatchableTests: XCTestCase { + + func testFinally() { + let finallyQueue = DispatchQueue(label: "\(#file):\(#line)", attributes: .concurrent) + + func helper(error: Error, on queue: DispatchQueue = .main, flags: DispatchWorkItemFlags? = nil) { + let ex = (expectation(description: ""), expectation(description: "")) + var x = 0 + let p = after(seconds: 0.01).cancellize().catch(policy: .allErrors) { _ in + XCTAssertEqual(x, 0) + x += 1 + ex.0.fulfill() + }.finally(on: queue, flags: flags) { + if let flags = flags, flags.contains(.barrier) { + dispatchPrecondition(condition: .onQueueAsBarrier(queue)) + } else { + dispatchPrecondition(condition: .onQueue(queue)) + } + XCTAssertEqual(x, 1) + x += 1 + ex.1.fulfill() + } + + p.cancel(with: error) + + wait(for: [ex.0, ex.1], timeout: 5) + } + + helper(error: Error.dummy) + helper(error: Error.cancelled) + helper(error: Error.dummy, on: finallyQueue) + helper(error: Error.dummy, on: finallyQueue, flags: .barrier) + } + + func testCauterize() { + let ex = expectation(description: "") + let p = after(seconds: 0.01).cancellize() + + // cannot test specifically that this outputs to console, + // but code-coverage will note that the line is run + p.cauterize() + + p.catch { _ in + ex.fulfill() + } + + p.cancel(with: Error.dummy) + + wait(for: [ex], timeout: 5) + } +} + +/// `Promise.recover` +extension CatchableTests { + func test__void_specialized_full_recover() { + + func helper(policy: CatchPolicy, error: Swift.Error, line: UInt = #line) { + let ex = expectation(description: "error caught") + CancellablePromise(error: error).recover { _ in }.done { _ in XCTFail() }.catch(policy: .allErrors, ex.fulfill).cancel() + wait(for: [ex], timeout: 5) + } + + helper(policy: .allErrorsExceptCancellation, error: Error.dummy) + helper(policy: .allErrors, error: Error.dummy) + helper(policy: .allErrorsExceptCancellation, error: Error.cancelled) + helper(policy: .allErrors, error: Error.cancelled) + + let ex2 = expectation(description: "cancel caught") + let d2 = CancellablePromise(error: Error.cancelled).recover(policy: .allErrors) { _ in }.done(ex2.fulfill) + d2.cancel() + wait(for: [ex2], timeout: 5) + } + + func test__void_specialized_full_recover__fulfilled_path() { + let ex = expectation(description: "") + CancellablePromise().recover { _ in + XCTFail() + }.done { _ in + XCTFail() + }.catch(policy: .allErrors) { + $0.isCancelled ? ex.fulfill() : XCTFail() + }.cancel() + wait(for: [ex], timeout: 5) + + let ex2 = expectation(description: "") + let promise = CancellablePromise() + promise.cancel() + promise.recover(policy: .allErrors) { _ in }.done(ex2.fulfill).catch(policy: .allErrors) { _ in XCTFail() } + wait(for: [ex2], timeout: 5) + } + + func test__void_specialized_conditional_recover() { + func helperDone(policy: CatchPolicy, error: Swift.Error, line: UInt = #line) { + let ex = expectation(description: "") + var x = 0 + let promise = CancellablePromise(error: error).recover(policy: policy) { (err: Swift.Error) throws -> Void in + guard x < 1 else { throw err } + x += 1 + }.done(ex.fulfill).catch(policy: .allErrors) { _ in + XCTFail() + } + promise.cancel() + wait(for: [ex], timeout: 5) + } + + func helperCatch(policy: CatchPolicy, error: Swift.Error, line: UInt = #line) { + let ex = expectation(description: "") + var x = 0 + let promise = CancellablePromise(error: error).recover(policy: policy) { (err: Swift.Error) throws -> Void in + guard x < 1 else { throw err } + x += 1 + }.done { _ in + XCTFail() + }.catch(policy: .allErrors) { + $0.isCancelled ? ex.fulfill() : XCTFail() + } + promise.cancel() + wait(for: [ex], timeout: 5) + } + + for error in [Error.dummy as Swift.Error, Error.cancelled] { + helperDone(policy: .allErrors, error: error) + } + helperCatch(policy: .allErrorsExceptCancellation, error: Error.dummy) + } + + func test__void_specialized_conditional_recover__no_recover() { + + func helper(policy: CatchPolicy, error: Error, line: UInt = #line) { + let ex = expectation(description: "") + CancellablePromise(error: error).recover(policy: .allErrorsExceptCancellation) { err in + throw err + }.catch(policy: .allErrors) { _ in + ex.fulfill() + }.cancel() + wait(for: [ex], timeout: 5) + } + + for error in [Error.dummy, Error.cancelled] { + helper(policy: .allErrors, error: error) + } + helper(policy: .allErrorsExceptCancellation, error: Error.dummy) + } + + func test__void_specialized_conditional_recover__ignores_cancellation_but_fed_cancellation() { + let ex = expectation(description: "") + CancellablePromise(error: Error.cancelled).recover(policy: .allErrorsExceptCancellation) { _ in + XCTFail() + }.catch(policy: .allErrors) { + XCTAssertEqual(Error.cancelled, $0 as? Error) + ex.fulfill() + }.cancel() + wait(for: [ex], timeout: 5) + } + + func test__void_specialized_conditional_recover__fulfilled_path() { + let ex = expectation(description: "") + let p = CancellablePromise().recover { _ in + XCTFail() + }.catch { _ in + XCTFail() // this `catch` to ensure we are calling the `recover` variant we think we are + }.finally { + ex.fulfill() + } + p.cancel() + wait(for: [ex], timeout: 5) + } +} + +/// `Promise.recover` +extension CatchableTests { + func test__full_recover() { + func helper(error: Swift.Error) { + let ex = expectation(description: "") + CancellablePromise(error: error).recover { _ in + return Promise.value(2).cancellize() + }.done { _ in + XCTFail() + }.catch(policy: .allErrors, ex.fulfill).cancel() + wait(for: [ex], timeout: 5) + } + + helper(error: Error.dummy) + helper(error: Error.cancelled) + } + + func test__full_recover__fulfilled_path() { + let ex = expectation(description: "") + Promise.value(1).cancellize().recover { _ -> CancellablePromise in + XCTFail() + return Promise.value(2).cancellize() + }.done { _ in + XCTFail() + }.catch(policy: .allErrors) { error in + error.isCancelled ? ex.fulfill() : XCTFail() + }.cancel() + wait(for: [ex], timeout: 5) + } + + func test__conditional_recover() { + func helper(policy: CatchPolicy, error: Swift.Error, line: UInt = #line) { + let ex = expectation(description: "\(policy) \(error) \(line)") + var x = 0 + CancellablePromise(error: error).recover(policy: policy) { (err: Swift.Error) throws -> CancellablePromise in + guard x < 1 else { + throw err + } + x += 1 + return Promise.value(x).cancellize() + }.done { _ in + ex.fulfill() + }.catch(policy: .allErrors) { error in + if policy == .allErrorsExceptCancellation { + error.isCancelled ? ex.fulfill() : XCTFail() + } else { + XCTFail() + } + }.cancel() + wait(for: [ex], timeout: 5) + } + + for error in [Error.dummy as Swift.Error, Error.cancelled] { + helper(policy: .allErrors, error: error) + } + helper(policy: .allErrorsExceptCancellation, error: Error.dummy) + } + + func test__conditional_recover__no_recover() { + + func helper(policy: CatchPolicy, error: Error, line: UInt = #line) { + let ex = expectation(description: "\(policy) \(error) \(line)") + CancellablePromise(error: error).recover(policy: policy) { err -> CancellablePromise in + throw err + }.catch(policy: .allErrors) { + if !(($0 as? PMKError)?.isCancelled ?? false) { + XCTAssertEqual(error, $0 as? Error) + } + ex.fulfill() + }.cancel() + wait(for: [ex], timeout: 5) + } + + for error in [Error.dummy, Error.cancelled] { + helper(policy: .allErrors, error: error) + } + helper(policy: .allErrorsExceptCancellation, error: Error.dummy) + } + + func test__conditional_recover__ignores_cancellation_but_fed_cancellation() { + let ex = expectation(description: "") + CancellablePromise(error: Error.cancelled).recover(policy: .allErrorsExceptCancellation) { _ -> CancellablePromise in + XCTFail() + return Promise.value(1).cancellize() + }.catch(policy: .allErrors) { + XCTAssertEqual(Error.cancelled, $0 as? Error) + ex.fulfill() + }.cancel() + wait(for: [ex], timeout: 5) + } + + func test__conditional_recover__fulfilled_path() { + let ex = expectation(description: "") + Promise.value(1).cancellize().recover { err -> CancellablePromise in + XCTFail() + throw err + }.done { + XCTFail() + XCTAssertEqual($0, 1) + }.catch(policy: .allErrors) { error in + error.isCancelled ? ex.fulfill() : XCTFail() + }.cancel() + wait(for: [ex], timeout: 5) + } + + func test__cancellable_conditional_recover__fulfilled_path() { + let ex = expectation(description: "") + Promise.value(1).cancellize().recover { err -> Promise in + XCTFail() + throw err + }.done { + XCTFail() + XCTAssertEqual($0, 1) + }.catch(policy: .allErrors) { error in + error.isCancelled ? ex.fulfill() : XCTFail() + }.cancel() + wait(for: [ex], timeout: 5) + } + + func testEnsureThen_Error() { + let ex = expectation(description: "") + + let p = Promise.value(1).cancellize().done { + XCTAssertEqual($0, 1) + throw Error.dummy + }.ensureThen { + return after(seconds: 0.01).cancellize() + }.catch(policy: .allErrors) { + XCTAssert(($0 as? PMKError)?.isCancelled ?? false) + }.finally { + ex.fulfill() + } + p.cancel() + + wait(for: [ex], timeout: 5) + } + + func testEnsureThen_Value() { + let ex = expectation(description: "") + + Promise.value(1).cancellize().ensureThen { + after(seconds: 0.01).cancellize() + }.done { _ in + XCTFail() + }.catch(policy: .allErrors) { + if !$0.isCancelled { + XCTFail() + } + }.finally { + ex.fulfill() + }.cancel() + + wait(for: [ex], timeout: 5) + } + + func testEnsureThen_Value_NotCancelled() { + let ex = expectation(description: "") + + Promise.value(1).cancellize().ensureThen { + after(seconds: 0.01).cancellize() + }.done { + XCTAssertEqual($0, 1) + }.catch(policy: .allErrors) { _ in + XCTFail() + }.finally { + ex.fulfill() + } + + wait(for: [ex], timeout: 5) + } + + func testCancellableFinalizerHelpers() { + let ex = expectation(description: "") + + let f = Promise.value(1).cancellize().done { _ in + XCTFail() + }.catch(policy: .allErrors) { + $0.isCancelled ? ex.fulfill() : XCTFail() + } + f.cancel() + + XCTAssertEqual(f.isCancelled, true) + XCTAssertEqual(f.cancelAttempted, true) + XCTAssert(f.cancelledError?.isCancelled ?? false) + + wait(for: [ex], timeout: 5) + } + + func testCancellableRecoverFromError() { + let ex = expectation(description: "") + + let p = Promise(error: PMKError.emptySequence).cancellize().recover(policy: .allErrors) { _ in + Promise.value(1) + }.done { + XCTAssertEqual($0, 1) + ex.fulfill() + } + let f = p.catch(policy: .allErrors) { _ in + XCTFail() + } + + XCTAssertEqual(f.isCancelled, false) + XCTAssertEqual(f.cancelAttempted, false) + XCTAssert(f.cancelledError == nil) + XCTAssert(p.cancelledError == nil) + + wait(for: [ex], timeout: 5) + + XCTAssertEqual(p.isPending, false) + XCTAssertEqual(p.isResolved, true) + XCTAssertEqual(p.isFulfilled, true) + } +} + +/// `Promise.catch(only:)` +extension CatchableTests { + func testCatchOnly() { + let x = expectation(description: #file + #function) + + Promise(error: Error.dummy).cancellize().catch(only: Error.dummy) { _ in + x.fulfill() + }.catch(policy: .allErrors) { + $0.isCancelled ? x.fulfill() : XCTFail() + }.cancel() + + wait(for: [x], timeout: 5) + } + + func testCatchOnly_PatternMatch_1() { + let x = expectation(description: "Pattern match only Error.dummy") + + Promise(error: Error.dummy).cancellize().catch(only: Error.dummy) { _ in + x.fulfill() + }.catch(only: Error.cancelled) { _ in + XCTFail() + x.fulfill() + }.catch(policy: .allErrors) { + $0.isCancelled ? x.fulfill() : XCTFail() + }.cancel() + + wait(for: [x], timeout: 5) + } + + func testCatchOnly_PatternMatch_2() { + let x = expectation(description: "Pattern match only Error.dummy") + + Promise(error: Error.dummy).cancellize().catch(only: Error.cancelled) { _ in + XCTFail() + x.fulfill() + }.catch(only: Error.dummy) { _ in + x.fulfill() + }.catch(policy: .allErrors) { + $0.isCancelled ? x.fulfill() : XCTFail() + }.cancel() + + wait(for: [x], timeout: 5) + } + + func testCatchOnly_BaseCatchIsNotCalledAfterCatchOnlyExecutes() { + let x = expectation(description: #file + #function) + + Promise(error: Error.dummy).cancellize().catch(only: Error.dummy) { _ in + x.fulfill() + }.catch { _ in + XCTFail() + x.fulfill() + } + + wait(for: [x], timeout: 5) + } + + func testCatchOnly_BaseCatchIsCalledWhenCatchOnlyDoesNotExecute() { + let x = expectation(description: #file + #function) + + Promise(error: Error.dummy).cancellize().catch(only: Error.cancelled) { _ in + XCTFail() + x.fulfill() + }.catch { _ in + x.fulfill() + } + + wait(for: [x], timeout: 5) + } + + func testCatchOnly_Type() { + let x = expectation(description: #file + #function) + + Promise(error: Error.dummy).cancellize().catch(only: Error.self) { _ in + x.fulfill() + }.catch(policy: .allErrors) { + $0.isCancelled ? x.fulfill() : XCTFail() + }.cancel() + + wait(for: [x], timeout: 5) + } + + func testCatchOnly_Type_Ignored() { + let x = expectation(description: #file + #function) + + enum Foo: Swift.Error { + case a + } + + Promise(error: Error.dummy).cancellize().catch(only: Foo.self) { _ in + XCTFail() + }.catch { _ in + x.fulfill() + } + + wait(for: [x], timeout: 5) + } + + func testCatchOnly_Type_PatternMatch_1() { + let x = expectation(description: "Pattern match only Error.Type") + + Promise(error: Error.dummy).cancellize().catch(only: Error.self) { _ in + x.fulfill() + }.catch(only: Error.dummy) { _ in + XCTFail() + x.fulfill() + }.catch(policy: .allErrors) { + $0.isCancelled ? x.fulfill() : XCTFail() + }.cancel() + + wait(for: [x], timeout: 5) + } + + func testCatchOnly_Type_PatternMatch_2() { + let x = expectation(description: "Pattern match only Error.dummy") + + Promise(error: Error.dummy).cancellize().catch(only: Error.dummy) { _ in + x.fulfill() + }.catch(only: Error.self) { _ in + XCTFail() + x.fulfill() + }.catch(policy: .allErrors) { + $0.isCancelled ? x.fulfill() : XCTFail() + }.cancel() + + wait(for: [x], timeout: 5) + } + + func testCatchOnly_Type_BaseCatchIsNotCalledAfterCatchOnlyExecutes() { + let x = expectation(description: #file + #function) + + Promise(error: Error.dummy).cancellize().catch(only: Error.self) { _ in + x.fulfill() + }.catch { _ in + XCTFail() + x.fulfill() + } + + wait(for: [x], timeout: 5) + } + + func testCatchOnly_Type_Cancellation_Ignore() { + let x = expectation(description: #file + #function) + + Promise(error: Error.cancelled).cancellize().catch(only: Error.self) { _ in + XCTFail() + x.fulfill() + }.catch(policy: .allErrors) { _ in + x.fulfill() + } + + wait(for: [x], timeout: 5) + } + + func testCatchOnly_Type_Cancellation_Handle() { + let x = expectation(description: #file + #function) + + Promise(error: Error.cancelled).cancellize().catch(only: Error.self, policy: .allErrors) { _ in + x.fulfill() + }.catch { _ in + XCTFail() + x.fulfill() + } + + wait(for: [x], timeout: 5) + } + + func testCatchOnly_Mixed() { + let x = expectation(description: #file + #function) + + enum Foo: Swift.Error { case bar } + + Promise(error: Foo.bar).cancellize().catch(only: Error.dummy) { _ in + XCTFail() + x.fulfill() + }.catch(only: Foo.self) { _ in + x.fulfill() + }.catch(policy: .allErrors) { + $0.isCancelled ? x.fulfill() : XCTFail() + }.cancel() + + wait(for: [x], timeout: 5) + } +} + +/// `Promise.recover(only:)` +extension CatchableTests { + func testRecoverOnly_Object() { + let x = expectation(description: #file + #function) + + Promise(error: Error.dummy).cancellize().recover(only: Error.dummy) { _ in + return Promise.value(1) + }.done { _ in + x.fulfill() + }.catch { _ in + XCTFail() + x.fulfill() + } + + wait(for: [x], timeout: 5) + } + + func testRecoverOnly_Object_Ignored() { + let x = expectation(description: #file + #function) + + Promise.value(1).cancellize().recover(only: Error.dummy) { _ in + return Promise(error: Error.dummy) + }.done { _ in + x.fulfill() + }.catch(policy: .allErrors) { + $0.isCancelled ? x.fulfill() : XCTFail() + }.cancel() + + wait(for: [x], timeout: 5) + } + + func testRecoverOnly_Object_PatternMatch() { + let x = expectation(description: #file + #function) + + Promise(error: Error.cancelled).cancellize().recover(only: Error.dummy) { _ in + return Promise.value(1) + }.done { _ in + XCTFail() + x.fulfill() + }.catch(policy: .allErrors) { _ in + x.fulfill() + } + + wait(for: [x], timeout: 5) + } + + func testRecoverOnly_Type() { + let x = expectation(description: #file + #function) + + Promise(error: Error.dummy).cancellize().recover(only: Error.self) { _ in + return Promise.value(1) + }.done { _ in + x.fulfill() + }.catch(policy: .allErrors) { + $0.isCancelled ? x.fulfill() : XCTFail() + }.cancel() + + wait(for: [x], timeout: 5) + } + + func testRecoverOnly_Type_Ignored() { + let x = expectation(description: #file + #function) + + Promise.value(1).cancellize().recover(only: Error.self) { _ in + return Promise(error: Error.dummy) + }.done { _ in + x.fulfill() + }.catch { _ in + XCTFail() + x.fulfill() + } + + wait(for: [x], timeout: 5) + } + + func testRecoverOnly_Type_PatternMatch() { + let x = expectation(description: #file + #function) + + enum Foo: Swift.Error { + case a + } + + Promise(error: Error.dummy).cancellize().recover(only: Foo.self) { _ in + Promise.value(1) + }.done { _ in + XCTFail() + x.fulfill() + }.catch { _ in + x.fulfill() + } + + wait(for: [x], timeout: 5) + } + + func testRecoverOnly_Type_Cancellation_Ignore() { + let x = expectation(description: #file + #function) + + Promise(error: Error.cancelled).cancellize().recover(only: Error.self) { _ in + return Promise.value(1) + }.done { _ in + XCTFail() + x.fulfill() + }.catch(policy: .allErrors) { _ in + x.fulfill() + } + + wait(for: [x], timeout: 5) + } + + func testRecoverOnly_Type_Cancellation_Handle() { + let x = expectation(description: #file + #function) + + Promise(error: Error.cancelled).cancellize().recover(only: Error.self, policy: .allErrors) { _ in + return Promise.value(1) + }.done { _ in + x.fulfill() + }.catch { _ in + XCTFail() + x.fulfill() + } + + wait(for: [x], timeout: 5) + } + + func testRecoverOnly_Chaining() { + let x = expectation(description: #file + #function) + + enum Foo: Swift.Error { case bar } + + Promise(error: Error.dummy).cancellize().recover(only: Foo.self) { _ in + return Promise(error: Foo.bar) + }.recover(only: Error.dummy) { _ in + return Promise.value(1) + }.done { _ in + x.fulfill() + }.catch { _ in + XCTFail() + x.fulfill() + } + + wait(for: [x], timeout: 5) + } + + func testRecoverOnly_BaseRecoverIsNotCalledAfterRecoverOnlyExecutes() { + let x = expectation(description: #file + #function) + + Promise(error: Error.dummy).cancellize().recover(only: Error.dummy) { _ in + return Promise.value(1) + }.recover { _ in + return Promise(error: Error.dummy) + }.done { _ in + x.fulfill() + }.catch { _ in + XCTFail() + x.fulfill() + } + + wait(for: [x], timeout: 5) + } + + func testRecoverOnly_Object_DoesNotReturnSelf() { + let x = expectation(description: #file + #function) + var promise: CancellablePromise! + promise = Promise(error: Error.dummy).cancellize().recover(only: Error.dummy) { _ -> CancellablePromise in + return promise + } + promise.catch { err in + if case PMKError.returnedSelf = err { + x.fulfill() + } + } + + wait(for: [x], timeout: 5) + } + + func testRecoverOnly_Type_DoesNotReturnSelf() { + let x = expectation(description: #file + #function) + var promise: CancellablePromise! + promise = Promise(error: Error.dummy).cancellize().recover(only: Error.self) { _ -> CancellablePromise in + return promise + } + promise.catch(policy: .allErrors) { err in + err.isCancelled ? XCTFail() : x.fulfill() + } + promise.cancel() + + wait(for: [x], timeout: 5) + } +} + +/// `Promise.recover(only:)` +extension CatchableTests { + func testRecoverOnly_Object_Void() { + let x = expectation(description: #file + #function) + + Promise(error: Error.dummy).cancellize().recover(only: Error.dummy) { _ in + return () + }.done { + x.fulfill() + }.catch { _ in + XCTFail() + x.fulfill() + } + + wait(for: [x], timeout: 5) + } + + func testRecoverOnly_Object_Void_Fufilled() { + let x = expectation(description: #file + #function) + + Promise.value(()).cancellize().recover(only: Error.dummy) { _ in + XCTFail() + x.fulfill() + }.done { + x.fulfill() + }.catch(policy: .allErrors) { + $0.isCancelled ? x.fulfill() : XCTFail() + }.cancel() + + wait(for: [x], timeout: 5) + } + + func testRecoverOnly_Object_Void_Ignored() { + let x = expectation(description: #file + #function) + + enum Foo: Swift.Error { case bar } + + Promise(error: Error.dummy).cancellize().recover(only: Foo.bar) { _ in + XCTFail() + x.fulfill() + }.done { + XCTFail() + x.fulfill() + }.catch { _ in + x.fulfill() + } + + wait(for: [x], timeout: 5) + } + + func testRecoverOnly_Type_Void() { + let x = expectation(description: #file + #function) + + Promise(error: Error.dummy).cancellize().recover(only: Error.self) { _ in }.done { + x.fulfill() + }.catch { _ in + XCTFail() + x.fulfill() + } + + wait(for: [x], timeout: 5) + } + + func testRecoverOnly_Type_Void_Fufilled() { + let x = expectation(description: #file + #function) + + Promise.value(()).cancellize().recover(only: Error.self) { _ in + XCTFail() + x.fulfill() + }.done { + x.fulfill() + }.catch(policy: .allErrors) { + $0.isCancelled ? x.fulfill() : XCTFail() + }.cancel() + + wait(for: [x], timeout: 5) + } + + func testRecoverOnly_Type_Void_Ignored() { + let x = expectation(description: #file + #function) + + enum Foo: Swift.Error { case bar } + + Promise(error: Error.dummy).cancellize().recover(only: Foo.self) { _ in + XCTFail() + x.fulfill() + }.done { + XCTFail() + x.fulfill() + }.catch { _ in + x.fulfill() + } + + wait(for: [x], timeout: 5) + } + + func testRecoverOnly_Type_Void_Rethrow() { + let x = expectation(description: #file + #function) + + Promise(error: Error.dummy).cancellize().recover(only: Error.self) { _ in + throw Error.dummy + }.done { + XCTFail() + x.fulfill() + }.catch { _ in + x.fulfill() + } + + wait(for: [x], timeout: 5) + } + + func testRecoverOnly_Type_Void_Cancellation_Ignore() { + let x = expectation(description: #file + #function) + + Promise(error: Error.cancelled).cancellize().recover(only: Error.self) { _ in }.done { + XCTFail() + x.fulfill() + }.catch(policy: .allErrors) { _ in + x.fulfill() + } + + wait(for: [x], timeout: 5) + } +} + +private enum Error: CancellableError { + case dummy + case cancelled + + var isCancelled: Bool { + return self == Error.cancelled + } +} diff --git a/Tests/Cancel/DefaultDispatchQueueTests.swift b/Tests/Cancel/DefaultDispatchQueueTests.swift new file mode 100644 index 000000000..b94467cbd --- /dev/null +++ b/Tests/Cancel/DefaultDispatchQueueTests.swift @@ -0,0 +1,74 @@ +import class Foundation.Thread +import PromiseKit +import Dispatch +import XCTest + +private enum Error: Swift.Error { case dummy } + +class CancellableDefaultDispatchQueueTest: XCTestCase { + + let myQueue = DispatchQueue(label: "myQueue") + + override func setUp() { + // can actually only set the default queue once + // - See: PMKSetDefaultDispatchQueue + conf.Q = (myQueue, myQueue) + } + + override func tearDown() { + conf.Q = (.main, .main) + } + + func testOverrodeDefaultThenQueue() { + let ex = expectation(description: "resolving") + + let p = Promise.value(1).cancellize() + p.cancel() + p.then { _ -> CancellablePromise in + XCTFail() + XCTAssertFalse(Thread.isMainThread) + return CancellablePromise() + }.catch(policy: .allErrors) { + $0.isCancelled ? ex.fulfill() : XCTFail() + XCTAssertFalse(Thread.isMainThread) + } + + XCTAssertTrue(Thread.isMainThread) + + waitForExpectations(timeout: 5) + } + + func testOverrodeDefaultCatchQueue() { + let ex = expectation(description: "resolving") + + let p = CancellablePromise(error: Error.dummy) + p.cancel() + p.catch { _ in + ex.fulfill() + XCTAssertFalse(Thread.isMainThread) + } + + XCTAssertTrue(Thread.isMainThread) + + waitForExpectations(timeout: 5) + } + + func testOverrodeDefaultAlwaysQueue() { + let ex = expectation(description: "resolving") + let ex2 = expectation(description: "catching") + + let p = Promise.value(1).cancellize() + p.cancel() + p.ensure { + ex.fulfill() + XCTAssertFalse(Thread.isMainThread) + }.catch(policy: .allErrors) { + $0.isCancelled ? ex2.fulfill() : XCTFail() + XCTAssertFalse(Thread.isMainThread) + } + + XCTAssertTrue(Thread.isMainThread) + + waitForExpectations(timeout: 5) + } +} diff --git a/Tests/Cancel/DispatchWrapperTests.swift b/Tests/Cancel/DispatchWrapperTests.swift new file mode 100644 index 000000000..9dbe2e615 --- /dev/null +++ b/Tests/Cancel/DispatchWrapperTests.swift @@ -0,0 +1,188 @@ +import Dispatch +import PromiseKit +import XCTest + +// Exercise the whole API through DispatchQueue wrappers. The test here is really +// that everything compiles smoothly, not anything that happens at test time. + +class DispatchWrapperTests: XCTestCase { + + enum TestError: Error, Equatable { + case errorOne + case errorTwo + case errorThree + case errorFour + case errorFive + case errorSix + case errorSeven + case errorEight + } + + enum OtherError: Error, Equatable { + case errorOne + } + + func testWrappedCancellablePromiseThenableAPI() { + let ex = expectation(description: "DispatchQueue Promise API") + Promise.value(42).cancellize().then(on: .global()) { v -> Promise in + Promise.value(v + 10) + }.then(on: .global()) { v -> CancellablePromise in + Promise.value(v + 10).cancellize() + }.map(on: .global()) { v -> Int in + v + 10 + }.get(on: .global()) { + XCTAssert($0 == 72) + }.tap(on: .global()) { result in + if case let .success(x) = result { + XCTAssert(x == 72) + } else { + XCTFail() + } + }.compactMap(on: .global()) { v -> Int in + v + 10 + }.done(on: .global()) { + XCTAssert($0 == 82) + ex.fulfill() + }.catch(on: .global()) { _ in + XCTFail() + } + waitForExpectations(timeout: 5) + } + + func testWrappedCancellablePromiseRecoverAPI() { + + let ex = expectation(description: "DispatchQueue Promise recover API") + var value = 0 + Promise.value(42).cancellize().then { _ -> Promise in + throw TestError.errorOne + // Specific error + }.recover(only: TestError.errorOne, on: .global()) { _ -> Promise in + value += 1 + throw TestError.errorTwo + // Error type + }.recover(only: TestError.self, on: .global()) { error -> Promise in + XCTAssert(error == .errorTwo) + value += 10 + throw TestError.errorThree + // Any error + }.recover(on: .global()) { error -> Promise in + if let error = error as? TestError { + XCTAssert(error == TestError.errorThree) + } else { + XCTFail() + } + value += 100 + throw TestError.errorFour + // Specific error, cancellable + }.recover(only: TestError.errorFour, on: .global()) { _ -> CancellablePromise in + value += 1_000 + throw TestError.errorTwo + // Error type, cancellable + }.recover(only: TestError.self, on: .global()) { error -> CancellablePromise in + XCTAssert(error == .errorTwo) + value += 10_000 + throw TestError.errorThree + // Any error, cancellable + }.recover(on: .global()) { error -> CancellablePromise in + if let error = error as? TestError { + XCTAssert(error == TestError.errorThree) + } else { + XCTFail() + } + value += 100_000 + throw TestError.errorFour + }.map(on: .global()) { _ -> Void in + // NOP + // Non-matching specific error + }.recover(only: TestError.errorThree, on: .global()) { _ in + XCTFail() + // Specific error, void return + }.recover(only: TestError.errorFour, on: .global()) { _ -> Void in + value += 1_000_000 + throw OtherError.errorOne + // Non-matching error class, void return + }.recover(only: TestError.self, on: .global()) { error -> Void in + XCTFail() + }.recover(only: OtherError.self, on: .global()) { error in + value += 10_000_000 + throw TestError.errorFive + }.ensure(on: .global()) { + value += 100_000_000 + }.catch { error in + if let error = error as? TestError { + XCTAssert(error == TestError.errorFive) + } else { + XCTFail() + } + value += 1_000_000_000 + ex.fulfill() + } + waitForExpectations(timeout: 5) + XCTAssert(value == 1_111_111_111) + + let g: Any = Promise.value(42).cancellize().recover(on: .global()) { error in + Guarantee.value(52) + } + XCTAssert(g is CancellablePromise) + + let g2: Any = Promise().cancellize().recover(on: .global()) { error -> Void in } + XCTAssert(g2 is CancellablePromise) + } + + func testWrappedCancellablePromiseCatchAPI() { + let ex = expectation(description: "DispatchQueue Promise catch API") + Promise.value(42).cancellize().then(on: .global()) { _ -> Promise in + throw TestError.errorOne + }.catch(only: OtherError.self, on: .global()) { error in + XCTFail() + }.catch(only: TestError.errorTwo, on: .global()) { _ in + XCTFail() + }.catch(only: TestError.self, on: .global()) { error in + XCTAssert(error == .errorOne) + ex.fulfill() + }.cauterize() + waitForExpectations(timeout: 5) + } + + func testWrappedCancellablePromiseEnsureAPI() { + let ex = expectation(description: "DispatchQueue Promise ensure API") + var value = 0 + Promise.value(42).cancellize().ensure(on: .global()) { + value += 1 + }.ensureThen(on: .global()) { () -> CancellablePromise in + value += 10 + return Promise().cancellize() + }.done(on: .global()) { _ in + value += 100 + ex.fulfill() + }.cauterize() + waitForExpectations(timeout: 5) + XCTAssert(value == 111) + } + + func testWrappedCancellablePromiseSequenceAPI() { + let ex = expectation(description: "DispatchQueue Promise sequence API") + Promise.value([42, 52]).cancellize().mapValues(on: .global()) { + $0 + 10 + }.flatMapValues(on: .global()) { + [$0] + }.compactMapValues(on: .global()) { + $0 + }.thenMap(on: .global()) { v -> Promise in + Promise.value(v) + }.thenFlatMap(on: .global()) { v -> Promise<[Int]> in + Promise.value([v]) + }.filterValues(on: .global()) { v -> Bool in + v > 10 + }.firstValue(on: .global()) { v -> Bool in + v > 60 + }.map(on: .global()) { v -> [Int] in + XCTAssert(v == 62) + return [82, 72] + }.sortedValues(on: .global()).done { v in + XCTAssert(v == [72, 82]) + ex.fulfill() + }.cauterize() + waitForExpectations(timeout: 5) + } +} diff --git a/Tests/Cancel/DispatcherTests.swift b/Tests/Cancel/DispatcherTests.swift new file mode 100644 index 000000000..24ca7129c --- /dev/null +++ b/Tests/Cancel/DispatcherTests.swift @@ -0,0 +1,486 @@ +import Dispatch +import PromiseKit +import XCTest + +fileprivate let queueIDKey = DispatchSpecificKey() + +class RecordingDispatcher: Dispatcher { + + static var queueIndex = 1 + + var dispatchCount = 0 + let queue: DispatchQueue + + init() { + queue = DispatchQueue(label: "org.promisekit.testqueue \(RecordingDispatcher.queueIndex)") + RecordingDispatcher.queueIndex += 1 + } + + func dispatch(_ body: @escaping () -> Void) { + dispatchCount += 1 + queue.async(execute: body) + } + +} + +class DispatcherTests: XCTestCase { + + var dispatcher = RecordingDispatcher() + + override func setUp() { + dispatcher = RecordingDispatcher() + } + + func testDispatcherWithThrow() { + let ex = expectation(description: "Dispatcher with throw") + CancellablePromise { seal in + seal.fulfill(42) + }.map(on: dispatcher) { _ in + throw PMKError.badInput + }.catch(on: dispatcher) { _ in + ex.fulfill() + } + waitForExpectations(timeout: 5) + XCTAssertEqual(self.dispatcher.dispatchCount, 2) + } + + func testDispatchQueueSelection() { + + let ex = expectation(description: "DispatchQueue compatibility") + + let oldConf = PromiseKit.conf.D + PromiseKit.conf.D = (map: dispatcher, return: dispatcher) + + let background = DispatchQueue.global() + background.setSpecific(key: queueIDKey, value: 100) + DispatchQueue.main.setSpecific(key: queueIDKey, value: 102) + dispatcher.queue.setSpecific(key: queueIDKey, value: 103) + + Promise.value(42).cancellize().map(on: .global(), flags: .barrier) { (x: Int) -> Int in + let queueID = DispatchQueue.getSpecific(key: queueIDKey) + XCTAssertNotNil(queueID) + XCTAssertEqual(queueID!, 100) + return x + 10 + }.get(on: .global(), flags: .barrier) { _ in + }.tap(on: .global(), flags: .barrier) { _ in + }.then(on: .main, flags: []) { (x: Int) -> CancellablePromise in + XCTAssertEqual(x, 52) + let queueID = DispatchQueue.getSpecific(key: queueIDKey) + XCTAssertNotNil(queueID) + XCTAssertEqual(queueID!, 102) + return Promise.value(50).cancellize() + }.map(on: nil) { (x: Int) -> Int in + let queueID = DispatchQueue.getSpecific(key: queueIDKey) + XCTAssertNotNil(queueID) + XCTAssertEqual(queueID!, 102) + return x + 10 + }.map { (x: Int) -> Int in + XCTAssertEqual(x, 60) + let queueID = DispatchQueue.getSpecific(key: queueIDKey) + XCTAssertNotNil(queueID) + XCTAssertEqual(queueID!, 103) + return x + 10 + }.done(on: background) { + XCTAssertEqual($0, 70) + let queueID = DispatchQueue.getSpecific(key: queueIDKey) + XCTAssertNotNil(queueID) + XCTAssertEqual(queueID!, 100) + ex.fulfill() + }.cauterize() + + waitForExpectations(timeout: 5) + PromiseKit.conf.D = oldConf + + } + +#if false + // test takes > 30 seconds to fail to compile, I have no clue what this is for + // or why it has been designed to be so ridiculuously complex for the type + // checker. It is stupid. + func testMapValues() { + let ex1 = expectation(description: "DispatchQueue MapValues compatibility") + Promise.value([42, 52]).cancellize() + .then(on: .global(), flags: .barrier) { v -> Promise<[Int]> in + Promise.value(v) + }.compactMap(on: .global(), flags: .barrier) { (v: Int) -> Int in + v + }.mapValues(on: .global(), flags: .barrier) { (v: Int) -> Int in + v + 10 + }.flatMapValues(on: .global(), flags: .barrier) { (v: Int) -> [Int] in + [v + 10] + }.compactMapValues(on: .global(), flags: .barrier) { (v: Int) -> Int in + v + 10 + }.thenMap(on: .global(), flags: .barrier) { (v: Int) -> CancellablePromise in + Promise.value(v + 10).cancellize() + }.thenMap(on: .global(), flags: .barrier) { (v: Int) -> Promise in + Promise.value(v + 10) + }.thenFlatMap(on: .global(), flags: .barrier) { (v: Int) -> CancellablePromise<[Int]> in + Promise.value([v + 10]).cancellize() + }.thenFlatMap(on: .global(), flags: .barrier) { (v: Int) -> Promise<[Int]> in + Promise.value([v + 10]) + }.filterValues(on: .global(), flags: .barrier) { (_: Int) in + true + }.sortedValues(on: .global(), flags: .barrier) + .firstValue(on: .global(), flags: .barrier) { (_: Int) -> Bool in + true + }.done(on: .global(), flags: .barrier) { (b: Bool) -> Void in + XCTAssertEqual(b, 112) + ex1.fulfill() + }.catch(on: .global(), flags: .barrier) { _ in + XCTFail() + } + + let ex2 = expectation(description: "DispatchQueue firstValue property") + Promise.value([42, 52]).cancellize().firstValue.done(on: .global(), flags: .barrier) { + XCTAssertEqual($0, 42) + ex2.fulfill() + }.catch(on: .global(), flags: .barrier, policy: .allErrors) { _ in + XCTFail() + } + + let ex3 = expectation(description: "DispatchQueue lastValue property") + Promise.value([42, 52]).cancellize().lastValue.done(on: .global(), flags: .barrier) { + XCTAssertEqual($0, 52) + ex3.fulfill() + }.catch(on: .global(), flags: .barrier, policy: .allErrors) { _ in + XCTFail() + } + + waitForExpectations(timeout: 5) + } +#endif + + func testRecover() { + let ex1 = expectation(description: "DispatchQueue CatchMixin recover cancellable") + Promise(error: Error.dummy).cancellize().recover(on: .global(), flags: .barrier) { _ in + Promise.value(42).cancellize() + }.ensure(on: .global(), flags: .barrier) { + }.ensureThen(on: .global(), flags: .barrier) { + Promise.value(42).asVoid().cancellize() + }.done(on: .global(), flags: .barrier) { + XCTAssertEqual($0, 42) + ex1.fulfill() + }.catch(on: .global(), flags: .barrier) { _ in + XCTFail() + } + + let ex2 = expectation(description: "DispatchQueue CatchMixin recover standard") + Promise(error: Error.dummy).cancellize().recover(on: .global(), flags: .barrier) { _ in + Promise.value(42) + }.done(on: .global(), flags: .barrier) { + XCTAssertEqual($0, 42) + ex2.fulfill() + }.catch(on: .global(), flags: .barrier) { _ in + XCTFail() + } + + let ex3 = expectation(description: "DispatchQueue CatchMixin recover void standard") + Promise(error: Error.dummy).cancellize().recover(on: .global(), flags: .barrier) { _ in + }.done(on: .global(), flags: .barrier) { + ex3.fulfill() + }.catch(on: .global(), flags: .barrier) { _ in + XCTFail() + } + + waitForExpectations(timeout: 5) + } + + func testRecoverIsCancelled() { + let ex1 = expectation(description: "DispatchQueue CatchMixin recover cancellable isCancelled") + Promise(error: Error.cancelled).cancellize().recover(on: .global(), flags: .barrier, policy: .allErrors) { _ in + Promise.value(42).cancellize() + }.ensure(on: .global(), flags: .barrier) { + }.ensureThen(on: .global(), flags: .barrier) { + Promise.value(42).asVoid().cancellize() + }.done(on: .global(), flags: .barrier) { + XCTAssertEqual($0, 42) + ex1.fulfill() + }.catch(on: .global(), flags: .barrier, policy: .allErrors) { _ in + XCTFail() + } + + let ex2 = expectation(description: "DispatchQueue CatchMixin recover standard isCancelled") + Promise(error: Error.cancelled).cancellize().recover(on: .global(), flags: .barrier, policy: .allErrors) { _ in + Promise.value(42) + }.done(on: .global(), flags: .barrier) { + XCTAssertEqual($0, 42) + ex2.fulfill() + }.catch(on: .global(), flags: .barrier, policy: .allErrors) { _ in + XCTFail() + } + + let ex3 = expectation(description: "DispatchQueue CatchMixin recover void standard isCancelled") + Promise(error: Error.cancelled).cancellize().recover(on: .global(), flags: .barrier, policy: .allErrors) { _ in + }.done(on: .global(), flags: .barrier) { + ex3.fulfill() + }.catch(on: .global(), flags: .barrier, policy: .allErrors) { _ in + XCTFail() + } + + waitForExpectations(timeout: 5) + } + + func testCatchOnly() { + let ex1 = expectation(description: "DispatchQueue CatchMixin catch-only") + Promise(error: Error.dummy).cancellize().done(on: .global(), flags: .barrier) { + XCTFail() + }.catch(only: Error.dummy, on: .global(), flags: .barrier) { _ in + ex1.fulfill() + }.catch(on: .global(), flags: .barrier) { _ in + XCTFail() + } + + let ex2 = expectation(description: "DispatchQueue CatchMixin catch-type") + Promise(error: Error.dummy).cancellize().done(on: .global(), flags: .barrier) { + XCTFail() + }.catch(only: Error.self, on: .global(), flags: .barrier) { _ in + ex2.fulfill() + }.catch(on: .global(), flags: .barrier) { _ in + XCTFail() + } + + let ex3 = expectation(description: "DispatchQueue CascadingFinalizer catch") + Promise(error: Error.dummy).cancellize().done(on: .global(), flags: .barrier) { + XCTFail() + }.catch(only: Error.cancelled, on: .global(), flags: .barrier) { _ in + XCTFail() + }.catch(on: .global(), flags: .barrier) { _ in + ex3.fulfill() + } + + let ex4 = expectation(description: "DispatchQueue CascadingFinalizer catch-only") + Promise(error: Error.dummy).cancellize().done(on: .global(), flags: .barrier) { + XCTFail() + }.catch(only: Error.cancelled, on: .global(), flags: .barrier) { _ in + XCTFail() + }.catch(only: Error.dummy, on: .global(), flags: .barrier) { _ in + ex4.fulfill() + }.catch(on: .global(), flags: .barrier) { _ in + XCTFail() + } + + let ex5 = expectation(description: "DispatchQueue CascadingFinalizer catch-type") + Promise(error: Error.dummy).cancellize().done(on: .global(), flags: .barrier) { + XCTFail() + }.catch(only: Error.cancelled, on: .global(), flags: .barrier) { _ in + XCTFail() + }.catch(only: Error.self, on: .global(), flags: .barrier) { _ in + ex5.fulfill() + }.catch(on: .global(), flags: .barrier) { _ in + XCTFail() + } + + waitForExpectations(timeout: 5) + } + + func testCatchOnlyIsCancelled() { + let ex1 = expectation(description: "DispatchQueue CatchMixin catch-only isCancelled") + Promise(error: Error.cancelled).cancellize().done(on: .global(), flags: .barrier) { + XCTFail() + }.catch(only: Error.cancelled, on: .global(), flags: .barrier) { _ in + ex1.fulfill() + }.catch(on: .global(), flags: .barrier, policy: .allErrors) { _ in + XCTFail() + } + + let ex2 = expectation(description: "DispatchQueue CatchMixin catch-type isCancelled") + Promise(error: Error.cancelled).cancellize().done(on: .global(), flags: .barrier) { + XCTFail() + }.catch(only: Error.self, on: .global(), flags: .barrier, policy: .allErrors) { _ in + ex2.fulfill() + }.catch(on: .global(), flags: .barrier, policy: .allErrors) { _ in + XCTFail() + } + + let ex3 = expectation(description: "DispatchQueue CascadingFinalizer catch isCancelled") + Promise(error: Error.cancelled).cancellize().done(on: .global(), flags: .barrier) { + XCTFail() + }.catch(only: Error.cancelled, on: .global(), flags: .barrier) { _ in + ex3.fulfill() + }.catch(on: .global(), flags: .barrier, policy: .allErrors) { _ in + XCTFail() + } + + let ex4 = expectation(description: "DispatchQueue CascadingFinalizer catch-only isCancelled") + Promise(error: Error.cancelled).cancellize().done(on: .global(), flags: .barrier) { + XCTFail() + }.catch(only: Error.dummy, on: .global(), flags: .barrier) { _ in + XCTFail() + }.catch(only: Error.cancelled, on: .global(), flags: .barrier) { _ in + ex4.fulfill() + }.catch(on: .global(), flags: .barrier, policy: .allErrors) { _ in + XCTFail() + } + + let ex5 = expectation(description: "DispatchQueue CascadingFinalizer catch-type isCancelled") + Promise(error: Error.cancelled).cancellize().done(on: .global(), flags: .barrier) { + XCTFail() + }.catch(only: Error.dummy, on: .global(), flags: .barrier) { _ in + XCTFail() + }.catch(only: Error.self, on: .global(), flags: .barrier, policy: .allErrors) { _ in + ex5.fulfill() + }.catch(on: .global(), flags: .barrier, policy: .allErrors) { _ in + XCTFail() + } + + waitForExpectations(timeout: 5) + } + + func testRecoverOnly() { + let ex1 = expectation(description: "DispatchQueue CatchMixin recover-only cancellable") + Promise(error: Error.dummy).cancellize().recover(only: Error.dummy, on: .global(), flags: .barrier) { _ in + Promise.value(42).cancellize() + }.done(on: .global(), flags: .barrier) { + XCTAssertEqual($0, 42) + ex1.fulfill() + }.catch(on: .global(), flags: .barrier) { _ in + XCTFail() + } + + let ex2 = expectation(description: "DispatchQueue CatchMixin recover-only standard") + Promise(error: Error.dummy).cancellize().recover(only: Error.dummy, on: .global(), flags: .barrier) { _ in + Promise.value(42) + }.done(on: .global(), flags: .barrier) { + XCTAssertEqual($0, 42) + ex2.fulfill() + }.catch(on: .global(), flags: .barrier) { _ in + XCTFail() + } + + let ex3 = expectation(description: "DispatchQueue CatchMixin recover-type cancellable") + Promise(error: Error.dummy).cancellize().recover(only: Error.self, on: .global(), flags: .barrier) { _ in + Promise.value(42).cancellize() + }.done(on: .global(), flags: .barrier) { + XCTAssertEqual($0, 42) + ex3.fulfill() + }.catch(on: .global(), flags: .barrier) { _ in + XCTFail() + } + + let ex4 = expectation(description: "DispatchQueue CatchMixin recover-type standard") + Promise(error: Error.dummy).cancellize().recover(only: Error.self, on: .global(), flags: .barrier) { _ in + Promise.value(42) + }.done(on: .global(), flags: .barrier) { + XCTAssertEqual($0, 42) + ex4.fulfill() + }.catch(on: .global(), flags: .barrier) { _ in + XCTFail() + } + + let ex5 = expectation(description: "DispatchQueue CatchMixin recover-only-void cancellable") + Promise(error: Error.dummy).cancellize().recover(only: Error.dummy, on: .global(), flags: .barrier) { _ in + }.done(on: .global(), flags: .barrier) { + ex5.fulfill() + }.catch(on: .global(), flags: .barrier) { _ in + XCTFail() + } + + let ex6 = expectation(description: "DispatchQueue CatchMixin recover-type-void standard") + Promise(error: Error.dummy).cancellize().recover(only: Error.self, on: .global(), flags: .barrier) { _ in + }.done(on: .global(), flags: .barrier) { + ex6.fulfill() + }.catch(on: .global(), flags: .barrier) { _ in + XCTFail() + } + + waitForExpectations(timeout: 5) + } + + func testRecoverOnlyIsCancelled() { + let ex1 = expectation(description: "DispatchQueue CatchMixin recover-only cancellable isCancelled") + Promise(error: Error.cancelled).cancellize().recover(only: Error.cancelled, on: .global(), flags: .barrier) { _ in + Promise.value(42).cancellize() + }.done(on: .global(), flags: .barrier) { + XCTAssertEqual($0, 42) + ex1.fulfill() + }.catch(on: .global(), flags: .barrier) { _ in + XCTFail() + } + + let ex2 = expectation(description: "DispatchQueue CatchMixin recover-only standard isCancelled") + Promise(error: Error.cancelled).cancellize().recover(only: Error.cancelled, on: .global(), flags: .barrier) { _ in + Promise.value(42) + }.done(on: .global(), flags: .barrier) { + XCTAssertEqual($0, 42) + ex2.fulfill() + }.catch(on: .global(), flags: .barrier) { _ in + XCTFail() + } + + let ex3 = expectation(description: "DispatchQueue CatchMixin recover-type cancellable isCancelled") + Promise(error: Error.cancelled).cancellize().recover(only: Error.self, on: .global(), flags: .barrier, policy: .allErrors) { _ in + Promise.value(42).cancellize() + }.done(on: .global(), flags: .barrier) { + XCTAssertEqual($0, 42) + ex3.fulfill() + }.catch(on: .global(), flags: .barrier) { _ in + XCTFail() + } + + let ex4 = expectation(description: "DispatchQueue CatchMixin recover-type standard isCancelled") + Promise(error: Error.cancelled).cancellize().recover(only: Error.self, on: .global(), flags: .barrier, policy: .allErrors) { _ in + Promise.value(42) + }.done(on: .global(), flags: .barrier) { + XCTAssertEqual($0, 42) + ex4.fulfill() + }.catch(on: .global(), flags: .barrier) { _ in + XCTFail() + } + + let ex5 = expectation(description: "DispatchQueue CatchMixin recover-only-void cancellable isCancelled") + Promise(error: Error.cancelled).cancellize().recover(only: Error.cancelled, on: .global(), flags: .barrier) { _ in + }.done(on: .global(), flags: .barrier) { + ex5.fulfill() + }.catch(on: .global(), flags: .barrier) { _ in + XCTFail() + } + + let ex6 = expectation(description: "DispatchQueue CatchMixin recover-type-void standard isCancelled") + Promise(error: Error.cancelled).cancellize().recover(only: Error.self, on: .global(), flags: .barrier, policy: .allErrors) { _ in + }.done(on: .global(), flags: .barrier) { + ex6.fulfill() + }.catch(on: .global(), flags: .barrier) { _ in + XCTFail() + } + + waitForExpectations(timeout: 20) + } + + @available(macOS 10.10, iOS 2.0, tvOS 10.0, watchOS 2.0, *) + func testDispatcherExtensionReturnsGuarantee() { + let ex = expectation(description: "Dispatcher.promise") + dispatcher.dispatch() { () -> Int in + XCTAssertFalse(Thread.isMainThread) + return 1 + }.cancellize().done { one in + XCTAssertEqual(one, 1) + ex.fulfill() + }.catch { _ in + XCTFail() + } + waitForExpectations(timeout: 5) + } + + @available(macOS 10.10, iOS 2.0, tvOS 10.0, watchOS 2.0, *) + func testDispatcherExtensionCanThrowInBody() { + let ex = expectation(description: "Dispatcher.promise") + dispatcher.dispatch() { () -> Int in + throw PMKError.badInput + }.cancellize().done { _ in + XCTFail() + }.catch { _ in + ex.fulfill() + } + waitForExpectations(timeout: 5) + } + +} + +private enum Error: CancellableError { + case dummy + case cancelled + + var isCancelled: Bool { + return self == Error.cancelled + } +} diff --git a/Tests/Cancel/ErrorTests.swift b/Tests/Cancel/ErrorTests.swift new file mode 100644 index 000000000..b97c7c8ab --- /dev/null +++ b/Tests/Cancel/ErrorTests.swift @@ -0,0 +1,12 @@ +import PromiseKit +import XCTest + +class CancellableErrorTests: XCTestCase { + func testCustomStringConvertible() { + XCTAssertNotNil(PMKError.cancelled.errorDescription) + } + + func testCustomDebugStringConvertible() { + XCTAssertFalse(PMKError.cancelled.debugDescription.isEmpty) + } +} diff --git a/Tests/Cancel/GuaranteeTests.swift b/Tests/Cancel/GuaranteeTests.swift new file mode 100644 index 000000000..8761075e9 --- /dev/null +++ b/Tests/Cancel/GuaranteeTests.swift @@ -0,0 +1,103 @@ +import PromiseKit +import XCTest + +class GuaranteeTests: XCTestCase { + func testInit() { + let ex = expectation(description: "") + Guarantee { seal in + seal(1) + }.cancellize().done { + XCTFail() + XCTAssertEqual(1, $0) + }.catch(policy: .allErrors) { + $0.isCancelled ? ex.fulfill() : XCTFail() + }.cancel() + wait(for: [ex], timeout: 5) + } + + func testWait() { + let ex = expectation(description: "") + do { + let p = after(.milliseconds(100)).cancellize().map(on: nil) { 1 } + p.cancel() + let value = try p.wait() + XCTAssertEqual(value, 1) + } catch { + error.isCancelled ? ex.fulfill() : XCTFail() + } + wait(for: [ex], timeout: 5) + } + + func testThenMap() { + let ex = expectation(description: "") + + Guarantee.value([1, 2, 3]).cancellize().thenMap { Guarantee.value($0 * 2).cancellize() } + .done { values in + XCTAssertEqual([], values) + XCTFail() + }.catch(policy: .allErrors) { + $0.isCancelled ? ex.fulfill() : XCTFail() + }.cancel() + + wait(for: [ex], timeout: 5) + } + + func testCancellable() { + var resolver: ((()) -> Void)! + + let task = DispatchWorkItem { + resolver(()) + } + + q.asyncAfter(deadline: DispatchTime.now() + 0.5, execute: task) + + let g = Guarantee(cancellable: task) { seal in + resolver = seal + } + + let ex = expectation(description: "") + firstly { + CancellablePromise(g) + }.done { + XCTFail() + }.catch(policy: .allErrors) { + $0.isCancelled ? ex.fulfill() : XCTFail("\($0)") + } .cancel() + + wait(for: [ex], timeout: 5) + } + + func testSetCancellable() { + var resolver: ((()) -> Void)! + + let task = DispatchWorkItem { + resolver(()) + } + + q.asyncAfter(deadline: DispatchTime.now() + 0.5, execute: task) + + let g = Guarantee { seal in + resolver = seal + } + g.setCancellable(task) + + let ex = expectation(description: "") + firstly { + g + }.cancellize().done { + XCTFail() + }.catch(policy: .allErrors) { + $0.isCancelled ? ex.fulfill() : XCTFail("\($0)") + } .cancel() + + wait(for: [ex], timeout: 5) + } +} + +private var q: DispatchQueue { + if #available(macOS 10.10, iOS 8.0, tvOS 9.0, watchOS 2.0, *) { + return DispatchQueue.global(qos: .default) + } else { + return DispatchQueue.global(priority: .default) + } +} diff --git a/Tests/Cancel/HangTests.swift b/Tests/Cancel/HangTests.swift new file mode 100644 index 000000000..06d6b9b4f --- /dev/null +++ b/Tests/Cancel/HangTests.swift @@ -0,0 +1,52 @@ +#if canImport(CoreFoundation) + +import PromiseKit +import XCTest + +class HangTests: XCTestCase { + func test() { + let ex = expectation(description: "block executed") + do { + let p = after(seconds: 0.02).cancellize().then { _ -> Promise in + XCTFail() + return Promise.value(1) + } + p.cancel() + let value = try hang(p) + XCTFail() + XCTAssertEqual(value, 1) + } catch { + error.isCancelled ? ex.fulfill() : XCTFail("Unexpected error") + } + waitForExpectations(timeout: 5) + } + + enum Error: Swift.Error { + case test + } + + func testError() { + var value = 0 + do { + let p = after(seconds: 0.02).cancellize().done { + XCTFail() + value = 1 + throw Error.test + } + p.cancel() + _ = try hang(p) + XCTFail() + XCTAssertEqual(value, 1) + } catch Error.test { + XCTFail() + } catch { + if !error.isCancelled { + XCTFail("Unexpected error (expected PMKError.cancelled)") + } + return + } + XCTFail("Expected error but no error was thrown") + } +} + +#endif diff --git a/Tests/Cancel/PromiseTests.swift b/Tests/Cancel/PromiseTests.swift new file mode 100644 index 000000000..4077c5f1e --- /dev/null +++ b/Tests/Cancel/PromiseTests.swift @@ -0,0 +1,272 @@ +import PromiseKit +import Dispatch +import XCTest + +class PromiseTests: XCTestCase { + func testIsPending() { + XCTAssertTrue(CancellablePromise.pending().promise.promise.isPending) + XCTAssertFalse(CancellablePromise().promise.isPending) + XCTAssertFalse(CancellablePromise(error: Error.dummy).promise.isPending) + } + + func testIsResolved() { + XCTAssertFalse(CancellablePromise.pending().promise.promise.isResolved) + XCTAssertTrue(CancellablePromise().promise.isResolved) + XCTAssertTrue(CancellablePromise(error: Error.dummy).promise.isResolved) + } + + func testIsFulfilled() { + XCTAssertFalse(CancellablePromise.pending().promise.promise.isFulfilled) + XCTAssertTrue(CancellablePromise().promise.isFulfilled) + XCTAssertFalse(CancellablePromise(error: Error.dummy).promise.isFulfilled) + } + + func testIsRejected() { + XCTAssertFalse(CancellablePromise.pending().promise.promise.isRejected) + XCTAssertTrue(CancellablePromise(error: Error.dummy).promise.isRejected) + XCTAssertFalse(CancellablePromise().promise.isRejected) + } + + @available(macOS 10.10, iOS 2.0, tvOS 10.0, watchOS 2.0, *) + func testDispatchQueueAsyncExtensionReturnsPromise() { + let ex = expectation(description: "") + + DispatchQueue.global().async(.promise) { () -> Int in + usleep(100000) + XCTAssertFalse(Thread.isMainThread) + return 1 + }.cancellize().done { one in + XCTFail() + XCTAssertEqual(one, 1) + }.catch(policy: .allErrors) { + $0.isCancelled ? ex.fulfill() : XCTFail("Error: \($0)") + }.cancel() + + waitForExpectations(timeout: 5) + } + + @available(macOS 10.10, iOS 2.0, tvOS 10.0, watchOS 2.0, *) + func testDispatchQueueAsyncExtensionCanThrowInBody() { + let ex = expectation(description: "") + + DispatchQueue.global().async(.promise) { () -> Int in + throw Error.dummy + }.cancellize().done { _ in + XCTFail() + }.catch(policy: .allErrors) { _ in + ex.fulfill() + }.cancel() + + waitForExpectations(timeout: 5) + } + + func testCustomStringConvertible() { + XCTAssertEqual(CancellablePromise.pending().promise.promise.debugDescription, "Promise.pending(handlers: 0)") + XCTAssertEqual(CancellablePromise().promise.debugDescription, "Promise<()>.success(())") + XCTAssertEqual(CancellablePromise(error: Error.dummy).promise.debugDescription, "Promise.failure(Error.dummy)") + + XCTAssertEqual("\(CancellablePromise.pending().promise.promise)", "Promise(…Int)") + XCTAssertEqual("\(Promise.value(3).cancellize().promise)", "Promise(3)") + XCTAssertEqual("\(CancellablePromise(error: Error.dummy).promise)", "Promise(dummy)") + } + + func testCannotFulfillWithError() { + + // sadly this test proves the opposite :( + // left here so maybe one day we can prevent instantiation of `CancellablePromise` + + _ = CancellablePromise { seal in + seal.fulfill(Error.dummy) + } + + _ = CancellablePromise.pending() + + _ = Promise.value(Error.dummy).cancellize() + + _ = CancellablePromise().map { Error.dummy } + } + + func testCanMakeVoidPromise() { + _ = CancellablePromise() + _ = Guarantee() + } + + enum Error: Swift.Error { + case dummy + } + + func testThrowInInitializer() { + let p = CancellablePromise { _ in + throw Error.dummy + } + p.cancel() + XCTAssertTrue(p.promise.isRejected) + guard let err = p.promise.error, case Error.dummy = err else { return XCTFail() } + } + + func testThrowInFirstly() { + let ex = expectation(description: "") + + firstly { () -> CancellablePromise in + throw Error.dummy + }.catch { + XCTAssertEqual($0 as? Error, Error.dummy) + ex.fulfill() + }.cancel() + + wait(for: [ex], timeout: 5) + } + + func testWait() throws { + let p = after(.milliseconds(100)).cancellize().then(on: nil){ Promise.value(1) } + p.cancel() + do { + _ = try p.wait() + XCTFail() + } catch { + XCTAssert(error.isCancelled) + } + + do { + let p = after(.milliseconds(100)).cancellize().map(on: nil){ throw Error.dummy } + p.cancel() + try p.wait() + XCTFail() + } catch { + XCTAssert(error.isCancelled) + } + } + + func testPipeForResolved() { + let ex = expectation(description: "") + Promise.value(1).cancellize().done { + XCTFail() + XCTAssertEqual(1, $0) + }.catch(policy: .allErrors) { + $0.isCancelled ? ex.fulfill() : XCTFail("\($0)") + }.cancel() + wait(for: [ex], timeout: 5) + } + + func testCancellable() { + var resolver: Resolver! + + let task = DispatchWorkItem { + resolver.fulfill(()) + } + + q.asyncAfter(deadline: DispatchTime.now() + 0.5, execute: task) + + let p = Promise(cancellable: task) { seal in + resolver = seal + } + + let ex = expectation(description: "") + firstly { + CancellablePromise(p) + }.done { + XCTFail() + }.catch(policy: .allErrors) { + $0.isCancelled ? ex.fulfill() : XCTFail("\($0)") + }.cancel() + + wait(for: [ex], timeout: 5) + } + + func testSetCancellable() { + var resolver: Resolver! + + let task = DispatchWorkItem { + resolver.fulfill(()) + } + + q.asyncAfter(deadline: DispatchTime.now() + 0.5, execute: task) + + var reject: ((Swift.Error) -> Void)? + let p = Promise(cancellable: task) { seal in + resolver = seal + reject = seal.reject + } + p.setCancellable(task, reject: reject) + + let ex = expectation(description: "") + firstly { + p + }.cancellize().done { + XCTFail() + }.catch(policy: .allErrors) { + $0.isCancelled ? ex.fulfill() : XCTFail("\($0)") + }.cancel() + + wait(for: [ex], timeout: 5) + } + + func testInitCancellable() { + var resolver: Resolver! + + let task = DispatchWorkItem { + resolver.fulfill(()) + } + + q.asyncAfter(deadline: DispatchTime.now() + 0.5, execute: task) + + let p = Promise { seal in + resolver = seal + } + + let ex = expectation(description: "") + firstly { + CancellablePromise(cancellable: task, promise: p, resolver: resolver) + }.done { + XCTFail() + }.catch(policy: .allErrors) { + $0.isCancelled ? ex.fulfill() : XCTFail("\($0)") + }.cancel() + + wait(for: [ex], timeout: 5) + } + + func testInitVoidCancellable() { + let task = DispatchWorkItem { } + q.asyncAfter(deadline: DispatchTime.now() + 0.5, execute: task) + + let ex = expectation(description: "") + firstly { + CancellablePromise(cancellable: task) + }.done { + XCTFail() + }.catch(policy: .allErrors) { + $0.isCancelled ? ex.fulfill() : XCTFail("\($0)") + }.cancel() + + wait(for: [ex], timeout: 5) + } + + func testBodyThrowsError() { + let task = DispatchWorkItem { } + q.asyncAfter(deadline: DispatchTime.now() + 0.5, execute: task) + + let p = Promise(cancellable: task) { seal in + throw PMKError.badInput + } + + let ex = expectation(description: "") + firstly { + CancellablePromise(p) + }.done { + XCTFail() + }.catch(policy: .allErrors) { + $0.isCancelled ? XCTFail("\($0)") : ex.fulfill() + }.cancel() + + wait(for: [ex], timeout: 5) + } +} + +private var q: DispatchQueue { + if #available(macOS 10.10, iOS 8.0, tvOS 9.0, watchOS 2.0, *) { + return DispatchQueue.global(qos: .default) + } else { + return DispatchQueue.global(priority: .default) + } +} diff --git a/Tests/Cancel/RaceTests.swift b/Tests/Cancel/RaceTests.swift new file mode 100644 index 000000000..a2900fbe1 --- /dev/null +++ b/Tests/Cancel/RaceTests.swift @@ -0,0 +1,107 @@ +import XCTest +import PromiseKit + +class RaceTests: XCTestCase { + func test1() { + let ex = expectation(description: "") + let after1 = after(.milliseconds(10)).cancellize() + let after2 = after(seconds: 1).cancellize() + race(after1.then{ Promise.value(1) }, after2.map { 2 }).done { index in + XCTFail() + XCTAssertEqual(index, 1) + }.catch(policy: .allErrors) { + $0.isCancelled ? ex.fulfill() : XCTFail() + }.cancel() + XCTAssert(after1.isCancelled) + XCTAssert(after2.isCancelled) + XCTAssert(after1.cancelAttempted) + XCTAssert(after2.cancelAttempted) + waitForExpectations(timeout: 5, handler: nil) + } + + func test2() { + let ex = expectation(description: "") + let after1 = after(seconds: 1).cancellize().map { 1 } + let after2 = after(.milliseconds(10)).cancellize().map { 2 } + race(after1, after2).done { index in + XCTFail() + XCTAssertEqual(index, 2) + }.catch(policy: .allErrors) { + $0.isCancelled ? ex.fulfill() : XCTFail() + }.cancel() + XCTAssert(after1.isCancelled) + XCTAssert(after2.isCancelled) + XCTAssert(after1.cancelAttempted) + XCTAssert(after2.cancelAttempted) + waitForExpectations(timeout: 5, handler: nil) + } + + func test1Array() { + let ex = expectation(description: "") + let promises = [after(.milliseconds(10)).cancellize().map { 1 }, after(seconds: 1).cancellize().map { 2 }] + race(promises).done { index in + XCTAssertEqual(index, 1) + ex.fulfill() + }.catch(policy: .allErrors) { + $0.isCancelled ? ex.fulfill() : XCTFail() + }.cancel() + for p in promises { + XCTAssert(p.cancelAttempted) + XCTAssert(p.isCancelled) + } + waitForExpectations(timeout: 5, handler: nil) + } + + func test2Array() { + let ex = expectation(description: "") + let after1 = after(seconds: 1).cancellize().map { 1 } + let after2 = after(.milliseconds(10)).cancellize().map { 2 } + race(after1, after2).done { index in + XCTFail() + XCTAssertEqual(index, 2) + }.catch(policy: .allErrors) { + $0.isCancelled ? ex.fulfill() : XCTFail() + }.cancel() + XCTAssert(after1.isCancelled) + XCTAssert(after2.isCancelled) + XCTAssert(after1.cancelAttempted) + XCTAssert(after2.cancelAttempted) + waitForExpectations(timeout: 5, handler: nil) + } + + func testEmptyArray() { + let ex = expectation(description: "") + let empty = [CancellablePromise]() + race(empty).catch { + guard case PMKError.badInput = $0 else { return XCTFail() } + ex.fulfill() + } + wait(for: [ex], timeout: 5) + } + + func testReject() { + let ex = expectation(description: "") + race(CancellablePromise(error: PMKError.timedOut), after(.milliseconds(10)).map{ 2 }.cancellize()).done { index in + XCTFail() + }.catch(policy: .allErrors) { + $0.isCancelled ? ex.fulfill() : XCTFail() + } + waitForExpectations(timeout: 5, handler: nil) + } + + func testCancelInner() { + let ex = expectation(description: "") + + let after1 = after(.milliseconds(10)).cancellize() + let after2 = after(seconds: 1).cancellize() + let r = race(after1.then{ Promise.value(1).cancellize() }, after2.map { 2 }) + + r.done { index in + XCTFail() + }.catch(policy: .allErrors) { + $0.isCancelled ? ex.fulfill() : XCTFail() + } + after1.cancel() + waitForExpectations(timeout: 5, handler: nil) + } +} diff --git a/Tests/Cancel/RegressionTests.swift b/Tests/Cancel/RegressionTests.swift new file mode 100644 index 000000000..22f239197 --- /dev/null +++ b/Tests/Cancel/RegressionTests.swift @@ -0,0 +1,57 @@ +import PromiseKit +import XCTest + +class RegressionTests: XCTestCase { + func testReturningPreviousPromiseWorks() { + + // regression test because we were doing this wrong + // in our A+ tests implementation for spec: 2.3.1 + + do { + let ex = expectation(description: "") + let promise1 = CancellablePromise() + promise1.cancel() + let promise2 = promise1.then(on: nil) { promise1 } + promise2.catch(on: nil, policy: .allErrors) { + ex.fulfill() + if !$0.isCancelled { + XCTFail() + } + } + wait(for: [ex], timeout: 5) + } + + do { + let ex = expectation(description: "") + let promise1 = CancellablePromise() + promise1.cancel() + let promise2 = promise1.then(on: nil) { () -> CancellablePromise in + XCTFail() + return promise1 + } + promise2.catch(on: nil, policy: .allErrors) { + ex.fulfill() + if !$0.isCancelled { + XCTFail() + } + } + wait(for: [ex], timeout: 5) + } + + do { + let ex = expectation(description: "") + enum Error: Swift.Error { case dummy } + + let promise1 = CancellablePromise(error: Error.dummy) + promise1.cancel() + let promise2 = promise1.recover(on: nil) { _ in promise1 } + promise2.catch(on: nil, policy: .allErrors) { err in + if case PMKError.returnedSelf = err { + XCTFail() + } + ex.fulfill() + } + wait(for: [ex], timeout: 5) + } + } +} diff --git a/Tests/Cancel/ResolverTests.swift b/Tests/Cancel/ResolverTests.swift new file mode 100644 index 000000000..ed279beec --- /dev/null +++ b/Tests/Cancel/ResolverTests.swift @@ -0,0 +1,338 @@ +import PromiseKit +import XCTest + +class WrapTests: XCTestCase { + fileprivate class KittenFetcher { + let value: Int? + let error: Error? + + init(value: Int?, error: Error?) { + self.value = value + self.error = error + } + + func fetchWithCompletionBlock(block: @escaping(Int?, Error?) -> Void) { + after(.milliseconds(20)).done { + block(self.value, self.error) + } + } + + func fetchWithCompletionBlock2(block: @escaping(Error?, Int?) -> Void) { + after(.milliseconds(20)).done { + block(self.error, self.value) + } + } + + func fetchWithCompletionBlock3(block: @escaping(Int, Error?) -> Void) { + after(.milliseconds(20)).done { + block(self.value ?? -99, self.error) + } + } + + func fetchWithCompletionBlock4(block: @escaping(Error?) -> Void) { + after(.milliseconds(20)).done { + block(self.error) + } + } + } + + fileprivate class CancellableKittenFetcher: Cancellable { + func cancel() { + finalizer?.cancel() + } + + var isCancelled: Bool { + return finalizer?.isCancelled ?? false + } + + let value: Int? + let error: Swift.Error? + var finalizer: CancellableFinalizer? + + init(value: Int?, error: Swift.Error?) { + self.value = value + self.error = error + } + + func fetchWithCompletionBlock(block: @escaping(Int?, Swift.Error?) -> Void) { + finalizer = after(.milliseconds(20)).cancellize().done {_ in + block(self.value, self.error) + }.catch(policy: .allErrors) { + block(nil, $0) + } + } + + func fetchWithCompletionBlock2(block: @escaping(Swift.Error?, Int?) -> Void) { + finalizer = after(.milliseconds(20)).cancellize().done { + block(self.error, self.value) + }.catch(policy: .allErrors) { + block($0, nil) + } + } + + func fetchWithCompletionBlock3(block: @escaping(Int, Swift.Error?) -> Void) { + finalizer = after(.milliseconds(20)).cancellize().done { + block(self.value ?? -99, self.error) + }.catch(policy: .allErrors) { + block(-99, $0) + } + } + + func fetchWithCompletionBlock4(block: @escaping(Swift.Error?) -> Void) { + finalizer = after(.milliseconds(20)).cancellize().done { + block(self.error) + }.catch(policy: .allErrors) { + block($0) + } + } + } + + func testSuccess() { + let ex = expectation(description: "") + let kittenFetcher = KittenFetcher(value: 2, error: nil) + CancellablePromise { seal in + kittenFetcher.fetchWithCompletionBlock(block: seal.resolve) + }.done { + XCTFail() + XCTAssertEqual($0, 2) + }.catch(policy: .allErrors) { + $0.isCancelled ? ex.fulfill() : XCTFail() + }.cancel() + waitForExpectations(timeout: 5) + } + + func testError() { + let ex = expectation(description: "") + + let kittenFetcher = KittenFetcher(value: nil, error: Error.test) + CancellablePromise { seal in + kittenFetcher.fetchWithCompletionBlock(block: seal.resolve) + }.catch(policy: .allErrors) { + $0.isCancelled ? ex.fulfill() : XCTFail() + }.cancel() + + waitForExpectations(timeout: 5) + } + + func testErrorNoDelay() { + let ex = expectation(description: "") + + CancellablePromise { seal in + seal.resolve(nil, Error.test) + }.catch(policy: .allErrors) { error in + defer { ex.fulfill() } + guard case Error.test = error else { + return XCTFail() + } + }.cancel() + + waitForExpectations(timeout: 5) + } + + func testErrorCancellableKitten() { + let ex = expectation(description: "") + + let kittenFetcher = CancellableKittenFetcher(value: nil, error: Error.test) + CancellablePromise(cancellable: kittenFetcher) { seal in + kittenFetcher.fetchWithCompletionBlock(block: seal.resolve) + }.catch(policy: .allErrors) { error in + error.isCancelled ? ex.fulfill() : XCTFail() + }.cancel() + + waitForExpectations(timeout: 5) + } + + func testInvalidCallingConvention() { + let ex = expectation(description: "") + + let kittenFetcher = KittenFetcher(value: nil, error: nil) + CancellablePromise { seal in + kittenFetcher.fetchWithCompletionBlock(block: seal.resolve) + }.catch(policy: .allErrors) { error in + error.isCancelled ? ex.fulfill() : XCTFail() + }.cancel() + + waitForExpectations(timeout: 5) + } + + func testInvalidCallingConventionCancellableKitten() { + let ex = expectation(description: "") + + let kittenFetcher = CancellableKittenFetcher(value: nil, error: nil) + CancellablePromise(cancellable: kittenFetcher) { seal in + kittenFetcher.fetchWithCompletionBlock(block: seal.resolve) + }.catch(policy: .allErrors) { (error: Swift.Error) -> Void in + error.isCancelled ? ex.fulfill() : XCTFail() + }.cancel() + + waitForExpectations(timeout: 5) + } + + func testInvertedCallingConvention() { + let ex = expectation(description: "") + let kittenFetcher = KittenFetcher(value: 2, error: nil) + CancellablePromise { seal in + kittenFetcher.fetchWithCompletionBlock2(block: seal.resolve) + }.done { + XCTFail() + XCTAssertEqual($0, 2) + }.catch(policy: .allErrors) { error in + error.isCancelled ? ex.fulfill() : XCTFail() + }.cancel() + + waitForExpectations(timeout: 5) + } + + func testInvertedCallingConventionCancellableKitten() { + let ex = expectation(description: "") + let kittenFetcher = CancellableKittenFetcher(value: 2, error: nil) + CancellablePromise(cancellable: kittenFetcher) { seal in + kittenFetcher.fetchWithCompletionBlock2(block: seal.resolve) + }.done { + XCTFail() + XCTAssertEqual($0, 2) + }.catch(policy: .allErrors) { error in + error.isCancelled ? ex.fulfill() : XCTFail() + }.cancel() + + waitForExpectations(timeout: 5) + } + + func testNonOptionalFirstParameter() { + let ex1 = expectation(description: "") + let kf1 = KittenFetcher(value: 2, error: nil) + CancellablePromise { seal in + kf1.fetchWithCompletionBlock3(block: seal.resolve) + }.done { + XCTFail() + XCTAssertEqual($0, 2) + }.catch(policy: .allErrors) { error in + error.isCancelled ? ex1.fulfill() : XCTFail() + }.cancel() + + let ex2 = expectation(description: "") + let kf2 = KittenFetcher(value: -100, error: Error.test) + CancellablePromise { seal in + kf2.fetchWithCompletionBlock3(block: seal.resolve) + }.catch(policy: .allErrors) { error in + error.isCancelled ? ex2.fulfill() : XCTFail() + }.cancel() + + wait(for: [ex1, ex2] ,timeout: 5) + } + + func testNonOptionalFirstParameterCancellableKitten() { + let ex1 = expectation(description: "") + let kf1 = CancellableKittenFetcher(value: 2, error: nil) + CancellablePromise(cancellable: kf1) { seal in + kf1.fetchWithCompletionBlock3(block: seal.resolve) + }.done { + XCTAssertEqual($0, 2) + ex1.fulfill() + }.catch(policy: .allErrors) { error in + error.isCancelled ? ex1.fulfill() : XCTFail() + }.cancel() + + let ex2 = expectation(description: "") + let kf2 = CancellableKittenFetcher(value: -100, error: Error.test) + CancellablePromise(cancellable: kf2) { seal in + kf2.fetchWithCompletionBlock3(block: seal.resolve) + }.catch(policy: .allErrors) { error in + error.isCancelled ? ex2.fulfill() : XCTFail() + }.cancel() + + wait(for: [ex1, ex2] ,timeout: 5) + } + + func testVoidCompletionValue() { + let ex1 = expectation(description: "") + let kf1 = KittenFetcher(value: nil, error: nil) + CancellablePromise { seal in + kf1.fetchWithCompletionBlock4(block: seal.resolve) + }.done(ex1.fulfill).catch(policy: .allErrors) { error in + error.isCancelled ? ex1.fulfill() : XCTFail() + }.cancel() + + let ex2 = expectation(description: "") + let kf2 = KittenFetcher(value: nil, error: Error.test) + CancellablePromise { seal in + kf2.fetchWithCompletionBlock4(block: seal.resolve) + }.catch(policy: .allErrors) { error in + error.isCancelled ? ex2.fulfill() : XCTFail() + }.cancel() + + wait(for: [ex1, ex2], timeout: 5) + } + + func testVoidCompletionValueCancellableKitten() { + let ex1 = expectation(description: "") + let kf1 = CancellableKittenFetcher(value: nil, error: nil) + CancellablePromise(cancellable: kf1) { seal in + kf1.fetchWithCompletionBlock4(block: seal.resolve) + }.done(ex1.fulfill).catch(policy: .allErrors) { error in + error.isCancelled ? ex1.fulfill() : XCTFail() + }.cancel() + + let ex2 = expectation(description: "") + let kf2 = CancellableKittenFetcher(value: nil, error: Error.test) + CancellablePromise(cancellable: kf2) { seal in + kf2.fetchWithCompletionBlock4(block: seal.resolve) + }.catch(policy: .allErrors) { error in + error.isCancelled ? ex2.fulfill() : XCTFail() + }.cancel() + + wait(for: [ex1, ex2], timeout: 5) + } + + func testIsFulfilled() { + let p1 = Promise.value(()).cancellize() + p1.cancel() + + var success1 = false + if let r1 = p1.result, case .success = r1 { + success1 = true + } + XCTAssertTrue(success1) + XCTAssertTrue(p1.isCancelled) + + let p2 = CancellablePromise(error: Error.test) + p2.cancel() + var success2 = true + if let r2 = p2.result { + if case .success = r2 { + success2 = true + } else { + success2 = false + } + } + XCTAssertFalse(success2) + XCTAssertTrue(p2.isCancelled) + } + + func testPendingPromiseDeallocated() { + + // NOTE this doesn't seem to register the `deinit` as covered :( + // BUT putting a breakpoint in the deinit CLEARLY shows it getting covered… + + class Foo { + let p = CancellablePromise.pending() + var ex: XCTestExpectation! + + deinit { + after(.milliseconds(100)).done(ex.fulfill) + } + } + + let ex = expectation(description: "") + do { + // for code coverage report for `Resolver.deinit` warning + let foo = Foo() + foo.ex = ex + } + wait(for: [ex], timeout: 5) + } +} + +private enum Error: Swift.Error { + case test +} diff --git a/Tests/Cancel/StressTests.swift b/Tests/Cancel/StressTests.swift new file mode 100644 index 000000000..dcffd80d0 --- /dev/null +++ b/Tests/Cancel/StressTests.swift @@ -0,0 +1,173 @@ +@testable import PromiseKit +import Dispatch +import XCTest + +class StressTests: XCTestCase { + func testThenDataRace() { + let e1 = expectation(description: "") + let e2 = expectation(description: "") + var errorCounter = 0 + + //will crash if then doesn't protect handlers + stressDataRace(expectation: e1, iterations: 1000, stressFunction: { promise in + promise.done { s in + XCTFail() + XCTAssertEqual("ok", s) + return + }.catch(policy: .allErrors) { + if !$0.isCancelled { + XCTFail() + } + errorCounter += 1 + if errorCounter == 1000 { + e2.fulfill() + } + }.cancel() + }, fulfill: { "ok" }) + + waitForExpectations(timeout: 5, handler: nil) + } + + @available(macOS 10.10, iOS 2.0, tvOS 10.0, watchOS 2.0, *) + func testThensAreSequentialForLongTime() { + var values = [Int]() + let ex = expectation(description: "") + var promise = DispatchQueue.global().async(.promise){ 0 }.cancellize() + let N = 1000 + for x in 1.. CancellablePromise in + values.append(y) + XCTFail() + return DispatchQueue.global().async(.promise) { x }.cancellize() + } + } + promise.done { x in + values.append(x) + XCTFail() + }.catch(policy: .allErrors) { + $0.isCancelled ? ex.fulfill() : XCTFail() + }.cancel() + + waitForExpectations(timeout: 5, handler: nil) + } + + func testZalgoDataRace() { + let e1 = expectation(description: "") + let e2 = expectation(description: "") + var errorCounter = 0 + + //will crash if zalgo doesn't protect handlers + stressDataRace(expectation: e1, iterations: 1000, stressFunction: { promise in + promise.done(on: nil) { s in + XCTAssertEqual("ok", s) + }.catch(policy: .allErrors) { + if !$0.isCancelled { + XCTFail() + } + errorCounter += 1 + if errorCounter == 1000 { + e2.fulfill() + } + }.cancel() + }, fulfill: { + return "ok" + }) + + waitForExpectations(timeout: 5, handler: nil) + } + + class StressTask: Cancellable { + init() { + isCancelled = true + } + + func cancel() { + } + + var isCancelled: Bool + } + + func testCancelContextConcurrentReadWrite() { + let e1 = expectation(description: "") + let context = CancelContext() + func consume(error: Swift.Error?) { } + + stressRace(expectation: e1, iterations: 1000, stressFactor: 1000, stressFunction: { + consume(error: context.cancelledError) + }, fulfillFunction: { + context.cancel() + }) + + waitForExpectations(timeout: 5, handler: nil) + } + + func testCancelContextConcurrentAppend() { + let e1 = expectation(description: "") + let context = CancelContext() + let promise = CancellablePromise() + let task = StressTask() + + stressRace(expectation: e1, iterations: 1000, stressFactor: 100, stressFunction: { + context.append(cancellable: task, reject: nil, thenable: promise) + }, fulfillFunction: { + context.append(cancellable: task, reject: nil, thenable: promise) + }) + + waitForExpectations(timeout: 5, handler: nil) + } + + func testCancelContextConcurrentCancel() { + let e1 = expectation(description: "") + let context = CancelContext() + let promise = CancellablePromise() + let task = StressTask() + + stressRace(expectation: e1, iterations: 500, stressFactor: 10, stressFunction: { + context.append(cancellable: task, reject: nil, thenable: promise) + }, fulfillFunction: { + context.cancel() + }) + + waitForExpectations(timeout: 5, handler: nil) + } +} + +private enum Error: Swift.Error { + case Dummy +} + +private func stressDataRace(expectation e1: XCTestExpectation, iterations: Int = 1000, stressFactor: Int = 10, stressFunction: @escaping (CancellablePromise) -> Void, fulfill f: @escaping () -> T) { + let group = DispatchGroup() + let queue = DispatchQueue(label: "the.domain.of.Zalgo", attributes: .concurrent) + + for _ in 0...pending() + + DispatchQueue.concurrentPerform(iterations: stressFactor) { _ in + stressFunction(promise) + } + + queue.async(group: group) { + seal.fulfill(f()) + } + } + + group.notify(queue: queue, execute: e1.fulfill) +} + +private func stressRace(expectation e1: XCTestExpectation, iterations: Int = 10000, stressFactor: Int = 1000, stressFunction: @escaping () -> Void, fulfillFunction: @escaping () -> Void) { + let group = DispatchGroup() + let queue = DispatchQueue(label: "the.domain.of.Zalgo", attributes: .concurrent) + + for _ in 0.. Int in + promise.cancel() + throw E.dummy + }.catch(policy: .allErrors) { + if case E.dummy = $0 {} else { + XCTFail() + } + ex.fulfill() + } + wait(for: [ex], timeout: 5) + } + + func testRejectedPromiseCompactMap() { + + enum E: Error { case dummy } + + let ex = expectation(description: "") + CancellablePromise(error: E.dummy).compactMap { + XCTFail() + }.catch(policy: .allErrors) { + if case E.dummy = $0 {} else { + XCTFail() + } + ex.fulfill() + }.cancel() + wait(for: [ex], timeout: 5) + } + + func testPMKErrorCompactMap() { + let ex = expectation(description: "") + Promise.value("a").cancellize().compactMap { + Int($0) + }.catch(policy: .allErrors) { + $0.isCancelled ? ex.fulfill() : XCTFail() + }.cancel() + wait(for: [ex], timeout: 5) + } + + func testCompactMapValues() { + let ex = expectation(description: "") + let promise = Promise.value(["1","2","a","4"]).cancellize() + promise.compactMapValues { + Int($0) + }.done { + promise.cancel() + XCTAssertEqual([1,2,4], $0) + ex.fulfill() + }.catch(policy: .allErrors) { _ in + XCTFail() + } + wait(for: [ex], timeout: 5) + } + + func testThenMap() { + let ex = expectation(description: "") + let promise = Promise.value([1,2,3,4]).cancellize() + promise.thenMap { (x: Int) -> Promise in + promise.cancel() + return Promise.value(x) // Intentionally use `Promise` rather than `CancellablePromise` + }.done { _ in + XCTFail() + }.catch(policy: .allErrors) { + $0.isCancelled ? ex.fulfill() : XCTFail() + } + wait(for: [ex], timeout: 5) + } + + func testThenFlatMap() { + let ex = expectation(description: "") + Promise.value([1,2,3,4]).cancellize().thenFlatMap { (x: Int) -> CancellablePromise<[Int]> in + XCTFail() + return Promise.value([x, x]).cancellize() + }.done { + XCTFail() + XCTAssertEqual([1,1,2,2,3,3,4,4], $0) + ex.fulfill() + }.catch(policy: .allErrors) { + $0.isCancelled ? ex.fulfill() : XCTFail() + }.cancel() + wait(for: [ex], timeout: 5) + } + + func testLastValueForEmpty() { + XCTAssertTrue(Promise.value([]).cancellize().lastValue.isRejected) + } + + func testFirstValueForEmpty() { + XCTAssertTrue(Promise.value([]).cancellize().firstValue.isRejected) + } + + func testThenOffRejected() { + // surprisingly missing in our CI, mainly due to + // extensive use of `done` in A+ tests since PMK 5 + + let ex = expectation(description: "") + CancellablePromise(error: PMKError.badInput).then { x -> Promise in + XCTFail() + return .value(x) + }.catch(policy: .allErrors) { + $0.isCancelled ? XCTFail() : ex.fulfill() + }.cancel() + wait(for: [ex], timeout: 5) + } + + func testBarrier() { + let ex = expectation(description: "") + let q = DispatchQueue(label: "\(#file):\(#line)", attributes: .concurrent) + Promise.value(1).cancellize().done(on: q, flags: .barrier) { + XCTAssertEqual($0, 1) + dispatchPrecondition(condition: .onQueueAsBarrier(q)) + ex.fulfill() + }.catch { _ in + XCTFail() + } + wait(for: [ex], timeout: 5) + } + + func testDispatchFlagsSyntax() { + let ex = expectation(description: "") + let q = DispatchQueue(label: "\(#file):\(#line)", attributes: .concurrent) + Promise.value(1).cancellize().done(on: q, flags: [.barrier, .inheritQoS]) { + XCTAssertEqual($0, 1) + dispatchPrecondition(condition: .onQueueAsBarrier(q)) + ex.fulfill() + }.catch { _ in + XCTFail() + } + wait(for: [ex], timeout: 5) + } +} diff --git a/Tests/Cancel/TimeoutTests.swift b/Tests/Cancel/TimeoutTests.swift new file mode 100644 index 000000000..d456a975a --- /dev/null +++ b/Tests/Cancel/TimeoutTests.swift @@ -0,0 +1,125 @@ +import PromiseKit +import XCTest + +class TimeoutTests: XCTestCase { + func testTimeout() { + let ex = expectation(description: "") + + race(after(seconds: 0.5).cancellize(), timeout(seconds: 0.01).cancellize()).done { + // race(cancellize(after(seconds: 0.5)), timeout(seconds: 0.01)).done { + XCTFail() + }.catch(policy: .allErrors) { + do { + throw $0 + } catch PMKError.timedOut { + ex.fulfill() + } catch { + XCTFail() + } + } + waitForExpectations(timeout: 5) + } + + func testReset() { + let ex = expectation(description: "") + let p = after(seconds: 0.5).cancellize() + race(p, timeout(seconds: 2.0).cancellize(), timeout(seconds: 0.01).cancellize()).done { + XCTFail() + }.catch(policy: .allErrors) { err in + do { + throw err + } catch PMKError.timedOut { + _ = (err as? PMKError).debugDescription + ex.fulfill() + } catch { + XCTFail() + } + } + waitForExpectations(timeout: 5) + XCTAssert(p.isCancelled) + } + + func testDoubleTimeout() { + let ex = expectation(description: "") + let p = after(seconds: 0.5).cancellize() + race(p, timeout(seconds: 0.01).cancellize(), timeout(seconds: 0.01).cancellize()).done { + XCTFail() + }.catch(policy: .allErrors) { + do { + throw $0 + } catch PMKError.timedOut { + ex.fulfill() + } catch { + XCTFail() + } + } + waitForExpectations(timeout: 5) + XCTAssert(p.isCancelled) + } + + func testNoTimeout() { + let ex = expectation(description: "") + race(after(seconds: 0.01).cancellize(), timeout(seconds: 0.5).cancellize()).then { _ -> Promise in + ex.fulfill() + return Promise.value(1) + }.catch(policy: .allErrors) { _ in + XCTFail() + } + waitForExpectations(timeout: 5) + } + + func testCancelBeforeTimeout() { + let ex = expectation(description: "") + let p = after(seconds: 0.5).cancellize() + race(p, timeout(seconds: 2).cancellize()).then { _ -> Promise in + XCTFail() + return Promise.value(1) + }.catch(policy: .allErrors) { + do { + throw $0 + } catch PMKError.cancelled { + ex.fulfill() + } catch { + XCTFail() + } + } + p.cancel() + waitForExpectations(timeout: 5) + } + + func testCancelRaceBeforeTimeout() { + let ex = expectation(description: "") + let ctxt = race(after(seconds: 0.5).cancellize(), timeout(seconds: 2).cancellize()).then { _ -> Promise in + XCTFail() + return Promise.value(1) + }.catch(policy: .allErrors) { + do { + throw $0 + } catch PMKError.cancelled { + ex.fulfill() + } catch { + XCTFail() + } + }.cancelContext + ctxt.cancel() + waitForExpectations(timeout: 5) + } + + func testMixTypes() { + let ex = expectation(description: "") + let promise1, promise2: CancellablePromise + promise1 = Promise.value("string").cancellize().asVoid() + promise2 = Promise.value(22).cancellize().asVoid() + race(promise1, promise2, + Promise.value("string").cancellize().asVoid(), + Promise.value(22).cancellize().asVoid(), + timeout(seconds: 2).cancellize()).then { thisone -> Promise in + print("\(thisone)") + ex.fulfill() + return Promise.value(1) + }.catch(policy: .allErrors) { _ in + XCTFail() + } + waitForExpectations(timeout: 5) + } +} diff --git a/Tests/Cancel/Utilities.swift b/Tests/Cancel/Utilities.swift new file mode 100644 index 000000000..228deb778 --- /dev/null +++ b/Tests/Cancel/Utilities.swift @@ -0,0 +1,50 @@ +import PromiseKit +import XCTest + +// Workaround for error with missing libswiftContacts.dylib, this import causes the +// library to be included as needed +#if os(iOS) || os(watchOS) || os(OSX) +import class Contacts.CNPostalAddress +#endif + +extension Promise { + func silenceWarning() {} +} + +extension CancellablePromise { + func silenceWarning() {} +} + +#if os(Linux) +import func CoreFoundation._CFIsMainThread + +extension Thread { + // `isMainThread` is not implemented yet in swift-corelibs-foundation. + static var isMainThread: Bool { + return _CFIsMainThread() + } +} + +extension XCTestCase { + func wait(for: [XCTestExpectation], timeout: TimeInterval, file: StaticString = #file, line: UInt = #line) { + waitForExpectations(timeout: timeout, file: file, line: Int(line)) + } +} + +#endif + +#if os(Linux) || os(Windows) +extension XCTestExpectation { + func fulfill() { + fulfill(#file, line: #line) + } +} +#endif + +#if os(Windows) +import class Foundation.Thread + +func usleep(_ us: UInt32) { + Thread.sleep(forTimeInterval: Double(us) / 1_000_000.0) +} +#endif diff --git a/Tests/Cancel/ValueTests.swift b/Tests/Cancel/ValueTests.swift new file mode 100644 index 000000000..1fbb2739b --- /dev/null +++ b/Tests/Cancel/ValueTests.swift @@ -0,0 +1,139 @@ +import XCTest +import PromiseKit + +class ValueTests: XCTestCase { + func testValueContext() { + let exComplete = expectation(description: "after completes") + Promise.value("hi").cancellize().done { _ in + XCTFail("value not cancelled") + }.catch(policy: .allErrors) { error in + error.isCancelled ? exComplete.fulfill() : XCTFail("error: \(error)") + }.cancel() + + wait(for: [exComplete], timeout: 5) + } + + func testValueDone() { + let exComplete = expectation(description: "after completes") + Promise.value("hi").cancellize().done { _ in + XCTFail("value not cancelled") + }.catch(policy: .allErrors) { error in + error.isCancelled ? exComplete.fulfill() : XCTFail("error: \(error)") + }.cancel() + + wait(for: [exComplete], timeout: 5) + } + + func testValueThen() { + let exComplete = expectation(description: "after completes") + + Promise.value("hi").cancellize().then { (_: String) -> Promise in + XCTFail("value not cancelled") + return Promise.value("bye") + }.done { _ in + XCTFail("value not cancelled") + }.catch(policy: .allErrors) { error in + error.isCancelled ? exComplete.fulfill() : XCTFail("error: \(error)") + }.cancel() + + wait(for: [exComplete], timeout: 5) + } + + func testFirstlyValueDone() { + let exComplete = expectation(description: "after completes") + + firstly { + Promise.value("hi") + }.cancellize().done { _ in + XCTFail("value not cancelled") + }.catch(policy: .allErrors) { error in + error.isCancelled ? exComplete.fulfill() : XCTFail("error: \(error)") + }.cancel() + + wait(for: [exComplete], timeout: 5) + } + + func testFirstlyThenValueDone() { + let exComplete = expectation(description: "after completes") + + firstly { + Promise.value("hi").cancellize() + }.then { (_: String) -> CancellablePromise in + XCTFail("'hi' not cancelled") + return Promise.value("there").cancellize() + }.done { _ in + XCTFail("'there' not cancelled") + }.catch(policy: .allErrors) { error in + error.isCancelled ? exComplete.fulfill() : XCTFail("error: \(error)") + }.cancel() + + wait(for: [exComplete], timeout: 5) + } + + func testFirstlyValueDifferentContextDone() { + let exComplete = expectation(description: "after completes") + + let p = firstly { + return Promise.value("hi") + }.cancellize().done { _ in + XCTFail("value not cancelled") + }.catch(policy: .allErrors) { error in + error.isCancelled ? exComplete.fulfill() : XCTFail("error: \(error)") + } + p.cancel() + + wait(for: [exComplete], timeout: 5) + } + + func testFirstlyValueDoneDifferentContext() { + let exComplete = expectation(description: "after completes") + + firstly { + Promise.value("hi") + }.cancellize().done { _ in + XCTFail("value not cancelled") + }.catch(policy: .allErrors) { error in + error.isCancelled ? exComplete.fulfill() : XCTFail("error: \(error)") + }.cancel() + + wait(for: [exComplete], timeout: 5) + } + + func testCancelForPromise_Then() { + let exComplete = expectation(description: "after completes") + + let promise = CancellablePromise { seal in + usleep(100000) + seal.fulfill(()) + } + promise.then { () throws -> Promise in + XCTFail("then not cancelled") + return Promise.value("x") + }.done { _ in + XCTFail("done not cancelled") + }.catch(policy: .allErrors) { error in + error.isCancelled ? exComplete.fulfill() : XCTFail("error: \(error)") + }.cancel() + + wait(for: [exComplete], timeout: 5) + } + + func testCancelForPromise_ThenDone() { + let exComplete = expectation(description: "done is cancelled") + + let promise = CancellablePromise { seal in + usleep(100000) + seal.fulfill(()) + } + promise.then { _ -> CancellablePromise in + XCTFail("then not cancelled") + return Promise.value("x").cancellize() + }.done { _ in + XCTFail("done not cancelled") + }.catch(policy: .allErrors) { error in + error.isCancelled ? exComplete.fulfill() : XCTFail("error: \(error)") + }.cancel() + + wait(for: [exComplete], timeout: 5) + } +} diff --git a/Tests/Cancel/WhenConcurrentTests.swift b/Tests/Cancel/WhenConcurrentTests.swift new file mode 100644 index 000000000..30a074065 --- /dev/null +++ b/Tests/Cancel/WhenConcurrentTests.swift @@ -0,0 +1,275 @@ +import XCTest +import PromiseKit + +class WhenConcurrentTestCase_Swift: XCTestCase { + + func testWhenSucceed() { + let e = expectation(description: "") + + var numbers = (0..<42).makeIterator() + let squareNumbers = numbers.map { $0 * $0 } + + let generator = AnyIterator> { + guard let number = numbers.next() else { + return nil + } + + return after(.milliseconds(10)).cancellize().map { + return number * number + } + } + + when(fulfilled: generator, concurrently: 5).done { numbers in + if numbers == squareNumbers { + e.fulfill() + } + }.silenceWarning() + + waitForExpectations(timeout: 5, handler: nil) + } + + func testWhenCancel() { + let e = expectation(description: "") + + var numbers = (0..<42).makeIterator() + let squareNumbers = numbers.map { $0 * $0 } + + let generator = AnyIterator> { + guard let number = numbers.next() else { + return nil + } + + return after(.milliseconds(10)).cancellize().map { + XCTFail() + return number * number + } + } + + when(fulfilled: generator, concurrently: 5).done { numbers in + XCTFail() + if numbers == squareNumbers { + e.fulfill() + } + }.catch(policy: .allErrors) { + $0.isCancelled ? e.fulfill() : XCTFail() + }.cancel() + + waitForExpectations(timeout: 5, handler: nil) + } + + func testWhenEmptyGeneratorSucceed() { + let e = expectation(description: "") + + let generator = AnyIterator> { + return nil + } + + when(fulfilled: generator, concurrently: 5).done { numbers in + if numbers.count == 0 { + e.fulfill() + } + }.silenceWarning() + + waitForExpectations(timeout: 5, handler: nil) + } + + func testWhenEmptyGeneratorCancel() { + let e = expectation(description: "") + + let generator = AnyIterator> { + return nil + } + + when(fulfilled: generator, concurrently: 5).done { numbers in + if numbers.count == 0 { + e.fulfill() + } + }.catch(policy: .allErrors) { + $0.isCancelled ? e.fulfill() : XCTFail() + }.cancel() + + waitForExpectations(timeout: 5, handler: nil) + } + + func testWhenGeneratorErrorSucceed() { + enum LocalError: Error { + case Unknown + case DivisionByZero + } + + let expectedErrorIndex = 42 + let expectedError = LocalError.DivisionByZero + + let e = expectation(description: "") + + var numbers = (-expectedErrorIndex..> { + guard let number = numbers.next() else { + return nil + } + + return after(.milliseconds(10)).cancellize().then { _ -> Promise in + if number != 0 { + return Promise(error: expectedError) + } else { + return Promise.value(100500 / number) + } + } + } + + when(fulfilled: generator, concurrently: 3).catch { error in + guard let error = error as? LocalError else { + return + } + guard case .DivisionByZero = error else { + return + } + e.fulfill() + } + + waitForExpectations(timeout: 5, handler: nil) + } + + func testWhenGeneratorErrorCancel() { + enum LocalError: Error { + case Unknown + case DivisionByZero + } + + let expectedErrorIndex = 42 + let expectedError = LocalError.DivisionByZero + + let e = expectation(description: "") + + var numbers = (-expectedErrorIndex..> { + guard let number = numbers.next() else { + return nil + } + + return after(.milliseconds(10)).cancellize().then { _ -> CancellablePromise in + if number != 0 { + return CancellablePromise(error: expectedError) + } else { + return Promise.value(100500 / number).cancellize() + } + } + } + + when(fulfilled: generator, concurrently: 3).catch(policy: .allErrors) { error in + error.isCancelled ? e.fulfill() : XCTFail() + }.cancel() + + waitForExpectations(timeout: 5, handler: nil) + } + + func testWhenConcurrencySucceed() { + let expectedConcurrently = 4 + var currentConcurrently = 0 + var maxConcurrently = 0 + + let e = expectation(description: "") + + var numbers = (0..<42).makeIterator() + + let generator = AnyIterator> { + currentConcurrently += 1 + maxConcurrently = max(maxConcurrently, currentConcurrently) + + guard let number = numbers.next() else { + return nil + } + + return after(.milliseconds(10)).cancellize().then(on: .main) { _ -> Promise in + currentConcurrently -= 1 + return Promise.value(number * number) + } + } + + when(fulfilled: generator, concurrently: expectedConcurrently).done { _ in + XCTAssertEqual(expectedConcurrently, maxConcurrently) + e.fulfill() + }.silenceWarning() + + waitForExpectations(timeout: 5) + } + + func testWhenConcurrencyCancel() { + let expectedConcurrently = 4 + var currentConcurrently = 0 + var maxConcurrently = 0 + + let e = expectation(description: "") + + var numbers = (0..<42).makeIterator() + + let generator = AnyIterator> { + currentConcurrently += 1 + maxConcurrently = max(maxConcurrently, currentConcurrently) + + guard let number = numbers.next() else { + return nil + } + + return after(.milliseconds(10)).cancellize().then(on: .main) { _ -> Promise in + currentConcurrently -= 1 + return Promise.value(number * number) + } + } + + when(fulfilled: generator, concurrently: expectedConcurrently).done { _ in + XCTFail() + XCTAssertEqual(expectedConcurrently, maxConcurrently) + e.fulfill() + }.catch(policy: .allErrors) { + $0.isCancelled ? e.fulfill() : XCTFail() + }.cancel() + + waitForExpectations(timeout: 5) + } + + func testWhenConcurrencyLessThanZero() { + let generator = AnyIterator> { XCTFail(); return nil } + + let p1 = when(fulfilled: generator, concurrently: 0) + let p2 = when(fulfilled: generator, concurrently: -1) + p1.cancel() + p2.cancel() + + guard let e1 = p1.error else { return XCTFail() } + guard let e2 = p2.error else { return XCTFail() } + guard case PMKError.badInput = e1 else { return XCTFail() } + guard case PMKError.badInput = e2 else { return XCTFail() } + } + + func testStopsDequeueingOnceRejected() { + let ex = expectation(description: "") + enum Error: Swift.Error { case dummy } + + var x: UInt = 0 + let generator = AnyIterator> { + x += 1 + switch x { + case 0: + fatalError() + case 1: + return CancellablePromise() + case 2: + return CancellablePromise(error: Error.dummy) + case _: + XCTFail() + return nil + } + } + + when(fulfilled: generator, concurrently: 1).done { + XCTFail("\($0)") + }.catch(policy: .allErrors) { + $0.isCancelled ? XCTFail() : ex.fulfill() + }.cancel() + + waitForExpectations(timeout: 5) + } +} diff --git a/Tests/Cancel/WhenResolvedTests.swift b/Tests/Cancel/WhenResolvedTests.swift new file mode 100644 index 000000000..6be9f6295 --- /dev/null +++ b/Tests/Cancel/WhenResolvedTests.swift @@ -0,0 +1,69 @@ +// Created by Austin Feight on 3/19/16. +// Copyright © 2016 Max Howell. All rights reserved. + +import PromiseKit +import XCTest + +class JoinTests: XCTestCase { + func testImmediates() { + let successPromise = CancellablePromise() + + var joinFinished = false + when(resolved: successPromise).done(on: nil) { _ in joinFinished = true }.cancel() + XCTAssert(joinFinished, "Join immediately finishes on fulfilled promise") + + let promise2 = Promise.value(2) + let promise3: CancellablePromise = Promise.value(3).cancellize() + let promise4 = Promise.value(4) + var join2Finished = false + when(resolved: CancellablePromise(promise2), promise3, CancellablePromise(promise4)).done(on: nil) { _ in join2Finished = true }.cancel() + XCTAssert(join2Finished, "Join immediately finishes on fulfilled promises") + } + + func testFulfilledAfterAllResolve() { + let (promise1, seal1) = CancellablePromise.pending() + let (promise2, seal2) = Promise.pending() + let (promise3, seal3) = CancellablePromise.pending() + + var finished = false + let promise = when(resolved: promise1, CancellablePromise(promise2), promise3).done(on: nil) { _ in finished = true } + XCTAssertFalse(finished, "Not all promises have resolved") + + seal1.fulfill(()) + XCTAssertFalse(finished, "Not all promises have resolved") + + seal2.fulfill(()) + XCTAssertFalse(finished, "Not all promises have resolved") + + seal3.fulfill(()) + promise.cancel() + XCTAssert(finished, "All promises have resolved") + } + + func testCancelledAfterAllResolve() { + let (promise1, seal1) = CancellablePromise.pending() + let (promise2, seal2) = Promise.pending() + let (promise3, seal3) = CancellablePromise.pending() + + var cancelled = false + let ex = expectation(description: "") + let cp2 = CancellablePromise(promise2) + when(resolved: promise1, cp2, promise3).done(on: nil) { _ in + XCTFail() + }.catch(policy: .allErrors) { + cancelled = $0.isCancelled + cancelled ? ex.fulfill() : XCTFail() + }.cancel() + + seal1.fulfill(()) + seal2.fulfill(()) + seal3.fulfill(()) + + waitForExpectations(timeout: 5) + + XCTAssert(cancelled, "Cancel error caught") + XCTAssert(promise1.isCancelled, "Promise 1 cancelled") + XCTAssert(cp2.isCancelled, "Promise 2 cancelled") + XCTAssert(promise3.isCancelled, "Promise 3 cancelled") + } +} diff --git a/Tests/Cancel/WhenTests.swift b/Tests/Cancel/WhenTests.swift new file mode 100644 index 000000000..ecf512e4c --- /dev/null +++ b/Tests/Cancel/WhenTests.swift @@ -0,0 +1,348 @@ +import PromiseKit +import Dispatch +import XCTest + +class WhenTests: XCTestCase { + + func testEmpty() { + let e1 = expectation(description: "") + let promises: [CancellablePromise] = [] + when(fulfilled: promises).done { _ in + XCTFail() + }.catch(policy: .allErrors) { + $0.isCancelled ? e1.fulfill() : XCTFail() + }.cancel() + + let e2 = expectation(description: "") + when(resolved: promises).done { _ in + XCTFail() + e2.fulfill() + }.catch(policy: .allErrors) { + $0.isCancelled ? e2.fulfill() : XCTFail() + }.cancel() + + wait(for: [e1, e2], timeout: 5) + } + + func testInt() { + let e1 = expectation(description: "") + let p1 = Promise.value(1).cancellize() + let p2 = Promise.value(2).cancellize() + let p3 = Promise.value(3).cancellize() + let p4 = Promise.value(4).cancellize() + + when(fulfilled: [p1, p2, p3, p4]).done { _ in + XCTFail() + }.catch(policy: .allErrors) { + $0.isCancelled ? e1.fulfill() : XCTFail() + }.cancel() + waitForExpectations(timeout: 5, handler: nil) + } + + func testIntAlt() { + let e1 = expectation(description: "") + let p1 = Promise.value(1).cancellize() + let p2 = Promise.value(2).cancellize() + let p3 = Promise.value(3).cancellize() + let p4 = Promise.value(4).cancellize() + + when(fulfilled: p1, p2, p3, p4).done { _ in + XCTFail() + }.catch(policy: .allErrors) { + $0.isCancelled ? e1.fulfill() : XCTFail() + }.cancel() + waitForExpectations(timeout: 5, handler: nil) + } + + func testDoubleTupleSucceed() { + let e1 = expectation(description: "") + let p1 = Promise.value(1).cancellize() + let p2 = Promise.value("abc").cancellize() + cancellableWhen(fulfilled: p1, p2).done{ x, y in + XCTAssertEqual(x, 1) + XCTAssertEqual(y, "abc") + e1.fulfill() + }.silenceWarning() + waitForExpectations(timeout: 5, handler: nil) + } + + func testDoubleTupleCancel() { + let e1 = expectation(description: "") + let p1 = Promise.value(1).cancellize() + let p2 = Promise.value("abc").cancellize() + cancellableWhen(fulfilled: p1, p2).done{ _, _ in + XCTFail() + }.catch(policy: .allErrors) { + $0.isCancelled ? e1.fulfill() : XCTFail() + }.cancel() + waitForExpectations(timeout: 5, handler: nil) + } + + func testTripleTuple() { + let e1 = expectation(description: "") + let p1 = Promise.value(1).cancellize() + let p2 = Promise.value("abc").cancellize() + let p3 = Promise.value(1.0).cancellize() + cancellableWhen(fulfilled: p1, p2, p3).done { _, _, _ in + XCTFail() + }.catch(policy: .allErrors) { + $0.isCancelled ? e1.fulfill() : XCTFail() + }.cancel() + waitForExpectations(timeout: 5, handler: nil) + } + + func testQuadrupleTuple() { + let e1 = expectation(description: "") + let p1 = Promise.value(1).cancellize() + let p2 = Promise.value("abc").cancellize() + let p3 = Promise.value(1.0).cancellize() + let p4 = Promise.value(true).cancellize() + cancellableWhen(fulfilled: p1, p2, p3, p4).done { _, _, _, _ in + XCTFail() + }.catch(policy: .allErrors) { + $0.isCancelled ? e1.fulfill() : XCTFail() + }.cancel() + waitForExpectations(timeout: 5, handler: nil) + } + + func testQuintupleTuple() { + let e1 = expectation(description: "") + let p1 = Promise.value(1).cancellize() + let p2 = Promise.value("abc").cancellize() + let p3 = Promise.value(1.0).cancellize() + let p4 = Promise.value(true).cancellize() + let p5 = Promise.value("a" as Character).cancellize() + cancellableWhen(fulfilled: p1, p2, p3, p4, p5).done { _, _, _, _, _ in + XCTFail() + }.catch(policy: .allErrors) { + $0.isCancelled ? e1.fulfill() : XCTFail() + }.cancel() + waitForExpectations(timeout: 5, handler: nil) + } + + func testVoid() { + let e1 = expectation(description: "") + let p1 = Promise.value(1).cancellize().done { _ in } + let p2 = Promise.value(2).cancellize().done { _ in } + let p3 = Promise.value(3).cancellize().done { _ in } + let p4 = Promise.value(4).cancellize().done { _ in } + + when(fulfilled: p1, p2, p3, p4).done { + XCTFail() + }.catch(policy: .allErrors) { + $0.isCancelled ? e1.fulfill() : XCTFail() + }.cancel() + + waitForExpectations(timeout: 5, handler: nil) + } + + func testRejected() { + enum Error: Swift.Error { case dummy } + + let e1 = expectation(description: "") + let p1 = after(.milliseconds(100)).cancellize().map{ true } + let p2: CancellablePromise = after(.milliseconds(200)).cancellize().map{ throw Error.dummy } + let p3 = Promise.value(false).cancellize() + + cancellableWhen(fulfilled: p1, p2, p3).catch(policy: .allErrors) { + $0.isCancelled ? e1.fulfill() : XCTFail() + }.cancel() + + waitForExpectations(timeout: 5, handler: nil) + } + + func testProgress() { + let ex = expectation(description: "") + + XCTAssertNil(Progress.current()) + + let p1 = after(.milliseconds(10)).cancellize() + let p2 = after(.milliseconds(20)).cancellize() + let p3 = after(.milliseconds(30)).cancellize() + let p4 = after(.milliseconds(40)).cancellize() + + let progress = Progress(totalUnitCount: 1) + progress.becomeCurrent(withPendingUnitCount: 1) + + when(fulfilled: p1, p2, p3, p4).done { _ in + XCTAssertEqual(progress.completedUnitCount, 1) + ex.fulfill() + }.catch(policy: .allErrors) { + $0.isCancelled ? ex.fulfill() : XCTFail() + }.cancel() + + progress.resignCurrent() + + waitForExpectations(timeout: 5, handler: nil) + } + + func testProgressDoesNotExceed100PercentSucceed() { + let ex1 = expectation(description: "") + let ex2 = expectation(description: "") + + XCTAssertNil(Progress.current()) + + let p1 = after(.milliseconds(10)).cancellize() + let p2 = after(.milliseconds(20)).cancellize().done { throw NSError(domain: "a", code: 1, userInfo: nil) } + let p3 = after(.milliseconds(30)).cancellize() + let p4 = after(.milliseconds(40)).cancellize() + + let progress = Progress(totalUnitCount: 1) + progress.becomeCurrent(withPendingUnitCount: 1) + + let promise = when(fulfilled: p1, p2, p3, p4) + + progress.resignCurrent() + + promise.catch { _ in + ex2.fulfill() + } + + var x = 0 + func finally() { + x += 1 + if x == 4 { + XCTAssertLessThanOrEqual(1, progress.fractionCompleted) + XCTAssertEqual(progress.completedUnitCount, 1) + ex1.fulfill() + } + } + + let q = DispatchQueue.main + p1.done(on: q, finally).silenceWarning() + p2.ensure(on: q, finally).silenceWarning() + p3.done(on: q, finally).silenceWarning() + p4.done(on: q, finally).silenceWarning() + + waitForExpectations(timeout: 5, handler: nil) + } + + func testProgressDoesNotExceed100PercentCancel() { + let ex1 = expectation(description: "") + let ex2 = expectation(description: "") + let ex3 = expectation(description: "") + + XCTAssertNil(Progress.current()) + + let p1 = after(.milliseconds(10)).cancellize() + let p2 = after(.milliseconds(20)).cancellize().done { throw NSError(domain: "a", code: 1, userInfo: nil) } + let p3 = after(.milliseconds(30)).cancellize() + let p4 = after(.milliseconds(40)).cancellize() + + let progress = Progress(totalUnitCount: 1) + progress.becomeCurrent(withPendingUnitCount: 1) + + let promise = when(fulfilled: p1, p2, p3, p4) + + progress.resignCurrent() + + promise.catch(policy: .allErrors) { + $0.isCancelled ? ex2.fulfill() : XCTFail() + } + + promise.cancel() + + func finally() { + XCTFail() + } + + func finallyEnsure() { + ex3.fulfill() + } + + var x = 0 + func catchall(err: Error) { + XCTAssert(err.isCancelled) + x += 1 + if x == 4 { + XCTAssertLessThanOrEqual(1, progress.fractionCompleted) + XCTAssertEqual(progress.completedUnitCount, 1) + ex1.fulfill() + } + } + + let q = DispatchQueue.main + p1.done(on: q, finally).catch(policy: .allErrors, catchall) + p2.ensure(on: q, finallyEnsure).catch(policy: .allErrors, catchall) + p3.done(on: q, finally).catch(policy: .allErrors, catchall) + p4.done(on: q, finally).catch(policy: .allErrors, catchall) + + waitForExpectations(timeout: 5, handler: nil) + } + + func testUnhandledErrorHandlerDoesNotFire() { + enum Error: Swift.Error { + case test + } + + let ex = expectation(description: "") + let p1 = CancellablePromise(error: Error.test) + let p2 = after(.milliseconds(100)).cancellize() + cancellableWhen(fulfilled: p1, p2).done{ _ in XCTFail() }.catch(policy: .allErrors) { + $0.isCancelled ? XCTFail() : ex.fulfill() + }.cancel() + + waitForExpectations(timeout: 5, handler: nil) + } + + func testUnhandledErrorHandlerDoesNotFireForStragglers() { + enum Error: Swift.Error { + case test + case straggler + } + + let ex1 = expectation(description: "") + let ex2 = expectation(description: "") + let ex3 = expectation(description: "") + + let p1 = CancellablePromise(error: Error.test) + let p2 = after(.milliseconds(100)).cancellize().done { throw Error.straggler } + let p3 = after(.milliseconds(200)).cancellize().done { throw Error.straggler } + + cancellableWhen(fulfilled: p1, p2, p3).catch(policy: .allErrors) { + $0.isCancelled ? XCTFail() : ex1.fulfill() + }.cancel() + + p2.ensure { after(.milliseconds(100)).done(ex2.fulfill) }.silenceWarning() + p3.ensure { after(.milliseconds(100)).done(ex3.fulfill) }.silenceWarning() + + waitForExpectations(timeout: 5, handler: nil) + } + + func testAllSealedRejectedFirstOneRejects() { + enum Error: Swift.Error { + case test1 + case test2 + case test3 + } + + let ex = expectation(description: "") + let p1 = CancellablePromise(error: Error.test1) + let p2 = CancellablePromise(error: Error.test2) + let p3 = CancellablePromise(error: Error.test3) + + when(fulfilled: p1, p2, p3).catch(policy: .allErrors) { + $0.isCancelled ? XCTFail() : ex.fulfill() + }.cancel() + + waitForExpectations(timeout: 5) + } + + func testGuaranteeWhen() { + let ex1 = expectation(description: "") + when(resolved: Guarantee().cancellize(), Guarantee().cancellize()).done { _ in + XCTFail() + }.catch(policy: .allErrors) { + $0.isCancelled ? ex1.fulfill() : XCTFail() + }.cancel() + + let ex2 = expectation(description: "") + when(resolved: [Guarantee().cancellize(), Guarantee().cancellize()]).done { _ in + XCTFail() + }.catch(policy: .allErrors) { + $0.isCancelled ? ex2.fulfill() : XCTFail() + }.cancel() + + wait(for: [ex1, ex2], timeout: 5) + } +} diff --git a/Tests/Cancel/ZalgoTests.swift b/Tests/Cancel/ZalgoTests.swift new file mode 100644 index 000000000..4aad62113 --- /dev/null +++ b/Tests/Cancel/ZalgoTests.swift @@ -0,0 +1,89 @@ +import XCTest +import PromiseKit + +class ZalgoTests: XCTestCase { + func test1() { + var resolved = false + Promise.value(1).cancellize().done(on: nil) { _ in + resolved = true + }.catch(policy: .allErrors) { _ in + resolved = false + }.cancel() + XCTAssertTrue(resolved) + } + + func test2() { + let p1 = Promise.value(1).cancellize().map(on: nil) { _ in + return 2 + } + p1.cancel() + XCTAssertEqual(p1.value!, 2) + + var x = 0 + + let ex = expectation(description: "") + let (p2, seal) = CancellablePromise.pending() + p2.cancel() + p2.done(on: nil) { _ in + x = 1 + }.catch(policy: .allErrors) { _ in + x = 2 + ex.fulfill() + } + XCTAssertEqual(x, 0) + + seal.fulfill(1) + waitForExpectations(timeout: 5) + XCTAssertEqual(x, 2) + } + + // returning a pending promise from its own zalgo’d then handler doesn’t hang + func test3Succeed() { + let ex = (expectation(description: ""), expectation(description: "")) + + var p1: CancellablePromise! + p1 = after(.milliseconds(100)).cancellize().then(on: nil) { _ -> CancellablePromise in + p1.cancel() + ex.0.fulfill() + return p1 + } + + p1.catch(policy: .allErrors) { err in + defer{ ex.1.fulfill() } + guard case PMKError.returnedSelf = err else { return XCTFail() } + } + + waitForExpectations(timeout: 5) + } + + // returning a pending promise from its own zalgo’d then handler doesn’t hang + func test3Cancel() { + let ex = expectation(description: "") + + var p1: CancellablePromise! + p1 = after(.milliseconds(100)).cancellize().then(on: nil) { _ -> CancellablePromise in + XCTFail() + return p1 + } + p1.cancel() + + p1.catch(policy: .allErrors) { + $0.isCancelled ? ex.fulfill() : XCTFail() + } + + waitForExpectations(timeout: 5) + } + + // return a sealed promise from its own zalgo’d then handler doesn’t hang + func test4() { + let ex = expectation(description: "") + let p1 = Promise.value(1).cancellize() + p1.then(on: nil) { _ -> CancellablePromise in + ex.fulfill() + return p1 + }.catch(policy: .allErrors) { + $0.isCancelled ? ex.fulfill() : XCTFail() + }.cancel() + waitForExpectations(timeout: 5) + } +} diff --git a/Tests/Core/AfterTests.swift b/Tests/Core/AfterTests.swift new file mode 100644 index 000000000..b44a40f59 --- /dev/null +++ b/Tests/Core/AfterTests.swift @@ -0,0 +1,34 @@ +import PromiseKit +import XCTest + +class AfterTests: XCTestCase { + func testZero() { + let ex2 = expectation(description: "") + after(seconds: 0).done(ex2.fulfill) + waitForExpectations(timeout: 5, handler: nil) + + let ex3 = expectation(description: "") + after(.seconds(0)).done(ex3.fulfill) + waitForExpectations(timeout: 5, handler: nil) + } + + func testNegative() { + let ex2 = expectation(description: "") + after(seconds: -1).done(ex2.fulfill) + waitForExpectations(timeout: 5, handler: nil) + + let ex3 = expectation(description: "") + after(.seconds(-1)).done(ex3.fulfill) + waitForExpectations(timeout: 5, handler: nil) + } + + func testPositive() { + let ex2 = expectation(description: "") + after(seconds: 1).done(ex2.fulfill) + waitForExpectations(timeout: 5, handler: nil) + + let ex3 = expectation(description: "") + after(.seconds(1)).done(ex3.fulfill) + waitForExpectations(timeout: 5, handler: nil) + } +} diff --git a/Tests/CorePromise/CancellableErrorTests.swift b/Tests/Core/CancellableErrorTests.swift similarity index 95% rename from Tests/CorePromise/CancellableErrorTests.swift rename to Tests/Core/CancellableErrorTests.swift index 3eb7212c9..1e44c98ed 100644 --- a/Tests/CorePromise/CancellableErrorTests.swift +++ b/Tests/Core/CancellableErrorTests.swift @@ -38,7 +38,7 @@ class CancellationTests: XCTestCase { expct.fulfill() } - waitForExpectations(timeout: 1) + waitForExpectations(timeout: 5) } func testRecoverWithCancellation() { @@ -62,7 +62,7 @@ class CancellationTests: XCTestCase { ex2.fulfill() } - waitForExpectations(timeout: 1) + waitForExpectations(timeout: 5) } func testFoundationBridging1() { @@ -79,7 +79,7 @@ class CancellationTests: XCTestCase { ex.fulfill() } - waitForExpectations(timeout: 1) + waitForExpectations(timeout: 5) } func testFoundationBridging2() { @@ -96,9 +96,10 @@ class CancellationTests: XCTestCase { ex.fulfill() } - waitForExpectations(timeout: 1) + waitForExpectations(timeout: 5) } + @available(watchOS 6.2, *) func testDoesntCrashSwift() { #if os(macOS) // Previously exposed a bridging crash in Swift @@ -132,14 +133,12 @@ class CancellationTests: XCTestCase { XCTAssertFalse(TestingError().isCancelled) } -#if swift(>=3.2) func testIsCancelled() { XCTAssertTrue(PMKError.cancelled.isCancelled) XCTAssertTrue(URLError.cancelled.isCancelled) XCTAssertTrue(CocoaError.cancelled.isCancelled) XCTAssertFalse(CocoaError(_nsError: NSError(domain: NSCocoaErrorDomain, code: CocoaError.Code.coderInvalidValue.rawValue)).isCancelled) } -#endif } private enum LocalError: CancellableError { diff --git a/Tests/Core/CatchableTests.swift b/Tests/Core/CatchableTests.swift new file mode 100644 index 000000000..26a75896f --- /dev/null +++ b/Tests/Core/CatchableTests.swift @@ -0,0 +1,752 @@ +import PromiseKit +import Dispatch +import XCTest + +class CatchableTests: XCTestCase { + + func testFinally() { + let finallyQueue = DispatchQueue(label: "\(#file):\(#line)", attributes: .concurrent) + + func helper(error: Error, on queue: DispatchQueue = .main, flags: DispatchWorkItemFlags? = nil) { + let ex = (expectation(description: ""), expectation(description: "")) + var x = 0 + Promise(error: error).catch(policy: .allErrors) { _ in + XCTAssertEqual(x, 0) + x += 1 + ex.0.fulfill() + }.finally(on: queue, flags: flags) { + if let flags = flags, flags.contains(.barrier) { + dispatchPrecondition(condition: .onQueueAsBarrier(queue)) + } else { + dispatchPrecondition(condition: .onQueue(queue)) + } + XCTAssertEqual(x, 1) + x += 1 + ex.1.fulfill() + } + wait(for: [ex.0, ex.1], timeout: 5) + } + + helper(error: Error.dummy) + helper(error: Error.cancelled) + helper(error: Error.dummy, on: finallyQueue) + helper(error: Error.dummy, on: finallyQueue, flags: .barrier) + } + + func testCauterize() { + let ex = expectation(description: "") + let p = Promise(error: Error.dummy) + + // cannot test specifically that this outputs to console, + // but code-coverage will note that the line is run + p.cauterize() + + p.catch { _ in + ex.fulfill() + } + wait(for: [ex], timeout: 5) + } +} + + +/// `Promise.recover` +extension CatchableTests { + func test__void_specialized_full_recover() { + + func helper(error: Swift.Error) { + let ex = expectation(description: "") + Promise(error: error).recover { _ in }.done(ex.fulfill) + wait(for: [ex], timeout: 5) + } + + helper(error: Error.dummy) + helper(error: Error.cancelled) + } + + func test__void_specialized_full_recover__fulfilled_path() { + let ex = expectation(description: "") + Promise().recover { _ in XCTFail() }.done(ex.fulfill) + wait(for: [ex], timeout: 5) + } + + func test__void_specialized_conditional_recover() { + func helper(policy: CatchPolicy, error: Swift.Error, line: UInt = #line) { + let ex = expectation(description: "") + var x = 0 + Promise(error: error).recover(policy: policy) { err in + guard x < 1 else { throw err } + x += 1 + }.done(ex.fulfill).silenceWarning() + wait(for: [ex], timeout: 5) + } + + for error in [Error.dummy as Swift.Error, Error.cancelled] { + helper(policy: .allErrors, error: error) + } + helper(policy: .allErrorsExceptCancellation, error: Error.dummy) + } + + func test__void_specialized_conditional_recover__no_recover() { + + func helper(policy: CatchPolicy, error: Error, line: UInt = #line) { + let ex = expectation(description: "") + Promise(error: error).recover(policy: policy) { err in + throw err + }.catch(policy: .allErrors) { + XCTAssertEqual(error, $0 as? Error) + ex.fulfill() + } + wait(for: [ex], timeout: 5) + } + + for error in [Error.dummy, Error.cancelled] { + helper(policy: .allErrors, error: error) + } + helper(policy: .allErrorsExceptCancellation, error: Error.dummy) + } + + func test__void_specialized_conditional_recover__ignores_cancellation_but_fed_cancellation() { + let ex = expectation(description: "") + Promise(error: Error.cancelled).recover(policy: .allErrorsExceptCancellation) { _ in + XCTFail() + }.catch(policy: .allErrors) { + XCTAssertEqual(Error.cancelled, $0 as? Error) + ex.fulfill() + } + wait(for: [ex], timeout: 5) + } + + func test__void_specialized_conditional_recover__fulfilled_path() { + let ex = expectation(description: "") + Promise().recover { _ in + XCTFail() + }.catch { _ in + XCTFail() // this `catch` to ensure we are calling the `recover` variant we think we are + }.finally { + ex.fulfill() + } + wait(for: [ex], timeout: 5) + } +} + + +/// `Promise.recover` +extension CatchableTests { + func test__full_recover() { + + func helper(error: Swift.Error) { + let ex = expectation(description: "") + Promise(error: error).recover { _ in return .value(2) }.done { + XCTAssertEqual($0, 2) + ex.fulfill() + } + wait(for: [ex], timeout: 5) + } + + helper(error: Error.dummy) + helper(error: Error.cancelled) + } + + func test__full_recover__fulfilled_path() { + let ex = expectation(description: "") + Promise.value(1).recover { _ in XCTFail(); return .value(2) }.done{ + XCTAssertEqual($0, 1) + ex.fulfill() + } + wait(for: [ex], timeout: 5) + } + + + func test__conditional_recover() { + func helper(policy: CatchPolicy, error: Swift.Error, line: UInt = #line) { + let ex = expectation(description: "") + var x = 0 + Promise(error: error).recover(policy: policy) { err -> Promise in + guard x < 1 else { throw err } + x += 1 + return .value(x) + }.done { + XCTAssertEqual($0, x) + ex.fulfill() + }.silenceWarning() + wait(for: [ex], timeout: 5) + } + + for error in [Error.dummy as Swift.Error, Error.cancelled] { + helper(policy: .allErrors, error: error) + } + helper(policy: .allErrorsExceptCancellation, error: Error.dummy) + } + + func test__conditional_recover__no_recover() { + + func helper(policy: CatchPolicy, error: Error, line: UInt = #line) { + let ex = expectation(description: "") + Promise(error: error).recover(policy: policy) { err -> Promise in + throw err + }.catch(policy: .allErrors) { + XCTAssertEqual(error, $0 as? Error) + ex.fulfill() + } + wait(for: [ex], timeout: 5) + } + + for error in [Error.dummy, Error.cancelled] { + helper(policy: .allErrors, error: error) + } + helper(policy: .allErrorsExceptCancellation, error: Error.dummy) + } + + func test__conditional_recover__ignores_cancellation_but_fed_cancellation() { + let ex = expectation(description: "") + Promise(error: Error.cancelled).recover(policy: .allErrorsExceptCancellation) { _ -> Promise in + XCTFail() + return .value(1) + }.catch(policy: .allErrors) { + XCTAssertEqual(Error.cancelled, $0 as? Error) + ex.fulfill() + } + wait(for: [ex], timeout: 5) + } + + func test__conditional_recover__fulfilled_path() { + let ex = expectation(description: "") + Promise.value(1).recover { err -> Promise in + XCTFail() + throw err + }.done { + XCTAssertEqual($0, 1) + ex.fulfill() + }.catch { _ in + XCTFail() // this `catch` to ensure we are calling the `recover` variant we think we are + } + wait(for: [ex], timeout: 5) + } + + func testEnsureThen_Error() { + let ex = expectation(description: "") + + Promise.value(1).done { + XCTAssertEqual($0, 1) + throw Error.dummy + }.ensureThen { + after(seconds: 0.01) + }.catch { + XCTAssertEqual(Error.dummy, $0 as? Error) + }.finally { + ex.fulfill() + } + + wait(for: [ex], timeout: 5) + } + + func testEnsureThen_Value() { + let ex = expectation(description: "") + + Promise.value(1).ensureThen { + after(seconds: 0.01) + }.done { + XCTAssertEqual($0, 1) + }.catch { _ in + XCTFail() + }.finally { + ex.fulfill() + } + + wait(for: [ex], timeout: 5) + } +} + +/// `Promise.catch(only:)` +extension CatchableTests { + func testCatchOnly() { + let x = expectation(description: #file + #function) + + Promise(error: Error.dummy).catch(only: Error.dummy) { _ in + x.fulfill() + }.silenceWarning() + + wait(for: [x], timeout: 5) + } + + func testCatchOnly_PatternMatch_1() { + let x = expectation(description: "Pattern match only Error.dummy") + + Promise(error: Error.dummy).catch(only: Error.dummy) { _ in + x.fulfill() + }.catch(only: Error.cancelled) { _ in + XCTFail() + x.fulfill() + }.silenceWarning() + + wait(for: [x], timeout: 5) + } + + func testCatchOnly_PatternMatch_2() { + let x = expectation(description: "Pattern match only Error.dummy") + + Promise(error: Error.dummy).catch(only: Error.cancelled) { _ in + XCTFail() + x.fulfill() + }.catch(only: Error.dummy) { _ in + x.fulfill() + }.silenceWarning() + + wait(for: [x], timeout: 5) + } + + func testCatchOnly_BaseCatchIsNotCalledAfterCatchOnlyExecutes() { + let x = expectation(description: #file + #function) + + Promise(error: Error.dummy).catch(only: Error.dummy) { _ in + x.fulfill() + }.catch { _ in + XCTFail() + x.fulfill() + } + + wait(for: [x], timeout: 5) + } + + func testCatchOnly_BaseCatchIsCalledWhenCatchOnlyDoesNotExecute() { + let x = expectation(description: #file + #function) + + Promise(error: Error.dummy).catch(only: Error.cancelled) { _ in + XCTFail() + x.fulfill() + }.catch { _ in + x.fulfill() + } + + wait(for: [x], timeout: 5) + } + + func testCatchOnly_Type() { + let x = expectation(description: #file + #function) + + Promise(error: Error.dummy).catch(only: Error.self) { _ in + x.fulfill() + }.silenceWarning() + + wait(for: [x], timeout: 5) + } + + func testCatchOnly_Type_Ignored() { + let x = expectation(description: #file + #function) + + enum Foo: Swift.Error { + case a + } + + Promise(error: Error.dummy).catch(only: Foo.self) { _ in + XCTFail() + }.catch { _ in + x.fulfill() + } + + wait(for: [x], timeout: 5) + } + + func testCatchOnly_Type_PatternMatch_1() { + let x = expectation(description: "Pattern match only Error.Type") + + Promise(error: Error.dummy).catch(only: Error.self) { _ in + x.fulfill() + }.catch(only: Error.dummy) { _ in + XCTFail() + x.fulfill() + }.silenceWarning() + + wait(for: [x], timeout: 5) + } + + func testCatchOnly_Type_PatternMatch_2() { + let x = expectation(description: "Pattern match only Error.dummy") + + Promise(error: Error.dummy).catch(only: Error.dummy) { _ in + x.fulfill() + }.catch(only: Error.self) { _ in + XCTFail() + x.fulfill() + }.silenceWarning() + + wait(for: [x], timeout: 5) + } + + func testCatchOnly_Type_BaseCatchIsNotCalledAfterCatchOnlyExecutes() { + let x = expectation(description: #file + #function) + + Promise(error: Error.dummy).catch(only: Error.self) { _ in + x.fulfill() + }.catch { _ in + XCTFail() + x.fulfill() + } + + wait(for: [x], timeout: 5) + } + + func testCatchOnly_Type_Cancellation_Ignore() { + let x = expectation(description: #file + #function) + + Promise(error: Error.cancelled).catch(only: Error.self) { _ in + XCTFail() + x.fulfill() + }.catch(policy: .allErrors) { _ in + x.fulfill() + } + + wait(for: [x], timeout: 5) + } + + func testCatchOnly_Type_Cancellation_Handle() { + let x = expectation(description: #file + #function) + + Promise(error: Error.cancelled).catch(only: Error.self, policy: .allErrors) { _ in + x.fulfill() + }.catch { _ in + XCTFail() + x.fulfill() + } + + wait(for: [x], timeout: 5) + } + + func testCatchOnly_Mixed() { + let x = expectation(description: #file + #function) + + enum Foo: Swift.Error { case bar } + + Promise(error: Foo.bar).catch(only: Error.dummy) { _ in + XCTFail() + x.fulfill() + }.catch(only: Foo.self) { _ in + x.fulfill() + }.silenceWarning() + + wait(for: [x], timeout: 5) + } +} + +/// `Promise.recover(only:)` +extension CatchableTests { + func testRecoverOnly_Object() { + let x = expectation(description: #file + #function) + + Promise(error: Error.dummy).recover(only: Error.dummy) { _ in + return Promise.value(1) + }.done { _ in + x.fulfill() + }.catch { _ in + XCTFail() + x.fulfill() + } + + wait(for: [x], timeout: 5) + } + + func testRecoverOnly_Object_Ignored() { + let x = expectation(description: #file + #function) + + Promise.value(1).recover(only: Error.dummy) { _ in + return Promise(error: Error.dummy) + }.done { _ in + x.fulfill() + }.catch { _ in + XCTFail() + x.fulfill() + } + + wait(for: [x], timeout: 5) + } + + func testRecoverOnly_Object_PatternMatch() { + let x = expectation(description: #file + #function) + + Promise(error: Error.cancelled).recover(only: Error.dummy) { _ in + return Promise.value(1) + }.done { _ in + XCTFail() + x.fulfill() + }.catch(policy: .allErrors) { _ in + x.fulfill() + } + + wait(for: [x], timeout: 5) + } + + func testRecoverOnly_Type() { + let x = expectation(description: #file + #function) + + Promise(error: Error.dummy).recover(only: Error.self) { _ in + return Promise.value(1) + }.done { _ in + x.fulfill() + }.catch { _ in + XCTFail() + x.fulfill() + } + + wait(for: [x], timeout: 5) + } + + func testRecoverOnly_Type_Ignored() { + let x = expectation(description: #file + #function) + + Promise.value(1).recover(only: Error.self) { _ in + return Promise(error: Error.dummy) + }.done { _ in + x.fulfill() + }.catch { _ in + XCTFail() + x.fulfill() + } + + wait(for: [x], timeout: 5) + } + + func testRecoverOnly_Type_PatternMatch() { + let x = expectation(description: #file + #function) + + enum Foo: Swift.Error { + case a + } + + Promise(error: Error.dummy).recover(only: Foo.self) { _ in + Promise.value(1) + }.done { _ in + XCTFail() + x.fulfill() + }.catch { _ in + x.fulfill() + } + + wait(for: [x], timeout: 5) + } + + func testRecoverOnly_Type_Cancellation_Ignore() { + let x = expectation(description: #file + #function) + + Promise(error: Error.cancelled).recover(only: Error.self) { _ in + return Promise.value(1) + }.done { _ in + XCTFail() + x.fulfill() + }.catch(policy: .allErrors) { _ in + x.fulfill() + } + + wait(for: [x], timeout: 5) + } + + func testRecoverOnly_Type_Cancellation_Handle() { + let x = expectation(description: #file + #function) + + Promise(error: Error.cancelled).recover(only: Error.self, policy: .allErrors) { _ in + return Promise.value(1) + }.done { _ in + x.fulfill() + }.catch { _ in + XCTFail() + x.fulfill() + } + + wait(for: [x], timeout: 5) + } + + func testRecoverOnly_Chaining() { + let x = expectation(description: #file + #function) + + enum Foo: Swift.Error { case bar } + + Promise(error: Error.dummy).recover(only: Foo.self) { _ in + return Promise(error: Foo.bar) + }.recover(only: Error.dummy) { _ in + return Promise.value(1) + }.done { _ in + x.fulfill() + }.catch { _ in + XCTFail() + x.fulfill() + } + + wait(for: [x], timeout: 5) + } + + func testRecoverOnly_BaseRecoverIsNotCalledAfterRecoverOnlyExecutes() { + let x = expectation(description: #file + #function) + + Promise(error: Error.dummy).recover(only: Error.dummy) { _ in + return Promise.value(1) + }.recover { _ in + return Promise(error: Error.dummy) + }.done { _ in + x.fulfill() + }.catch { _ in + XCTFail() + x.fulfill() + } + + wait(for: [x], timeout: 5) + } + + func testRecoverOnly_Object_DoesNotReturnSelf() { + let x = expectation(description: #file + #function) + var promise: Promise! + promise = Promise(error: Error.dummy).recover(only: Error.dummy) { (_) -> Promise in + return promise + } + promise.catch { err in + if case PMKError.returnedSelf = err { + x.fulfill() + } + } + + wait(for: [x], timeout: 5) + } + + func testRecoverOnly_Type_DoesNotReturnSelf() { + let x = expectation(description: #file + #function) + var promise: Promise! + promise = Promise(error: Error.dummy).recover(only: Error.self) { _ -> Promise in + return promise + } + promise.catch { err in + if case PMKError.returnedSelf = err { + x.fulfill() + } + } + + wait(for: [x], timeout: 5) + } +} + +/// `Promise.recover(only:)` +extension CatchableTests { + func testRecoverOnly_Object_Void() { + let x = expectation(description: #file + #function) + + Promise(error: Error.dummy).recover(only: Error.dummy) { _ in + return () + }.done { + x.fulfill() + }.catch { _ in + XCTFail() + x.fulfill() + } + + wait(for: [x], timeout: 5) + } + + func testRecoverOnly_Object_Void_Fufilled() { + let x = expectation(description: #file + #function) + + Promise.value(()).recover(only: Error.dummy) { _ in + XCTFail() + x.fulfill() + }.done { + x.fulfill() + }.silenceWarning() + + wait(for: [x], timeout: 5) + } + + func testRecoverOnly_Object_Void_Ignored() { + let x = expectation(description: #file + #function) + + enum Foo: Swift.Error { case bar } + + Promise(error: Error.dummy).recover(only: Foo.bar) { _ in + XCTFail() + x.fulfill() + }.done { + XCTFail() + x.fulfill() + }.catch { _ in + x.fulfill() + } + + wait(for: [x], timeout: 5) + } + + func testRecoverOnly_Type_Void() { + let x = expectation(description: #file + #function) + + Promise(error: Error.dummy).recover(only: Error.self) { _ in }.done { + x.fulfill() + }.catch { _ in + XCTFail() + x.fulfill() + } + + wait(for: [x], timeout: 5) + } + + func testRecoverOnly_Type_Void_Fufilled() { + let x = expectation(description: #file + #function) + + Promise.value(()).recover(only: Error.self) { _ in + XCTFail() + x.fulfill() + }.done { + x.fulfill() + }.silenceWarning() + + wait(for: [x], timeout: 5) + } + + func testRecoverOnly_Type_Void_Ignored() { + let x = expectation(description: #file + #function) + + enum Foo: Swift.Error { case bar } + + Promise(error: Error.dummy).recover(only: Foo.self) { _ in + XCTFail() + x.fulfill() + }.done { + XCTFail() + x.fulfill() + }.catch { _ in + x.fulfill() + } + + wait(for: [x], timeout: 5) + } + + func testRecoverOnly_Type_Void_Rethrow() { + let x = expectation(description: #file + #function) + + Promise(error: Error.dummy).recover(only: Error.self) { _ in + throw Error.dummy + }.done { + XCTFail() + x.fulfill() + }.catch { _ in + x.fulfill() + } + + wait(for: [x], timeout: 5) + } + + func testRecoverOnly_Type_Void_Cancellation_Ignore() { + let x = expectation(description: #file + #function) + + Promise(error: Error.cancelled).recover(only: Error.self) { _ in }.done { + XCTFail() + x.fulfill() + }.catch(policy: .allErrors) { _ in + x.fulfill() + } + + wait(for: [x], timeout: 5) + } +} + +private enum Error: CancellableError { + case dummy + case cancelled + + var isCancelled: Bool { + return self == Error.cancelled + } +} diff --git a/Tests/CorePromise/DefaultDispatchQueueTests.swift b/Tests/Core/DefaultDispatchQueueTests.swift similarity index 92% rename from Tests/CorePromise/DefaultDispatchQueueTests.swift rename to Tests/Core/DefaultDispatchQueueTests.swift index f9908e26a..cb0cd132a 100644 --- a/Tests/CorePromise/DefaultDispatchQueueTests.swift +++ b/Tests/Core/DefaultDispatchQueueTests.swift @@ -39,7 +39,7 @@ class PMKDefaultDispatchQueueTest: XCTestCase { XCTAssertTrue(Thread.isMainThread) - waitForExpectations(timeout: 1) + waitForExpectations(timeout: 5) } func testOverrodeDefaultCatchQueue() { @@ -52,7 +52,7 @@ class PMKDefaultDispatchQueueTest: XCTestCase { XCTAssertTrue(Thread.isMainThread) - waitForExpectations(timeout: 1) + waitForExpectations(timeout: 5) } func testOverrodeDefaultAlwaysQueue() { @@ -65,6 +65,6 @@ class PMKDefaultDispatchQueueTest: XCTestCase { XCTAssertTrue(Thread.isMainThread) - waitForExpectations(timeout: 1) + waitForExpectations(timeout: 5) } } diff --git a/Tests/Core/DispatchWrapperTests.swift b/Tests/Core/DispatchWrapperTests.swift new file mode 100644 index 000000000..fe5ed627b --- /dev/null +++ b/Tests/Core/DispatchWrapperTests.swift @@ -0,0 +1,187 @@ +import Dispatch +import PromiseKit +import XCTest + +// Exercise the whole API through DispatchQueue wrappers. The test here is really +// that everything compiles smoothly, not anything that happens at test time. + +class DispatchWrapperTests: XCTestCase { + + enum TestError: Error, Equatable { + case errorOne + case errorTwo + case errorThree + case errorFour + case errorFive + case errorSix + case errorSeven + case errorEight + } + + enum OtherError: Error, Equatable { + case errorOne + } + + func testWrappedPromiseThenableAPI() { + let ex = expectation(description: "DispatchQueue Promise API") + Promise.value(42).then(on: .global()) { + Promise.value($0 + 10) + }.map(on: .global()) { + $0 + 10 + }.get(on: .global()) { + XCTAssert($0 == 62) + }.tap(on: .global()) { result in + if case let .success(x) = result { + XCTAssert(x == 62) + } else { + XCTFail() + } + }.compactMap(on: .global()) { + $0 + 10 + }.done(on: .global()) { + XCTAssert($0 == 72) + ex.fulfill() + }.catch(on: .global()) { _ in + XCTFail() + } + waitForExpectations(timeout: 5) + } + + func testWrappedPromiseRecoverAPI() { + + let ex = expectation(description: "DispatchQueue Promise recover API") + var value = 0 + Promise.value(42).then { _ -> Promise in + throw TestError.errorOne + // Specific error + }.recover(only: TestError.errorOne, on: .global()) { error -> Promise in + value += 1 + throw TestError.errorTwo + // Error type + }.recover(only: TestError.self, on: .global()) { error -> Promise in + XCTAssert(error == .errorTwo) + value += 10 + throw TestError.errorThree + // Any error + }.recover(on: .global()) { error -> Promise in + if let error = error as? TestError { + XCTAssert(error == TestError.errorThree) + } else { + XCTFail() + } + value += 100 + throw TestError.errorFour + }.map(on: .global()) { _ -> Void in + // NOP + // Non-matching specific error + }.recover(only: TestError.errorThree, on: .global()) { error in + XCTFail() + // Specific error, void return + }.recover(only: TestError.errorFour, on: .global()) { error -> Void in + value += 1_000 + throw OtherError.errorOne + // Non-matching error class, void return + }.recover(only: TestError.self, on: .global()) { error -> Void in + XCTFail() + }.recover(only: OtherError.self, on: .global()) { error in + value += 10_000 + throw TestError.errorFive + }.ensure(on: .global()) { + value += 100_000 + }.catch { error in + if let error = error as? TestError { + XCTAssert(error == TestError.errorFive) + } else { + XCTFail() + } + value += 1_000_000 + ex.fulfill() + } + waitForExpectations(timeout: 5) + XCTAssert(value == 1_111_111) + + let g: Any = Promise.value(42).recover(on: .global()) { error in + Guarantee.value(52) + } + XCTAssert(g is Guarantee) + + let g2: Any = Promise.value(()).recover(on: .global()) { error -> Void in } + XCTAssert(g2 is Guarantee) + } + + func testWrappedPromiseCatchAPI() { + let ex = expectation(description: "DispatchQueue Promise catch API") + Promise.value(42).then(on: .global()) { _ -> Promise in + throw TestError.errorOne + }.catch(only: OtherError.self, on: .global()) { error in + XCTFail() + }.catch(only: TestError.errorTwo, on: .global()) { error in + XCTFail() + }.catch(only: TestError.self, on: .global()) { error in + XCTAssert(error == .errorOne) + ex.fulfill() + }.cauterize() + waitForExpectations(timeout: 5) + } + + func testWrappedPromiseEnsureAPI() { + let ex = expectation(description: "DispatchQueue Promise ensure API") + var value = 0 + Promise.value(42).ensure(on: .global()) { + value += 1 + }.ensureThen(on: .global()) { () -> Guarantee in + value += 10 + return Guarantee() + }.done(on: .global()) { _ in + value += 100 + ex.fulfill() + }.cauterize() + waitForExpectations(timeout: 5) + XCTAssert(value == 111) + } + + func testWrappedPromiseSequenceAPI() { + let ex = expectation(description: "DispatchQueue Promise sequence API") + Promise.value([42, 52]).mapValues(on: .global()) { + $0 + 10 + }.flatMapValues(on: .global()) { + [$0] + }.compactMapValues(on: .global()) { + $0 + }.thenMap(on: .global()) { + Promise.value($0) + }.thenFlatMap(on: .global()) { + Promise.value([$0]) + }.filterValues(on: .global()) { + $0 > 10 + }.firstValue(on: .global()) { + $0 > 60 + }.map(on: .global()) { v -> [Int] in + XCTAssert(v == 62) + return [82, 72] + }.sortedValues(on: .global()).done { v in + XCTAssert(v == [72, 82]) + ex.fulfill() + }.cauterize() + waitForExpectations(timeout: 5) + } + + func testWrappedGuaranteeAPI() { + let ex = expectation(description: "DispatchQueue Guarantee API") + Guarantee.value(42).then(on: .global()) { + Guarantee.value($0 + 10) + }.map(on: .global()) { + $0 + 10 + }.get(on: .global()) { + XCTAssert($0 == 62) + }.map { + [$0, $0] + }.thenMap(on: .global()) { + Guarantee.value($0 + 10) + }.done(on: .global()) { + XCTAssert($0 == [72, 72]) + ex.fulfill() + } + waitForExpectations(timeout: 5) + } +} diff --git a/Tests/Core/DispatcherTests.swift b/Tests/Core/DispatcherTests.swift new file mode 100644 index 000000000..5c9038038 --- /dev/null +++ b/Tests/Core/DispatcherTests.swift @@ -0,0 +1,234 @@ +import Dispatch +import PromiseKit +import XCTest + +fileprivate let queueIDKey = DispatchSpecificKey() + +class RecordingDispatcher: Dispatcher { + + static var queueIndex = 1 + + var dispatchCount = 0 + let queue: DispatchQueue + + init() { + queue = DispatchQueue(label: "org.promisekit.testqueue \(RecordingDispatcher.queueIndex)") + RecordingDispatcher.queueIndex += 1 + } + + func dispatch(_ body: @escaping () -> Void) { + dispatchCount += 1 + queue.async(execute: body) + } + +} + +class DispatcherTests: XCTestCase { + + var dispatcher = RecordingDispatcher() + var dispatcherB = RecordingDispatcher() + + override func setUp() { + dispatcher = RecordingDispatcher() + dispatcherB = RecordingDispatcher() + } + + func testConfD() { + let ex = expectation(description: "conf.D") + let oldConf = PromiseKit.conf.D + PromiseKit.conf.D.map = dispatcher + PromiseKit.conf.D.return = dispatcherB + XCTAssertNil(PromiseKit.conf.Q.map, "conf.Q.map not nil") // Not representable as DispatchQueues + XCTAssertNil(PromiseKit.conf.Q.return, "conf.Q.return not nil") + Promise { seal in + seal.fulfill(42) + }.map { + $0 + 10 + }.done() { + XCTAssertEqual($0, 52, "summation result != 52") + XCTAssertEqual(self.dispatcher.dispatchCount, 1, "map dispatcher count != 1") + XCTAssertEqual(self.dispatcherB.dispatchCount, 1, "return dispatcher count != 1") + ex.fulfill() + }.cauterize() + waitForExpectations(timeout: 5) + let testQueue = DispatchQueue(label: "test queue") + PromiseKit.conf.D.map = testQueue // Assign DispatchQueue to Dispatcher variable + PromiseKit.conf.Q.return = testQueue // Assign DispatchQueue to DispatchQueue variable + XCTAssert(PromiseKit.conf.Q.map === testQueue, "did not get main DispatchQueue back from map") + XCTAssert((PromiseKit.conf.D.return as? DispatchQueue)! === testQueue, "did not get main DispatchQueue back from return") + PromiseKit.conf.D = oldConf + } + + func testPMKDefaultIdentity() { + // If this identity does not hold, the DispatchQueue wrapper API will not behave correctly + XCTAssert(DispatchQueue.pmkDefault === DispatchQueue.pmkDefault, "DispatchQueues are not object-identity-preserving on this platform") + } + + func testDispatcherWithThrow() { + let ex = expectation(description: "Dispatcher with throw") + Promise { seal in + seal.fulfill(42) + }.map(on: dispatcher) { _ in + throw PMKError.badInput + }.catch(on: dispatcher) { _ in + ex.fulfill() + } + waitForExpectations(timeout: 5) + XCTAssertEqual(self.dispatcher.dispatchCount, 2) + } + + func testDispatchQueueSelection() { + + let ex = expectation(description: "DispatchQueue compatibility") + + let oldConf = PromiseKit.conf.D + PromiseKit.conf.D = (map: dispatcher, return: dispatcher) + + let background = DispatchQueue.global(qos: .background) + background.setSpecific(key: queueIDKey, value: 100) + DispatchQueue.main.setSpecific(key: queueIDKey, value: 102) + dispatcher.queue.setSpecific(key: queueIDKey, value: 103) + + Promise.value(42).map(on: .global(qos: .background), flags: .barrier) { (x: Int) -> Int in + let queueID = DispatchQueue.getSpecific(key: queueIDKey) + XCTAssertNotNil(queueID) + XCTAssertEqual(queueID!, 100) + return x + 10 + }.get(on: .global(qos: .background), flags: .barrier) { _ in + }.tap(on: .global(qos: .background), flags: .barrier) { _ in + }.then(on: .main, flags: []) { (x: Int) -> Promise in + XCTAssertEqual(x, 52) + let queueID = DispatchQueue.getSpecific(key: queueIDKey) + XCTAssertNotNil(queueID) + XCTAssertEqual(queueID!, 102) + return Promise.value(50) + }.map(on: nil) { (x: Int) -> Int in + let queueID = DispatchQueue.getSpecific(key: queueIDKey) + XCTAssertNotNil(queueID) + XCTAssertEqual(queueID!, 102) + return x + 10 + }.map { (x: Int) -> Int in + XCTAssertEqual(x, 60) + let queueID = DispatchQueue.getSpecific(key: queueIDKey) + XCTAssertNotNil(queueID) + XCTAssertEqual(queueID!, 103) + return x + 10 + }.done(on: background) { + XCTAssertEqual($0, 70) + let queueID = DispatchQueue.getSpecific(key: queueIDKey) + XCTAssertNotNil(queueID) + XCTAssertEqual(queueID!, 100) + ex.fulfill() + }.cauterize() + + waitForExpectations(timeout: 5) + PromiseKit.conf.D = oldConf + + } + + func testMapValues() { + let ex1 = expectation(description: "DispatchQueue MapValues compatibility") + Promise.value([42, 52]).mapValues(on: .global(qos: .background), flags: .barrier) { + $0 + 10 + }.compactMap(on: .global(qos: .background), flags: .barrier) { + $0 + }.flatMapValues(on: .global(qos: .background), flags: .barrier) { + [$0 + 10] + }.compactMapValues(on: .global(qos: .background), flags: .barrier) { + $0 + 10 + }.thenMap(on: .global(qos: .background), flags: .barrier) { + Promise.value($0 + 10) + }.thenFlatMap(on: .global(qos: .background), flags: .barrier) { + Promise.value([$0 + 10]) + }.filterValues(on: .global(qos: .background), flags: .barrier) { _ in + true + }.sortedValues(on: .global(qos: .background), flags: .barrier).firstValue(on: .global(qos: .background), flags: .barrier) { _ in + true + }.done(on: .global(qos: .background), flags: .barrier) { + XCTAssertEqual($0, 92) + ex1.fulfill() + }.catch(on: .global(qos: .background), flags: .barrier) { _ in + XCTFail() + } + + let ex2 = expectation(description: "DispatchQueue firstValue property") + Promise.value([42, 52]).firstValue.done(on: .global(qos: .background), flags: .barrier) { + XCTAssertEqual($0, 42) + ex2.fulfill() + }.catch(on: .global(qos: .background), flags: .barrier, policy: .allErrors) { _ in + XCTFail() + } + + let ex3 = expectation(description: "DispatchQueue lastValue property") + Promise.value([42, 52]).lastValue.done(on: .global(qos: .background), flags: .barrier) { + XCTAssertEqual($0, 52) + ex3.fulfill() + }.catch(on: .global(qos: .background), flags: .barrier, policy: .allErrors) { _ in + XCTFail() + } + + waitForExpectations(timeout: 5) + } + + func testRecover() { + let ex1 = expectation(description: "DispatchQueue CatchMixin compatibility") + Promise.value(42).recover(on: .global(qos: .background), flags: .barrier) { _ in + return Promise.value(42) + }.ensure(on: .global(qos: .background), flags: .barrier) { + }.ensureThen(on: .global(qos: .background), flags: .barrier) { + return after(seconds: 0.0) + }.recover(on: .global(qos: .background), flags: .barrier) { _ in + return Promise.value(42) + }.done(on: .global(qos: .background), flags: .barrier) { + XCTAssertEqual($0, 42) + ex1.fulfill() + }.catch(on: .global(qos: .background), flags: .barrier) { _ in + XCTFail() + } + + let ex2 = expectation(description: "DispatchQueue CatchMixin Void recover") + firstly { + Promise.value(42).asVoid() + }.recover(on: .global(qos: .background), flags: .barrier) { _ in + throw PMKError.emptySequence + }.recover(on: .global(qos: .background), flags: .barrier) { _ in + }.done { + ex2.fulfill() + }.catch(on: .global(qos: .background), flags: .barrier) { _ in + XCTFail() + } + + waitForExpectations(timeout: 5) + } + + @available(macOS 10.10, iOS 2.0, tvOS 10.0, watchOS 2.0, *) + func testDispatcherExtensionReturnsGuarantee() { + let ex = expectation(description: "Dispatcher.promise") + let object: Any = dispatcher.dispatch() { () -> Int in + XCTAssertFalse(Thread.isMainThread) + return 1 + } + XCTAssert(object is Guarantee, "Guarantee not returned from Dispatcher.dispatch { () -> Int }") + (object as? Guarantee)?.done { one in + XCTAssertEqual(one, 1) + ex.fulfill() + } + waitForExpectations(timeout: 5) + } + + @available(macOS 10.10, iOS 2.0, tvOS 10.0, watchOS 2.0, *) + func testDispatcherExtensionCanThrowInBody() { + let ex = expectation(description: "Dispatcher.promise") + let object: Any = dispatcher.dispatch() { () -> Int in + throw PMKError.badInput + } + XCTAssert(object is Promise, "Promise not returned from Dispatcher.dispatch { () throws -> Int }") + (object as? Promise)?.done { _ in + XCTFail() + }.catch { _ in + ex.fulfill() + } + waitForExpectations(timeout: 5) + } + +} diff --git a/Tests/Core/DispatcherTypeTests.swift b/Tests/Core/DispatcherTypeTests.swift new file mode 100644 index 000000000..d60e3bc7f --- /dev/null +++ b/Tests/Core/DispatcherTypeTests.swift @@ -0,0 +1,275 @@ +import Dispatch +@testable import PromiseKit +import XCTest + +class DispatcherTypeTests: XCTestCase { + + struct ScenarioParameters { + let hiatusLikelihoods: [Double] + let noDelayLikelihoods: [Double] + let intervals: [Double] + let dispatches: [Int] + } + + let standardParams = ScenarioParameters( + hiatusLikelihoods: [ 0.3 ], + noDelayLikelihoods: [ 0.75 ], + intervals: [ 0.02, 0.1 ], + dispatches: [ 20 ] + ) + + // Low-CPU, low-parallelism test environment + let travisParams = ScenarioParameters( + hiatusLikelihoods: [ 0.3 ], + noDelayLikelihoods: [ 0.75 ], + intervals: [ 0.1, 0.3 ], + dispatches: [ 10 ] + ) + + // More thorough testing, but takes longer to run + let tortureParams = ScenarioParameters( + hiatusLikelihoods: [ 0.0, 0.3, 0.7 ], + noDelayLikelihoods: [ 0.3, 0.75, 1.0 ], + intervals: [ 0.02, 0.1 ], + dispatches: [ 20 ] + ) + + lazy var scenarios = generateRateLimitScenarios(travisParams) + var rng = Xoroshiro(0x80D0082B8A9651BA, 0x49A8092CFD464A11) // Arbitrary seed + let debug = false + let laxity = 1 // For Travis and low-parallelism environments, elsewhere use 0 + + struct RateLimitScenario { + let maxDispatches: Int + let interval: Double + let hiatusLikelihood: Double + let nHiatuses: Int + let noDelayLikelihood: Double + let delays: [UInt32] + } + + func printScenarioDetails(_ scenario: RateLimitScenario) { + guard debug else { return } + print("\nNew run: n = \(scenario.delays.count), most = \(scenario.maxDispatches),", + "interval = \(scenario.interval), pNoDelay = \(scenario.noDelayLikelihood),", + "pHiatus = \(scenario.hiatusLikelihood), nHiatuses = \(scenario.nHiatuses)\n") + } + + func printTestResults(_ deltaT: TimeInterval, _ concurrent: Int, _ scenario: RateLimitScenario) { + guard debug else { return } + let rateAvg = Double(scenario.delays.count) * scenario.interval / deltaT + print("result actual max = \(concurrent), target max = \(scenario.maxDispatches), average rate = \(rateAvg)") + } + + func generateRateLimitScenarios(_ params: ScenarioParameters) -> [RateLimitScenario] { + + var rng = Xoroshiro(0x80D0082B8A9651BA, 0x49A8092CFD464A11) // Arbitrary seed + var scenarios: [RateLimitScenario] = [] + + for hiatusLikelihoodPerInterval in params.hiatusLikelihoods { + for noDelayLikelihood in params.noDelayLikelihoods { + for interval in params.intervals { + for maxDispatches in params.dispatches { + + // <------------ + + let n = maxDispatches * 10 + let avgSlice = UInt32(interval * 1_000_000 * 0.9 / Double(maxDispatches)) + let normalDelayRange = 0...avgSlice + let hiatusRange = UInt32(interval * 0.5 * 1_000_000)...UInt32(interval * 2.5 * 1_000_000) + let hiatusLikelihoodPerDispatch = 1 - pow(1 - hiatusLikelihoodPerInterval, 1 / Double(maxDispatches)) + + var delays: [UInt32] = [] + for _ in 1...n { + let rand = Double.random(in: 0...1, using: &rng) + if rand < hiatusLikelihoodPerDispatch { + delays.append(hiatusRange.randomElement(using: &rng)!) + } else if rand > (1 - noDelayLikelihood) { + delays.append(0) + } else { + delays.append(normalDelayRange.randomElement(using: &rng)!) + } + } + + let nHiatuses = delays.reduce(0) { $1 > avgSlice ? $0 + 1 : $0 } + + scenarios.append(RateLimitScenario(maxDispatches: maxDispatches, interval: interval, + hiatusLikelihood: hiatusLikelihoodPerInterval, nHiatuses: nHiatuses, + noDelayLikelihood: noDelayLikelihood, delays: delays)) + + // <------------- + + }}}} + + return scenarios + } + + func rateLimitTest(_ dispatcher: Dispatcher, delays: [UInt32], interval: TimeInterval) -> (TimeInterval, Int) { + + let testStart = DispatchTime.now() + var closureStartTimes: [DispatchTime] = [] + let serializer = DispatchQueue(label: "Rate limit") + let ex = expectation(description: "Rate limit") + + for delay in delays { + usleep(delay) + Guarantee.value(42).done(on: dispatcher) { _ in + let now = DispatchTime.now() + serializer.sync { + closureStartTimes.append(now) + if closureStartTimes.count == delays.count { + ex.fulfill() + } + } + } + } + + let totalDelay = Double(delays.reduce(0, +)) / 1_000_000 + let expectedDuration = interval * Double(delays.count) + let adequateTime = max(expectedDuration, totalDelay) * 1.5 + waitForExpectations(timeout: adequateTime) + + let most = mostAtOnce(closureStartTimes, interval: interval) + let duration = DispatchTime.now() - testStart + + return (duration, most) + } + + func mostAtOnce(_ times: [DispatchTime], interval: TimeInterval) -> Int { + var most = 0 + for start in times { + let timeRange = start...(start + interval) + let pruned = times.filter { timeRange.contains($0) } + most = max(most, pruned.count) + } + return most + } + + func testRateLimitedDispatcher() { + for scenario in scenarios { + printScenarioDetails(scenario) + let dispatcher = RateLimitedDispatcher(maxDispatches: scenario.maxDispatches, perInterval: scenario.interval) + let (deltaT, mostConcurrent) = rateLimitTest(dispatcher, delays: scenario.delays, interval: scenario.interval) + // For the nonstrict RateLimitedDispatcher, burst rate may be up to 2X the goal. + // There is, unavoidably, a potential lag between the time a closure is dispatched and the + // time it actually starts to run and has its start-time measured. This redistribution in time + // makes it impossible to verify rates with perfect accuracy because of bunching. For desktop + // testing the issue essentially never occurs and laxity should be set to 0. + XCTAssertLessThanOrEqual(mostConcurrent, scenario.maxDispatches * 2 + laxity) + // Significantly under the goal rate is also a concern + XCTAssertGreaterThan(mostConcurrent, (scenario.maxDispatches * 3) / 4) + printTestResults(deltaT, mostConcurrent, scenario) + } + } + + func testStrictRateLimitedDispatcher() { + for scenario in scenarios { + printScenarioDetails(scenario) + let dispatcher = StrictRateLimitedDispatcher(maxDispatches: scenario.maxDispatches, perInterval: scenario.interval) + let (deltaT, mostConcurrent) = rateLimitTest(dispatcher, delays: scenario.delays, interval: scenario.interval) + // There is, unavoidably, a potential lag between the time a closure is dispatched and the + // time it actually starts to run and has its start-time measured. This redistribution in time + // makes it impossible to verify rates with perfect accuracy because of bunching. For desktop + // testing the issue essentially never occurs and laxity should be set to 0. + XCTAssertLessThanOrEqual(mostConcurrent, scenario.maxDispatches + laxity) + // Significantly under the goal rate is also a concern + XCTAssertGreaterThan(mostConcurrent, (scenario.maxDispatches * 3) / 4) + printTestResults(deltaT, mostConcurrent, scenario) + // print("tail wait start", DispatchTime.now().rawValue) + usleep(UInt32(scenario.interval * 1_000_000 * 2)) + // print("tail wait end", DispatchTime.now().rawValue) + XCTAssert(dispatcher.startTimeHistory.count == 0, "Dispatcher did not clean up properly") + } + } + + func testConcurrencyLimitedDispatcher() { + + for scenario in scenarios { + + printScenarioDetails(scenario) + let dispatcher = ConcurrencyLimitedDispatcher(limit: scenario.maxDispatches) + + var nConcurrent = 0 + var maxNConcurrent = 0 + var nRun = 0 + let serializer = DispatchQueue(label: "Concurrency test") + let ex = expectation(description: "Concurrency limit") + + for delay in scenario.delays { + usleep(delay) + Guarantee.value(42).done(on: dispatcher) { _ in + serializer.sync { + nConcurrent += 1 + maxNConcurrent = max(maxNConcurrent, nConcurrent) + } + usleep(UInt32.random(in: 10_000...100_000, using: &self.rng)) + serializer.sync { + nConcurrent -= 1 + nRun += 1 + if nRun == scenario.delays.count { + ex.fulfill() + } + } + } + } + + waitForExpectations(timeout: Double(scenario.delays.count) * 0.1) + // Usually maxNConcurrent will == target, but some platforms have inherent limits on parallelism, at least in test + XCTAssertLessThanOrEqual(maxNConcurrent, scenario.maxDispatches, "More concurrent tasks than allowed") + XCTAssertGreaterThanOrEqual(maxNConcurrent, 2, "Concurrent executions not concurrent") + + } + } + + // These aren't really "tests" per se; they just exercise all the various init types + // to verify that none of them produce ambiguity warnings or recurse indefinitely, + // and that DispatchQueue members are accessible. + + func testRateLimitedDispatcherInit() { + XCTAssertNotNil(RateLimitedDispatcher(maxDispatches: 1, perInterval: 1)) + XCTAssertNotNil(RateLimitedDispatcher(maxDispatches: 1, perInterval: 1, queue: DispatchQueue.main)) + XCTAssertNotNil(RateLimitedDispatcher(maxDispatches: 1, perInterval: 1, queue: CurrentThreadDispatcher())) + XCTAssertNotNil(RateLimitedDispatcher(maxDispatches: 1, perInterval: 1, queue: .main)) + XCTAssertNotNil(RateLimitedDispatcher(maxDispatches: 1, perInterval: 1, queue: .global(qos: .background))) + } + + func testStrictRateLimitedDispatcherInit() { + XCTAssertNotNil(StrictRateLimitedDispatcher(maxDispatches: 1, perInterval: 1)) + XCTAssertNotNil(StrictRateLimitedDispatcher(maxDispatches: 1, perInterval: 1, queue: DispatchQueue.main)) + XCTAssertNotNil(StrictRateLimitedDispatcher(maxDispatches: 1, perInterval: 1, queue: CurrentThreadDispatcher())) + XCTAssertNotNil(StrictRateLimitedDispatcher(maxDispatches: 1, perInterval: 1, queue: .main)) + XCTAssertNotNil(StrictRateLimitedDispatcher(maxDispatches: 1, perInterval: 1, queue: .global(qos: .background))) + } + + func testConcurrencyLimitedDispatcherInit() { + XCTAssertNotNil(ConcurrencyLimitedDispatcher(limit: 1)) + XCTAssertNotNil(ConcurrencyLimitedDispatcher(limit: 1, queue: DispatchQueue.main)) + XCTAssertNotNil(ConcurrencyLimitedDispatcher(limit: 1, queue: CurrentThreadDispatcher())) + XCTAssertNotNil(ConcurrencyLimitedDispatcher(limit: 1, queue: .main)) + XCTAssertNotNil(ConcurrencyLimitedDispatcher(limit: 1, queue: .global(qos: .background))) + } + +} + +// Reproducible, seedable RNG + +struct Xoroshiro: RandomNumberGenerator { + + typealias State = (UInt64, UInt64) + + var state: State + + init(_ a: UInt64, _ b: UInt64) { + state = (a, b) + } + + mutating func next() -> UInt64 { + let (l, k0, k1, k2): (UInt64, UInt64, UInt64, UInt64) = (64, 55, 14, 36) + let result = state.0 &+ state.1 + let x = state.0 ^ state.1 + state.0 = ((state.0 << k0) | (state.0 >> (l - k0))) ^ x ^ (x << k1) + state.1 = (x << k2) | (x >> (l - k2)) + return result + } + +} diff --git a/Tests/CorePromise/ErrorTests.swift b/Tests/Core/ErrorTests.swift similarity index 100% rename from Tests/CorePromise/ErrorTests.swift rename to Tests/Core/ErrorTests.swift diff --git a/Tests/CorePromise/GuaranteeTests.swift b/Tests/Core/GuaranteeTests.swift similarity index 88% rename from Tests/CorePromise/GuaranteeTests.swift rename to Tests/Core/GuaranteeTests.swift index 55d12a712..07e16160f 100644 --- a/Tests/CorePromise/GuaranteeTests.swift +++ b/Tests/Core/GuaranteeTests.swift @@ -10,7 +10,7 @@ class GuaranteeTests: XCTestCase { XCTAssertEqual(1, $0) ex.fulfill() } - wait(for: [ex], timeout: 10) + wait(for: [ex], timeout: 5) } func testMap() { @@ -23,7 +23,7 @@ class GuaranteeTests: XCTestCase { ex.fulfill() } - wait(for: [ex], timeout: 10) + wait(for: [ex], timeout: 5) } func testMapByKeyPath() { @@ -34,7 +34,7 @@ class GuaranteeTests: XCTestCase { ex.fulfill() } - wait(for: [ex], timeout: 10) + wait(for: [ex], timeout: 5) } func testWait() { @@ -51,7 +51,7 @@ class GuaranteeTests: XCTestCase { ex.fulfill() } - wait(for: [ex], timeout: 10) + wait(for: [ex], timeout: 5) } func testMapValuesByKeyPath() { @@ -64,7 +64,7 @@ class GuaranteeTests: XCTestCase { ex.fulfill() } - wait(for: [ex], timeout: 10) + wait(for: [ex], timeout: 5) } func testFlatMapValues() { @@ -77,7 +77,7 @@ class GuaranteeTests: XCTestCase { ex.fulfill() } - wait(for: [ex], timeout: 10) + wait(for: [ex], timeout: 5) } func testCompactMapValues() { @@ -90,7 +90,7 @@ class GuaranteeTests: XCTestCase { ex.fulfill() } - wait(for: [ex], timeout: 10) + wait(for: [ex], timeout: 5) } func testCompactMapValuesByKeyPath() { @@ -103,7 +103,7 @@ class GuaranteeTests: XCTestCase { ex.fulfill() } - wait(for: [ex], timeout: 10) + wait(for: [ex], timeout: 5) } func testThenMap() { @@ -117,7 +117,7 @@ class GuaranteeTests: XCTestCase { ex.fulfill() } - wait(for: [ex], timeout: 10) + wait(for: [ex], timeout: 5) } func testThenFlatMap() { @@ -131,7 +131,7 @@ class GuaranteeTests: XCTestCase { ex.fulfill() } - wait(for: [ex], timeout: 10) + wait(for: [ex], timeout: 5) } func testFilterValues() { @@ -145,7 +145,7 @@ class GuaranteeTests: XCTestCase { ex.fulfill() } - wait(for: [ex], timeout: 10) + wait(for: [ex], timeout: 5) } func testFilterValuesByKeyPath() { @@ -159,7 +159,7 @@ class GuaranteeTests: XCTestCase { ex.fulfill() } - wait(for: [ex], timeout: 10) + wait(for: [ex], timeout: 5) } func testSorted() { @@ -173,7 +173,7 @@ class GuaranteeTests: XCTestCase { ex.fulfill() } - wait(for: [ex], timeout: 10) + wait(for: [ex], timeout: 5) } func testSortedBy() { @@ -187,10 +187,9 @@ class GuaranteeTests: XCTestCase { ex.fulfill() } - wait(for: [ex], timeout: 10) + wait(for: [ex], timeout: 5) } - #if swift(>=3.1) func testNoAmbiguityForValue() { let ex = expectation(description: "") let a = Guarantee.value @@ -199,7 +198,6 @@ class GuaranteeTests: XCTestCase { when(fulfilled: a, b, c).done { ex.fulfill() }.cauterize() - wait(for: [ex], timeout: 10) + wait(for: [ex], timeout: 5) } - #endif } diff --git a/Tests/CorePromise/HangTests.swift b/Tests/Core/HangTests.swift similarity index 91% rename from Tests/CorePromise/HangTests.swift rename to Tests/Core/HangTests.swift index 84156d35b..da389e638 100644 --- a/Tests/CorePromise/HangTests.swift +++ b/Tests/Core/HangTests.swift @@ -1,3 +1,5 @@ +#if canImport(CoreFoundation) + import PromiseKit import XCTest @@ -13,7 +15,7 @@ class HangTests: XCTestCase { } catch { XCTFail("Unexpected error") } - waitForExpectations(timeout: 0) + waitForExpectations(timeout: 5) } enum Error: Swift.Error { @@ -36,3 +38,5 @@ class HangTests: XCTestCase { XCTFail("Expected error but no error was thrown") } } + +#endif diff --git a/Tests/CorePromise/LoggingTests.swift b/Tests/Core/LoggingTests.swift similarity index 52% rename from Tests/CorePromise/LoggingTests.swift rename to Tests/Core/LoggingTests.swift index ab869d1ac..22418a067 100644 --- a/Tests/CorePromise/LoggingTests.swift +++ b/Tests/Core/LoggingTests.swift @@ -2,23 +2,44 @@ import Dispatch import XCTest +private extension LogEvent { + var rawDescription: String { + switch self { + case .waitOnMainThread: return "waitOnMainThread" + case .pendingPromiseDeallocated: return "pendingPromiseDeallocated" + case .pendingGuaranteeDeallocated: return "pendingGuaranteeDeallocated" + case .cauterized(let a): return "cauterized(\(a))" + case .nilDispatchQueueWithFlags: return "nilDispatchQueueWithFlags" + case .extraneousFlagsSpecified: return "extraneousFlagsSpecified" + } + } +} + class LoggingTests: XCTestCase { + + enum ForTesting: Error, CustomDebugStringConvertible { + case purposes + var debugDescription: String { + return "purposes" + } + } + + var logOutput: String? = nil + + func captureLogger(_ event: LogEvent) { + logOutput = event.rawDescription + } + /** The test should emit the following log messages: - + PromiseKit: warning: `wait()` called on main thread! PromiseKit: warning: pending promise deallocated + PromiseKit: warning: pending guarantee deallocated PromiseKit:cauterized-error: purposes - This is an error message */ func testLogging() { - - var logOutput: String? = nil - - enum ForTesting: Error { - case purposes - } - + // Test Logging to Console, the default behavior conf.logHandler(.waitOnMainThread) conf.logHandler(.pendingPromiseDeallocated) @@ -33,16 +54,7 @@ class LoggingTests: XCTestCase { conf.logHandler(.cauterized(ForTesting.purposes)) XCTAssertNil(logOutput) - conf.logHandler = { event in - switch event { - case .waitOnMainThread, .pendingPromiseDeallocated, .pendingGuaranteeDeallocated: - logOutput = "\(event)" - case .cauterized: - // Using an enum with associated value does not convert to a string properly in - // earlier versions of swift - logOutput = "cauterized" - } - } + conf.logHandler = captureLogger conf.logHandler(.waitOnMainThread) XCTAssertEqual(logOutput!, "waitOnMainThread") logOutput = nil @@ -50,20 +62,13 @@ class LoggingTests: XCTestCase { XCTAssertEqual(logOutput!, "pendingPromiseDeallocated") logOutput = nil conf.logHandler(.cauterized(ForTesting.purposes)) - XCTAssertEqual(logOutput!, "cauterized") + XCTAssertEqual(logOutput!, "cauterized(purposes)") } // Verify waiting on main thread in Promise is logged func testPromiseWaitOnMainThreadLogged() throws { - - enum ForTesting: Error { - case purposes - } - - var logOutput: String? = nil - conf.logHandler = { event in - logOutput = "\(event)" - } + + conf.logHandler = captureLogger let promiseResolver = Promise.pending() let workQueue = DispatchQueue(label: "worker") workQueue.async { @@ -73,28 +78,14 @@ class LoggingTests: XCTestCase { XCTAssertEqual("PromiseFulfilled", promisedString) XCTAssertEqual(logOutput!, "waitOnMainThread") } - + // Verify Promise.cauterize() is logged func testCauterizeIsLogged() { - - enum ForTesting: Error { - case purposes - } - var logOutput: String? = nil - conf.logHandler = { event in - switch event { - case .waitOnMainThread, .pendingPromiseDeallocated, .pendingGuaranteeDeallocated: - logOutput = "\(event)" - case .cauterized: - // Using an enum with associated value does not convert to a string properly in - // earlier versions of swift - logOutput = "cauterized" - } - } + conf.logHandler = captureLogger func createPromise() -> Promise { let promiseResolver = Promise.pending() - + let queue = DispatchQueue(label: "workQueue") queue.async { promiseResolver.resolver.reject(ForTesting.purposes) @@ -107,14 +98,14 @@ class LoggingTests: XCTestCase { }.ensure { ex.fulfill() }.cauterize() - waitForExpectations(timeout: 1) + waitForExpectations(timeout: 5) ex = expectation(description: "read") let readQueue = DispatchQueue(label: "readQueue") readQueue.async { var outputSet = false while !outputSet { - if let logOutput = logOutput { - XCTAssertEqual(logOutput, "cauterized") + if let logOutput = self.logOutput { + XCTAssertEqual(logOutput, "cauterized(purposes)") outputSet = true ex.fulfill() } @@ -123,27 +114,13 @@ class LoggingTests: XCTestCase { } } } - waitForExpectations(timeout: 1) + waitForExpectations(timeout: 5) } // Verify waiting on main thread in Guarantee is logged func testGuaranteeWaitOnMainThreadLogged() { - - enum ForTesting: Error { - case purposes - } - - var logOutput: String? = nil - conf.logHandler = { event in - switch event { - case .waitOnMainThread, .pendingPromiseDeallocated, .pendingGuaranteeDeallocated: - logOutput = "\(event)" - case .cauterized: - // Using an enum with associated value does not convert to a string properly in - // earlier versions of swift - logOutput = "cauterized" - } - } + + conf.logHandler = captureLogger let guaranteeResolve = Guarantee.pending() let workQueue = DispatchQueue(label: "worker") workQueue.async { @@ -153,47 +130,42 @@ class LoggingTests: XCTestCase { XCTAssertEqual("GuaranteeFulfilled", guaranteedString) XCTAssertEqual(logOutput!, "waitOnMainThread") } - + // Verify pendingPromiseDeallocated is logged func testPendingPromiseDeallocatedIsLogged() { - - var logOutput: String? = nil - conf.logHandler = { event in - switch event { - case .waitOnMainThread, .pendingPromiseDeallocated, .pendingGuaranteeDeallocated: - logOutput = "\(event)" - case .cauterized: - // Using an enum with associated value does not convert to a string properly in - // earlier versions of swift - logOutput = "cauterized" - } - } + + conf.logHandler = captureLogger do { let _ = Promise.pending() } XCTAssertEqual ("pendingPromiseDeallocated", logOutput!) } - + // Verify pendingGuaranteeDeallocated is logged func testPendingGuaranteeDeallocatedIsLogged() { - - var logOutput: String? = nil - let loggingClosure: (PromiseKit.LogEvent) -> Void = { event in - switch event { - case .waitOnMainThread, .pendingPromiseDeallocated, .pendingGuaranteeDeallocated: - logOutput = "\(event)" - case .cauterized: - // Using an enum with associated value does not convert to a string properly in - // earlier versions of swift - logOutput = "cauterized" - } - } - conf.logHandler = loggingClosure + var logOutput = "" + conf.logHandler = { logOutput = $0.rawDescription } do { - let _ = Guarantee.pending() + _ = Guarantee.pending() } - XCTAssertEqual ("pendingGuaranteeDeallocated", logOutput!) + XCTAssertEqual ("pendingGuaranteeDeallocated", logOutput) + } + + // Verify nilDispatchQueueWithFlags is logged + func testNilDispatchQueueWithFlags() { + + conf.logHandler = captureLogger + Guarantee.value(42).done(on: nil, flags: .barrier) { _ in } + XCTAssertEqual ("nilDispatchQueueWithFlags", logOutput!) } - - //TODO Verify pending promise deallocation is logged + + // Verify extraneousFlagsSpecified is logged + func testExtraneousFlagsSpecified() { + + conf.logHandler = captureLogger + conf.D.return = CurrentThreadDispatcher() + Guarantee.value(42).done(flags: .barrier) { _ in } + XCTAssertEqual ("extraneousFlagsSpecified", logOutput!) + } + } diff --git a/Tests/Core/PromiseTests.swift b/Tests/Core/PromiseTests.swift new file mode 100644 index 000000000..4a1e985a9 --- /dev/null +++ b/Tests/Core/PromiseTests.swift @@ -0,0 +1,220 @@ +import PromiseKit +import Dispatch +import XCTest + +class PromiseTests: XCTestCase { + func testIsPending() { + XCTAssertTrue(Promise.pending().promise.isPending) + XCTAssertFalse(Promise().isPending) + XCTAssertFalse(Promise(error: Error.dummy).isPending) + } + + func testIsResolved() { + XCTAssertFalse(Promise.pending().promise.isResolved) + XCTAssertTrue(Promise().isResolved) + XCTAssertTrue(Promise(error: Error.dummy).isResolved) + } + + func testIsFulfilled() { + XCTAssertFalse(Promise.pending().promise.isFulfilled) + XCTAssertTrue(Promise().isFulfilled) + XCTAssertFalse(Promise(error: Error.dummy).isFulfilled) + } + + func testIsRejected() { + XCTAssertFalse(Promise.pending().promise.isRejected) + XCTAssertTrue(Promise(error: Error.dummy).isRejected) + XCTAssertFalse(Promise().isRejected) + } + + @available(macOS 10.10, iOS 2.0, tvOS 10.0, watchOS 2.0, *) + func testDispatchQueueAsyncExtensionReturnsGuarantee() { + let ex = expectation(description: "") + let returnedValue: Any = DispatchQueue.global().async(.promise) { () -> Int in + XCTAssertFalse(Thread.isMainThread) + return 1 + } + // This is statically determined, but we want to promote it into something that fits into XCTest + XCTAssert(returnedValue is Guarantee, "DispatchQueue.async() returns non-Guarantee even when code doesn't throw") + if let guarantee = returnedValue as? Guarantee { + guarantee.done { one in + XCTAssertEqual(one, 1) + ex.fulfill() + } + waitForExpectations(timeout: 5) + } + } + + @available(macOS 10.10, iOS 2.0, tvOS 10.0, watchOS 2.0, *) + func testDispatcherDispatchExtensionReturnsGuarantee() { + let ex = expectation(description: "Dispatcher.dispatch -> Guarantee") + let dispatcher: Dispatcher = DispatchQueue.global() + let returnedValue: Any = dispatcher.dispatch { () -> Int in + XCTAssertFalse(Thread.isMainThread) + return 1 + } + // This is statically determined, but we want to promote it into something that fits into XCTest + XCTAssert(returnedValue is Guarantee, "Dispatcher.dispatch() returns non-Guarantee even when code doesn't throw") + if let guarantee = returnedValue as? Guarantee { + guarantee.done { one in + XCTAssertEqual(one, 1) + ex.fulfill() + } + waitForExpectations(timeout: 5) + } + } + + @available(macOS 10.10, iOS 2.0, tvOS 10.0, watchOS 2.0, *) + func testDispatchQueueAsyncExtensionCanThrowInBody() { + let ex = expectation(description: "") + let returnedValue: Any = DispatchQueue.global().async(.promise) { () -> Int in + throw Error.dummy + } + // This is statically determined, but we want to promote it into something that fits into XCTest + XCTAssert(returnedValue is Promise, "Dispatcher.dispatch() returns non-Promise even when code can throw") + XCTAssert(returnedValue is Promise, "DispatchQueue.async() returns non-Promise even when code can throw") + if let promise = returnedValue as? Promise { + promise.done { _ in + XCTFail("Promise should not complete normally") + }.catch { _ in + ex.fulfill() + } + waitForExpectations(timeout: 5) + } else { + XCTFail("Could not recover Promise from Any") + } + } + + @available(macOS 10.10, iOS 2.0, tvOS 10.0, watchOS 2.0, *) + func testDispatcherDispatchExtensionCanThrowInBody() { + let ex = expectation(description: "Dispatcher.dispatch -> Promise") + let dispatcher: Dispatcher = DispatchQueue.global() + let returnedValue: Any = dispatcher.dispatch { () -> Int in + throw Error.dummy + } + // This is statically determined, but we want to promote it into something that fits into XCTest + XCTAssert(returnedValue is Promise, "Dispatcher.dispatch() returns non-Promise even when code can throw") + if let promise = returnedValue as? Promise { + promise.done { _ in + XCTFail("Promise should not complete normally") + }.catch { _ in + ex.fulfill() + } + waitForExpectations(timeout: 5) + } else { + XCTFail("Could not recover Promise from Any") + } + } + + @available(macOS 10.10, iOS 2.0, tvOS 10.0, watchOS 2.0, *) + func testDispatcherDispatchExtensionDoesNotInterfereWithRegularDispatch() { + let dispatcher: Dispatcher = DispatchQueue.global() + + let plain = expectation(description: "plain closure") + let plainReturn: Any = dispatcher.dispatch { + plain.fulfill() + } + // This is statically determined, but we want to promote it into something that fits into XCTest + XCTAssert(plainReturn is Void, "Dispatcher.dispatch() returns something other than Void") + + // With a throwing closure, the return should be a Promise, even without a return value. + // There's no standard Dispatcher API that accepts throwing closures for dispatch. + let throwing = expectation(description: "throwing closure") + let throwingReturn: Any = dispatcher.dispatch { + throwing.fulfill() + throw Error.dummy + } + // This is statically determined, but we want to promote it into something that fits into XCTest + XCTAssert(throwingReturn is Promise, "Dispatcher.dispatch() returns something other than Promise with plain throwing closure") + waitForExpectations(timeout: 5) + } + + func testCustomStringConvertible() { + XCTAssertEqual(Promise.pending().promise.debugDescription, "Promise.pending(handlers: 0)") + XCTAssertEqual(Promise().debugDescription, "Promise<()>.success(())") + XCTAssertEqual(Promise(error: Error.dummy).debugDescription, "Promise.failure(Error.dummy)") + + XCTAssertEqual("\(Promise.pending().promise)", "Promise(…Int)") + XCTAssertEqual("\(Promise.value(3))", "Promise(3)") + XCTAssertEqual("\(Promise(error: Error.dummy))", "Promise(dummy)") + } + + func testCannotFulfillWithError() { + + // sadly this test proves the opposite :( + // left here so maybe one day we can prevent instantiation of `Promise` + + _ = Promise { seal in + seal.fulfill(Error.dummy) + } + + _ = Promise.pending() + + _ = Promise.value(Error.dummy) + + _ = Promise().map { Error.dummy } + } + + func testCanMakeVoidPromise() { + _ = Promise() + _ = Guarantee() + } + + enum Error: Swift.Error { + case dummy + } + + func testThrowInInitializer() { + let p = Promise { _ in + throw Error.dummy + } + XCTAssertTrue(p.isRejected) + guard let err = p.error, case Error.dummy = err else { return XCTFail() } + } + + func testThrowInFirstly() { + let ex = expectation(description: "") + + firstly { () -> Promise in + throw Error.dummy + }.catch { + XCTAssertEqual($0 as? Error, Error.dummy) + ex.fulfill() + } + + wait(for: [ex], timeout: 5) + } + + func testWait() throws { + let p = after(.milliseconds(100)).then(on: nil){ Promise.value(1) } + XCTAssertEqual(try p.wait(), 1) + + do { + let p = after(.milliseconds(100)).map(on: nil){ throw Error.dummy } + try p.wait() + XCTFail() + } catch { + XCTAssertEqual(error as? Error, Error.dummy) + } + } + + func testPipeForResolved() { + let ex = expectation(description: "") + Promise.value(1).done { + XCTAssertEqual(1, $0) + ex.fulfill() + }.silenceWarning() + wait(for: [ex], timeout: 5) + } + + func testNoAmbiguityForValue() { + let ex = expectation(description: "") + let a = Promise.value + let b = Promise.value(Void()) + let c = Promise.value(()) + when(fulfilled: a, b, c).done { + ex.fulfill() + }.cauterize() + wait(for: [ex], timeout: 5) + } +} diff --git a/Tests/CorePromise/RaceTests.swift b/Tests/Core/RaceTests.swift similarity index 80% rename from Tests/CorePromise/RaceTests.swift rename to Tests/Core/RaceTests.swift index 45d7ef0b7..459d8f6d2 100644 --- a/Tests/CorePromise/RaceTests.swift +++ b/Tests/Core/RaceTests.swift @@ -8,16 +8,16 @@ class RaceTests: XCTestCase { XCTAssertEqual(index, 1) ex.fulfill() }.silenceWarning() - waitForExpectations(timeout: 1, handler: nil) + waitForExpectations(timeout: 5, handler: nil) } - + func test2() { let ex = expectation(description: "") race(after(seconds: 1).map{ 1 }, after(.milliseconds(10)).map{ 2 }).done { index in XCTAssertEqual(index, 2) ex.fulfill() } - waitForExpectations(timeout: 1, handler: nil) + waitForExpectations(timeout: 5, handler: nil) } func test1Array() { @@ -27,16 +27,16 @@ class RaceTests: XCTestCase { XCTAssertEqual(index, 1) ex.fulfill() }.silenceWarning() - waitForExpectations(timeout: 1, handler: nil) + waitForExpectations(timeout: 5, handler: nil) } - + func test2Array() { let ex = expectation(description: "") race(after(seconds: 1).map{ 1 }, after(.milliseconds(10)).map{ 2 }).done { index in XCTAssertEqual(index, 2) ex.fulfill() } - waitForExpectations(timeout: 1, handler: nil) + waitForExpectations(timeout: 5, handler: nil) } func testEmptyArray() { @@ -46,7 +46,17 @@ class RaceTests: XCTestCase { guard case PMKError.badInput = $0 else { return XCTFail() } ex.fulfill() } - wait(for: [ex], timeout: 10) + wait(for: [ex], timeout: 5) + } + + func testReject() { + let ex = expectation(description: "") + race(Promise(error: PMKError.timedOut), after(.milliseconds(10)).map{ 2 }).done { index in + XCTFail() + }.catch(policy: .allErrors) { + $0.isCancelled ? ex.fulfill() : XCTFail() + } + waitForExpectations(timeout: 5, handler: nil) } func testFulfilled() { @@ -60,7 +70,7 @@ class RaceTests: XCTestCase { XCTFail() ex.fulfill() } - wait(for: [ex], timeout: 10) + wait(for: [ex], timeout: 5) } func testFulfilledEmptyArray() { @@ -70,7 +80,7 @@ class RaceTests: XCTestCase { guard case PMKError.badInput = $0 else { return XCTFail() } ex.fulfill() } - wait(for: [ex], timeout: 10) + wait(for: [ex], timeout: 5) } func testFulfilledWithNoWinner() { @@ -86,6 +96,6 @@ class RaceTests: XCTestCase { guard pmkError.debugDescription == "All thenables passed to race(fulfilled:) were rejected" else { return XCTFail() } ex.fulfill() } - wait(for: [ex], timeout: 10) + wait(for: [ex], timeout: 5) } } diff --git a/Tests/CorePromise/RegressionTests.swift b/Tests/Core/RegressionTests.swift similarity index 100% rename from Tests/CorePromise/RegressionTests.swift rename to Tests/Core/RegressionTests.swift diff --git a/Tests/CorePromise/ResolverTests.swift b/Tests/Core/ResolverTests.swift similarity index 84% rename from Tests/CorePromise/ResolverTests.swift rename to Tests/Core/ResolverTests.swift index 63b35322d..ac0413a33 100644 --- a/Tests/CorePromise/ResolverTests.swift +++ b/Tests/Core/ResolverTests.swift @@ -11,7 +11,7 @@ class WrapTests: XCTestCase { self.error = error } - func fetchWithCompletionBlock(block: @escaping(Int?, Error?) -> Void) { + func fetchWithCompletionBlock(block: @escaping(Int?, Swift.Error?) -> Void) { after(.milliseconds(20)).done { block(self.value, self.error) } @@ -23,7 +23,7 @@ class WrapTests: XCTestCase { } } - func fetchWithCompletionBlock3(block: @escaping(Int, Error?) -> Void) { + func fetchWithCompletionBlock3(block: @escaping(Int, Swift.Error?) -> Void) { after(.milliseconds(20)).done { block(self.value ?? -99, self.error) } @@ -35,8 +35,7 @@ class WrapTests: XCTestCase { } } -#if swift(>=5.0) - func fetchWithCompletionBlock5(block: @escaping(Swift.Result) -> Void) { + func fetchWithCompletionBlock5(block: @escaping(Swift.Result) -> Void) { after(.milliseconds(20)).done { if let value = self.value { block(.success(value)) @@ -45,7 +44,6 @@ class WrapTests: XCTestCase { } } } -#endif } func testSuccess() { @@ -58,7 +56,7 @@ class WrapTests: XCTestCase { ex.fulfill() }.silenceWarning() - waitForExpectations(timeout: 1) + waitForExpectations(timeout: 5) } func testError() { @@ -74,7 +72,7 @@ class WrapTests: XCTestCase { } } - waitForExpectations(timeout: 1) + waitForExpectations(timeout: 5) } func testInvalidCallingConvention() { @@ -90,7 +88,7 @@ class WrapTests: XCTestCase { } } - waitForExpectations(timeout: 1) + waitForExpectations(timeout: 5) } func testInvertedCallingConvention() { @@ -103,7 +101,7 @@ class WrapTests: XCTestCase { ex.fulfill() }.silenceWarning() - waitForExpectations(timeout: 1) + waitForExpectations(timeout: 5) } @@ -123,10 +121,9 @@ class WrapTests: XCTestCase { kf2.fetchWithCompletionBlock3(block: seal.resolve) }.catch { _ in ex2.fulfill() } - wait(for: [ex1, ex2] ,timeout: 1) + wait(for: [ex1, ex2] ,timeout: 5) } -#if swift(>=3.1) func testVoidCompletionValue() { let ex1 = expectation(description: "") let kf1 = KittenFetcher(value: nil, error: nil) @@ -140,27 +137,23 @@ class WrapTests: XCTestCase { kf2.fetchWithCompletionBlock4(block: seal.resolve) }.catch { _ in ex2.fulfill() } - wait(for: [ex1, ex2], timeout: 1) + wait(for: [ex1, ex2], timeout: 5) } -#endif func testSwiftResultSuccess() { - #if swift(>=5.0) let ex = expectation(description: "") let kittenFetcher = KittenFetcher(value: 2, error: nil) - Promise { seal in + Promise { seal in kittenFetcher.fetchWithCompletionBlock5(block: seal.resolve) }.done { XCTAssertEqual($0, 2) ex.fulfill() }.silenceWarning() - waitForExpectations(timeout: 1) - #endif + waitForExpectations(timeout: 5) } func testSwiftResultError() { - #if swift(>=5.0) let ex = expectation(description: "") let kittenFetcher = KittenFetcher(value: nil, error: Error.test) @@ -173,13 +166,12 @@ class WrapTests: XCTestCase { } } - waitForExpectations(timeout: 1) - #endif + waitForExpectations(timeout: 5) } func testIsFulfilled() { - XCTAssertTrue(Promise.value(()).result?.isFulfilled ?? false) - XCTAssertFalse(Promise(error: Error.test).result?.isFulfilled ?? true) + XCTAssertNotNil(try? Promise.value(()).result?.get()) + XCTAssertNil(try? Promise(error: Error.test).result?.get()) } func testPendingPromiseDeallocated() { @@ -202,14 +194,10 @@ class WrapTests: XCTestCase { let foo = Foo() foo.ex = ex } - wait(for: [ex], timeout: 10) + wait(for: [ex], timeout: 5) } func testVoidResolverFulfillAmbiguity() { - #if !swift(>=5) && swift(>=4.1) || swift(>=3.3) && !swift(>=4.0) - // ^^ this doesn’t work with Swift < 3.3 for some reason - // ^^ this doesn’t work with Swift 5.0-beta1 for some reason - // reference: https://github.com/mxcl/PromiseKit/issues/990 func foo(success: () -> Void, failure: (Error) -> Void) { @@ -224,8 +212,14 @@ class WrapTests: XCTestCase { let ex = expectation(description: "") bar().done(ex.fulfill).cauterize() - wait(for: [ex], timeout: 10) - #endif + wait(for: [ex], timeout: 5) + + // ^^ ambiguous in Swift 5.0 & 5.1, testing again in next version + let ex2 = expectation(description: "") + Guarantee { seal in + after(.microseconds(10)).done(seal) + }.done(ex2.fulfill) + wait(for: [ex2], timeout: 5) } } diff --git a/Tests/CorePromise/StressTests.swift b/Tests/Core/StressTests.swift similarity index 93% rename from Tests/CorePromise/StressTests.swift rename to Tests/Core/StressTests.swift index 787e485d0..842a435c6 100644 --- a/Tests/CorePromise/StressTests.swift +++ b/Tests/Core/StressTests.swift @@ -14,7 +14,7 @@ class StressTests: XCTestCase { }.silenceWarning() }, fulfill: { "ok" }) - waitForExpectations(timeout: 10, handler: nil) + waitForExpectations(timeout: 5, handler: nil) } @available(macOS 10.10, iOS 2.0, tvOS 10.0, watchOS 2.0, *) @@ -35,7 +35,7 @@ class StressTests: XCTestCase { XCTAssertEqual(values, (0..(error: E.dummy) + + p.compactMap { (x: Int) -> Int? in + Int(x) }.catch { if case E.dummy = $0 {} else { XCTFail() } ex.fulfill() } - wait(for: [ex], timeout: 10) + wait(for: [ex], timeout: 5) } func testPMKErrorCompactMap() { @@ -105,7 +108,7 @@ class ThenableTests: XCTestCase { } ex.fulfill() } - wait(for: [ex], timeout: 10) + wait(for: [ex], timeout: 5) } func testCompactMapByKeyPath() { @@ -114,7 +117,7 @@ class ThenableTests: XCTestCase { XCTAssertEqual($0, 26) ex.fulfill() }.silenceWarning() - wait(for: [ex], timeout: 10) + wait(for: [ex], timeout: 5) } func testMapValues() { @@ -125,7 +128,7 @@ class ThenableTests: XCTestCase { XCTAssertEqual([28, 40, 90], $0) ex.fulfill() }.silenceWarning() - wait(for: [ex], timeout: 10) + wait(for: [ex], timeout: 5) } func testMapValuesByKeyPath() { @@ -134,7 +137,7 @@ class ThenableTests: XCTestCase { XCTAssertEqual(["Max", "Roman", "John"], $0) ex.fulfill() }.silenceWarning() - wait(for: [ex], timeout: 10) + wait(for: [ex], timeout: 5) } func testCompactMapValues() { @@ -145,7 +148,7 @@ class ThenableTests: XCTestCase { XCTAssertEqual([1,2,4], $0) ex.fulfill() }.silenceWarning() - wait(for: [ex], timeout: 10) + wait(for: [ex], timeout: 5) } func testCompactMapValuesByKeyPath() { @@ -154,7 +157,7 @@ class ThenableTests: XCTestCase { XCTAssertEqual([26, 23], $0) ex.fulfill() }.silenceWarning() - wait(for: [ex], timeout: 10) + wait(for: [ex], timeout: 5) } func testThenMap() { @@ -165,7 +168,7 @@ class ThenableTests: XCTestCase { XCTAssertEqual([1,2,3,4], $0) ex.fulfill() }.silenceWarning() - wait(for: [ex], timeout: 10) + wait(for: [ex], timeout: 5) } func testThenFlatMap() { @@ -176,7 +179,7 @@ class ThenableTests: XCTestCase { XCTAssertEqual([1,1,2,2,3,3,4,4], $0) ex.fulfill() }.silenceWarning() - wait(for: [ex], timeout: 10) + wait(for: [ex], timeout: 5) } func testFilterValues() { @@ -187,7 +190,7 @@ class ThenableTests: XCTestCase { XCTAssertEqual([Person(name: "John", age: 23, isStudent: true)], $0) ex.fulfill() }.silenceWarning() - wait(for: [ex], timeout: 10) + wait(for: [ex], timeout: 5) } func testFilterValuesByKeyPath() { @@ -196,7 +199,7 @@ class ThenableTests: XCTestCase { XCTAssertEqual([Person(name: "John", age: 23, isStudent: true)], $0) ex.fulfill() }.silenceWarning() - wait(for: [ex], timeout: 10) + wait(for: [ex], timeout: 5) } func testLastValueForEmpty() { @@ -218,7 +221,7 @@ class ThenableTests: XCTestCase { }.catch { _ in ex.fulfill() } - wait(for: [ex], timeout: 10) + wait(for: [ex], timeout: 5) } func testBarrier() { @@ -231,7 +234,7 @@ class ThenableTests: XCTestCase { }.catch { _ in XCTFail() } - wait(for: [ex], timeout: 10) + wait(for: [ex], timeout: 5) } func testDispatchFlagsSyntax() { @@ -244,6 +247,6 @@ class ThenableTests: XCTestCase { }.catch { _ in XCTFail() } - wait(for: [ex], timeout: 10) + wait(for: [ex], timeout: 5) } } diff --git a/Tests/CorePromise/Utilities.swift b/Tests/Core/Utilities.swift similarity index 70% rename from Tests/CorePromise/Utilities.swift rename to Tests/Core/Utilities.swift index 6e9bce694..ebce722e4 100644 --- a/Tests/CorePromise/Utilities.swift +++ b/Tests/Core/Utilities.swift @@ -1,9 +1,14 @@ import PromiseKit +import XCTest extension Promise { func silenceWarning() {} } +extension PMKCascadingFinalizer { + func silenceWarning() {} +} + #if os(Linux) import func CoreFoundation._CFIsMainThread @@ -14,20 +19,26 @@ extension Thread { } } -import XCTest - extension XCTestCase { func wait(for: [XCTestExpectation], timeout: TimeInterval, file: StaticString = #file, line: UInt = #line) { - #if !(swift(>=4.0) && !swift(>=4.1)) - let line = Int(line) - #endif - waitForExpectations(timeout: timeout, file: file, line: line) + waitForExpectations(timeout: timeout, file: file, line: Int(line)) } } +#endif + +#if os(Linux) || os(Windows) extension XCTestExpectation { func fulfill() { fulfill(#file, line: #line) } } #endif + +#if os(Windows) +import class Foundation.Thread + +func usleep(_ us: UInt32) { + Thread.sleep(forTimeInterval: Double(us) / 1_000_000.0) +} +#endif diff --git a/Tests/CorePromise/WhenConcurrentTests.swift b/Tests/Core/WhenConcurrentTests.swift similarity index 94% rename from Tests/CorePromise/WhenConcurrentTests.swift rename to Tests/Core/WhenConcurrentTests.swift index 1b2c8179f..55c62c74d 100644 --- a/Tests/CorePromise/WhenConcurrentTests.swift +++ b/Tests/Core/WhenConcurrentTests.swift @@ -25,7 +25,7 @@ class WhenConcurrentTestCase_Swift: XCTestCase { } }.silenceWarning() - waitForExpectations(timeout: 3, handler: nil) + waitForExpectations(timeout: 5, handler: nil) } func testWhenEmptyGenerator() { @@ -41,7 +41,7 @@ class WhenConcurrentTestCase_Swift: XCTestCase { } }.silenceWarning() - waitForExpectations(timeout: 1, handler: nil) + waitForExpectations(timeout: 5, handler: nil) } func testWhenGeneratorError() { @@ -82,7 +82,7 @@ class WhenConcurrentTestCase_Swift: XCTestCase { e.fulfill() } - waitForExpectations(timeout: 3, handler: nil) + waitForExpectations(timeout: 5, handler: nil) } func testWhenConcurrency() { @@ -113,7 +113,7 @@ class WhenConcurrentTestCase_Swift: XCTestCase { e.fulfill() }.silenceWarning() - waitForExpectations(timeout: 3) + waitForExpectations(timeout: 5) } func testWhenConcurrencyLessThanZero() { @@ -154,11 +154,10 @@ class WhenConcurrentTestCase_Swift: XCTestCase { ex.fulfill() } - waitForExpectations(timeout: 3) + waitForExpectations(timeout: 5) } func testWhenResolvedContinuesWhenRejected() { - #if swift(>=5.3) let ex = expectation(description: "") enum Error: Swift.Error { case dummy } @@ -184,7 +183,6 @@ class WhenConcurrentTestCase_Swift: XCTestCase { ex.fulfill() } - waitForExpectations(timeout: 3) - #endif + waitForExpectations(timeout: 5) } } diff --git a/Tests/CorePromise/WhenResolvedTests.swift b/Tests/Core/WhenResolvedTests.swift similarity index 94% rename from Tests/CorePromise/WhenResolvedTests.swift rename to Tests/Core/WhenResolvedTests.swift index 32bda7bb7..d65cf3728 100644 --- a/Tests/CorePromise/WhenResolvedTests.swift +++ b/Tests/Core/WhenResolvedTests.swift @@ -29,13 +29,13 @@ class JoinTests: XCTestCase { when(resolved: promise1, promise2, promise3).done(on: nil) { _ in finished = true } XCTAssertFalse(finished, "Not all promises have resolved") - seal1.fulfill_() + seal1.fulfill() XCTAssertFalse(finished, "Not all promises have resolved") - seal2.fulfill_() + seal2.fulfill() XCTAssertFalse(finished, "Not all promises have resolved") - seal3.fulfill_() + seal3.fulfill() XCTAssert(finished, "All promises have resolved") } } diff --git a/Tests/CorePromise/WhenTests.swift b/Tests/Core/WhenTests.swift similarity index 91% rename from Tests/CorePromise/WhenTests.swift rename to Tests/Core/WhenTests.swift index 9a6781ac7..d19e72f2c 100644 --- a/Tests/CorePromise/WhenTests.swift +++ b/Tests/Core/WhenTests.swift @@ -16,7 +16,7 @@ class WhenTests: XCTestCase { e2.fulfill() }.silenceWarning() - wait(for: [e1, e2], timeout: 1) + wait(for: [e1, e2], timeout: 5) } func testInt() { @@ -34,7 +34,7 @@ class WhenTests: XCTestCase { XCTAssertEqual(x.count, 4) e1.fulfill() }.silenceWarning() - waitForExpectations(timeout: 1, handler: nil) + waitForExpectations(timeout: 5, handler: nil) } func testDoubleTuple() { @@ -46,7 +46,7 @@ class WhenTests: XCTestCase { XCTAssertEqual(y, "abc") e1.fulfill() }.silenceWarning() - waitForExpectations(timeout: 1, handler: nil) + waitForExpectations(timeout: 5, handler: nil) } func testTripleTuple() { @@ -60,7 +60,7 @@ class WhenTests: XCTestCase { XCTAssertEqual(1.0, w) e1.fulfill() }.silenceWarning() - waitForExpectations(timeout: 1, handler: nil) + waitForExpectations(timeout: 5, handler: nil) } func testQuadrupleTuple() { @@ -76,7 +76,7 @@ class WhenTests: XCTestCase { XCTAssertEqual(true, x) e1.fulfill() }.silenceWarning() - waitForExpectations(timeout: 1, handler: nil) + waitForExpectations(timeout: 5, handler: nil) } func testQuintupleTuple() { @@ -94,7 +94,7 @@ class WhenTests: XCTestCase { XCTAssertEqual("a" as Character, y) e1.fulfill() }.silenceWarning() - waitForExpectations(timeout: 1, handler: nil) + waitForExpectations(timeout: 5, handler: nil) } func testVoid() { @@ -106,7 +106,7 @@ class WhenTests: XCTestCase { when(fulfilled: p1, p2, p3, p4).done(e1.fulfill).silenceWarning() - waitForExpectations(timeout: 1, handler: nil) + waitForExpectations(timeout: 5, handler: nil) } func testRejected() { @@ -121,7 +121,7 @@ class WhenTests: XCTestCase { e1.fulfill() } - waitForExpectations(timeout: 1, handler: nil) + waitForExpectations(timeout: 5, handler: nil) } func testProgress() { @@ -144,7 +144,7 @@ class WhenTests: XCTestCase { progress.resignCurrent() - waitForExpectations(timeout: 1, handler: nil) + waitForExpectations(timeout: 5, handler: nil) } func testProgressDoesNotExceed100Percent() { @@ -185,7 +185,7 @@ class WhenTests: XCTestCase { p3.done(on: q, finally) p4.done(on: q, finally) - waitForExpectations(timeout: 1, handler: nil) + waitForExpectations(timeout: 5, handler: nil) } func testUnhandledErrorHandlerDoesNotFire() { @@ -201,7 +201,7 @@ class WhenTests: XCTestCase { ex.fulfill() } - waitForExpectations(timeout: 1, handler: nil) + waitForExpectations(timeout: 5, handler: nil) } func testUnhandledErrorHandlerDoesNotFireForStragglers() { @@ -227,7 +227,7 @@ class WhenTests: XCTestCase { p2.ensure { after(.milliseconds(100)).done(ex2.fulfill) }.silenceWarning() p3.ensure { after(.milliseconds(100)).done(ex3.fulfill) }.silenceWarning() - waitForExpectations(timeout: 1, handler: nil) + waitForExpectations(timeout: 5, handler: nil) } func testAllSealedRejectedFirstOneRejects() { @@ -248,7 +248,7 @@ class WhenTests: XCTestCase { ex.fulfill() } - waitForExpectations(timeout: 1) + waitForExpectations(timeout: 5) } func testGuaranteeWhen() { @@ -262,6 +262,6 @@ class WhenTests: XCTestCase { ex2.fulfill() } - wait(for: [ex1, ex2], timeout: 10) + wait(for: [ex1, ex2], timeout: 5) } } diff --git a/Tests/CorePromise/ZalgoTests.swift b/Tests/Core/ZalgoTests.swift similarity index 94% rename from Tests/CorePromise/ZalgoTests.swift rename to Tests/Core/ZalgoTests.swift index e3909b4d2..31a4153ab 100644 --- a/Tests/CorePromise/ZalgoTests.swift +++ b/Tests/Core/ZalgoTests.swift @@ -43,7 +43,7 @@ class ZalgoTests: XCTestCase { guard case PMKError.returnedSelf = err else { return XCTFail() } } - waitForExpectations(timeout: 1) + waitForExpectations(timeout: 5) } // return a sealed promise from its own zalgo’d then handler doesn’t hang @@ -54,6 +54,6 @@ class ZalgoTests: XCTestCase { ex.fulfill() return p1 }.silenceWarning() - waitForExpectations(timeout: 1) + waitForExpectations(timeout: 5) } } diff --git a/Tests/CoreObjC/AnyPromiseTests.m b/Tests/CoreObjC/AnyPromiseTests.m deleted file mode 100644 index 0d3003ccf..000000000 --- a/Tests/CoreObjC/AnyPromiseTests.m +++ /dev/null @@ -1,912 +0,0 @@ -@import PromiseKit; -@import XCTest; -#import "Infrastructure.h" -#define PMKTestErrorDomain @"PMKTestErrorDomain" - -static inline NSError *dummyWithCode(NSInteger code) { - return [NSError errorWithDomain:PMKTestErrorDomain code:rand() userInfo:@{NSLocalizedDescriptionKey: @(code).stringValue}]; -} - -static inline NSError *dummy() { - return dummyWithCode(rand()); -} - -static inline AnyPromise *rejectLater() { - return [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) { - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - dispatch_async(dispatch_get_main_queue(), ^{ - resolve(dummy()); - }); - }); - }]; -} - -static inline AnyPromise *fulfillLater() { - return [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) { - dispatch_async(dispatch_get_global_queue(0, 0), ^{ - resolve(@1); - }); - }]; -} - - - -@interface AnyPromiseTestSuite : XCTestCase @end @implementation AnyPromiseTestSuite - -- (void)test_01_resolve { - id ex1 = [self expectationWithDescription:@""]; - - AnyPromise *promise = [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) { - resolve(@1); - }]; - promise.then(^(NSNumber *o){ - [ex1 fulfill]; - XCTAssertEqual(o.intValue, 1); - }); - promise.catch(^{ - XCTFail(); - }); - - [self waitForExpectationsWithTimeout:1 handler:nil]; -} - -- (void)test_02_reject { - id ex1 = [self expectationWithDescription:@""]; - - AnyPromise *promise = [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) { - resolve(dummyWithCode(2)); - }]; - promise.then(^{ - XCTFail(); - }); - promise.catch(^(NSError *error){ - XCTAssertEqualObjects(error.localizedDescription, @"2"); - [ex1 fulfill]; - }); - - [self waitForExpectationsWithTimeout:1 handler:nil]; -} - -- (void)test_03_return_error { - id ex1 = [self expectationWithDescription:@""]; - - AnyPromise *promise = [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) { - resolve(@2); - }]; - promise.then(^{ - return [NSError errorWithDomain:@"a" code:3 userInfo:nil]; - }).catch(^(NSError *e){ - [ex1 fulfill]; - XCTAssertEqual(3, e.code); - }); - promise.catch(^{ - XCTFail(); - }); - - [self waitForExpectationsWithTimeout:1 handler:nil]; -} - -- (void)test_04_return_error_doesnt_compromise_result { - id ex1 = [self expectationWithDescription:@""]; - - AnyPromise *promise = [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) { - resolve(@4); - }].then(^{ - return dummy(); - }); - promise.then(^{ - XCTFail(); - }); - promise.catch(^{ - [ex1 fulfill]; - }); - - [self waitForExpectationsWithTimeout:1 handler:nil]; -} - -- (void)test_05_throw_and_bubble { - id ex1 = [self expectationWithDescription:@""]; - - [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) { - resolve(@5); - }].then(^(id ii){ - XCTAssertEqual(5, [ii intValue]); - return [NSError errorWithDomain:@"a" code:[ii intValue] userInfo:nil]; - }).catch(^(NSError *e){ - XCTAssertEqual(e.code, 5); - [ex1 fulfill]; - }); - - [self waitForExpectationsWithTimeout:1 handler:nil]; -} - -- (void)test_05_throw_and_bubble_more { - id ex1 = [self expectationWithDescription:@""]; - - [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) { - resolve(@5); - }].then(^{ - return dummy(); - }).then(^{ - //NOOP - }).catch(^(NSError *e){ - [ex1 fulfill]; - XCTAssertEqualObjects(e.domain, PMKTestErrorDomain); - }); - - [self waitForExpectationsWithTimeout:1 handler:nil]; -} - -- (void)test_06_return_error { - id ex1 = [self expectationWithDescription:@""]; - - [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) { - resolve(@5); - }].then(^{ - return dummy(); - }).catch(^{ - [ex1 fulfill]; - }); - - [self waitForExpectationsWithTimeout:1 handler:nil]; -} - -- (void)test_07_can_then_resolved { - id ex1 = [self expectationWithDescription:@""]; - - [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) { - resolve(@1); - }].then(^(id o){ - [ex1 fulfill]; - XCTAssertEqualObjects(@1, o); - }); - - [self waitForExpectationsWithTimeout:1 handler:nil]; -} - -- (void)test_07a_can_fail_rejected { - id ex1 = [self expectationWithDescription:@""]; - - [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) { - resolve(dummyWithCode(1)); - }].catch(^(NSError *e){ - [ex1 fulfill]; - XCTAssertEqualObjects(@"1", e.localizedDescription); - }); - - [self waitForExpectationsWithTimeout:1 handler:nil]; -} - -- (void)test_09_async { - id ex1 = [self expectationWithDescription:@""]; - - __block int x = 0; - [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) { - resolve(@1); - }].then(^{ - XCTAssertEqual(x, 0); - x++; - }).then(^{ - XCTAssertEqual(x, 1); - x++; - }).then(^{ - XCTAssertEqual(x, 2); - x++; - }).then(^{ - XCTAssertEqual(x, 3); - x++; - }).then(^{ - XCTAssertEqual(x, 4); - x++; - - [ex1 fulfill]; - }); - - [self waitForExpectationsWithTimeout:1 handler:nil]; - - XCTAssertEqual(x, 5); -} - -- (void)test_10_then_returns_resolved_promise { - id ex1 = [self expectationWithDescription:@""]; - - [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) { - resolve(@10); - }].then(^(id o){ - XCTAssertEqualObjects(@10, o); - return [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) { - resolve(@100); - }]; - }).then(^(id o){ - XCTAssertEqualObjects(@100, o); - [ex1 fulfill]; - }); - - [self waitForExpectationsWithTimeout:1 handler:nil]; -} - -- (void)test_11_then_returns_pending_promise { - id ex1 = [self expectationWithDescription:@""]; - - [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) { - resolve(@1); - }].then(^{ - return fulfillLater(); - }).then(^(id o){ - [ex1 fulfill]; - }); - - [self waitForExpectationsWithTimeout:1 handler:nil]; -} - -- (void)test_12_then_returns_recursive_promises { - id ex1 = [self expectationWithDescription:@""]; - id ex2 = [self expectationWithDescription:@""]; - - __block int x = 0; - fulfillLater().then(^{ - NSLog(@"1"); - XCTAssertEqual(x++, 0); - return fulfillLater().then(^{ - NSLog(@"2"); - XCTAssertEqual(x++, 1); - return fulfillLater().then(^{ - NSLog(@"3"); - XCTAssertEqual(x++, 2); - return fulfillLater().then(^{ - NSLog(@"4"); - XCTAssertEqual(x++, 3); - [ex2 fulfill]; - return @"foo"; - }); - }); - }); - }).then(^(id o){ - NSLog(@"5"); - XCTAssertEqualObjects(@"foo", o); - XCTAssertEqual(x++, 4); - [ex1 fulfill]; - }); - - [self waitForExpectationsWithTimeout:1 handler:nil]; - - XCTAssertEqual(x, 5); -} - - - (void)test_13_then_returns_recursive_promises_that_fails { - id ex1 = [self expectationWithDescription:@""]; - id ex2 = [self expectationWithDescription:@""]; - - fulfillLater().then(^{ - return fulfillLater().then(^{ - return fulfillLater().then(^{ - return fulfillLater().then(^{ - [ex2 fulfill]; - return dummy(); - }); - }); - }); - }).then(^{ - XCTFail(); - }).catch(^(NSError *e){ - XCTAssertEqualObjects(e.domain, PMKTestErrorDomain); - [ex1 fulfill]; - }); - - [self waitForExpectationsWithTimeout:1 handler:nil]; - } - -- (void)test_14_fail_returns_value { - id ex1 = [self expectationWithDescription:@""]; - - [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) { - resolve(@1); - }].then(^{ - return [NSError errorWithDomain:@"a" code:1 userInfo:nil]; - }).catch(^(NSError *e){ - XCTAssertEqual(e.code, 1); - return @2; - }).then(^(id o){ - XCTAssertEqualObjects(o, @2); - [ex1 fulfill]; - }); - - [self waitForExpectationsWithTimeout:1 handler:nil]; -} - -- (void)test_15_fail_returns_promise { - id ex1 = [self expectationWithDescription:@""]; - - [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) { - resolve(@1); - }].then(^{ - return dummy(); - }).catch(^{ - return fulfillLater().then(^{ - return @123; - }); - }).then(^(id o){ - XCTAssertEqualObjects(o, @123); - [ex1 fulfill]; - }); - - [self waitForExpectationsWithTimeout:1 handler:nil]; -} - -- (void)test_23_add_another_fail_to_already_rejected { - id ex1 = [self expectationWithDescription:@""]; - id ex2 = [self expectationWithDescription:@""]; - - PMKResolver resolve; - AnyPromise *promise = [[AnyPromise alloc] initWithResolver:&resolve]; - - promise.then(^{ - XCTFail(); - }).catch(^(NSError *e){ - XCTAssertEqualObjects(e.localizedDescription, @"23"); - [ex1 fulfill]; - }); - - resolve(dummyWithCode(23)); - - promise.then(^{ - XCTFail(); - }).catch(^(NSError *e){ - XCTAssertEqualObjects(e.localizedDescription, @"23"); - [ex2 fulfill]; - }); - [self waitForExpectationsWithTimeout:1 handler:nil]; -} - -- (void)test_25_then_plus_deferred_plus_GCD { - id ex1 = [self expectationWithDescription:@""]; - id ex2 = [self expectationWithDescription:@""]; - id ex3 = [self expectationWithDescription:@""]; - - fulfillLater().then(^(id o){ - [ex1 fulfill]; - return fulfillLater().then(^{ - return @YES; - }); - }).then(^(id o){ - XCTAssertEqualObjects(@YES, o); - [ex2 fulfill]; - }).then(^(id o){ - XCTAssertNil(o); - [ex3 fulfill]; - }).catch(^{ - XCTFail(); - }); - - [self waitForExpectationsWithTimeout:1 handler:nil]; -} - -- (void)test_26_promise_then_promise_fail_promise_fail { - id ex1 = [self expectationWithDescription:@""]; - - fulfillLater().then(^{ - return fulfillLater().then(^{ - return dummy(); - }).catch(^{ - return fulfillLater().then(^{ - return dummy(); - }); - }); - }).then(^{ - XCTFail(); - }).catch(^{ - [ex1 fulfill]; - }); - - [self waitForExpectationsWithTimeout:1 handler:nil];} - -- (void)test_27_eat_failure { - id ex1 = [self expectationWithDescription:@""]; - - fulfillLater().then(^{ - return dummy(); - }).catch(^{ - return @YES; - }).then(^{ - [ex1 fulfill]; - }); - - [self waitForExpectationsWithTimeout:1 handler:nil]; -} - -- (void)test_28_deferred_rejected_catch_promise { - id ex1 = [self expectationWithDescription:@""]; - id ex2 = [self expectationWithDescription:@""]; - - rejectLater().catch(^{ - [ex1 fulfill]; - return fulfillLater(); - }).then(^(id o){ - [ex2 fulfill]; - }).catch(^{ - XCTFail(); - }); - - [self waitForExpectationsWithTimeout:1 handler:nil]; -} - -- (void)test_29_deferred_rejected_catch_promise { - id ex1 = [self expectationWithDescription:@""]; - id ex2 = [self expectationWithDescription:@""]; - - rejectLater().catch(^{ - [ex1 fulfill]; - return fulfillLater().then(^{ - return dummy(); - }); - }).then(^{ - XCTFail(@"1"); - }).catch(^(NSError *error){ - [ex2 fulfill]; - }).catch(^{ - XCTFail(@"2"); - }); - - [self waitForExpectationsWithTimeout:1 handler:nil]; -} - -- (void)test_30_dispatch_returns_pending_promise { - id ex1 = [self expectationWithDescription:@""]; - dispatch_promise(^{ - return fulfillLater(); - }).then(^{ - [ex1 fulfill]; - }); - [self waitForExpectationsWithTimeout:1 handler:nil]; -} - -- (void)test_31_dispatch_returns_promise { - id ex1 = [self expectationWithDescription:@""]; - dispatch_promise(^{ - return [AnyPromise promiseWithValue:@1]; - }).then(^(id o){ - XCTAssertEqualObjects(o, @1); - [ex1 fulfill]; - }); - [self waitForExpectationsWithTimeout:1 handler:nil]; -} - -- (void)test_32_return_primitive { - id ex1 = [self expectationWithDescription:@""]; - __block void (^fulfiller)(id) = nil; - [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) { - fulfiller = resolve; - }].then(^(id o){ - XCTAssertEqualObjects(o, @32); - return 3; - }).then(^(id o){ - XCTAssertEqualObjects(@3, o); - [ex1 fulfill]; - }); - fulfiller(@32); - [self waitForExpectationsWithTimeout:1 handler:nil]; -} - -- (void)test_33_return_nil { - id ex1 = [self expectationWithDescription:@""]; - [AnyPromise promiseWithValue:@1].then(^(id o){ - XCTAssertEqualObjects(o, @1); - return nil; - }).then(^{ - return nil; - }).then(^(id o){ - XCTAssertNil(o); - [ex1 fulfill]; - }); - [self waitForExpectationsWithTimeout:1 handler:nil]; -} - -- (void)test_33a_return_nil { - id ex1 = [self expectationWithDescription:@""]; - id ex2 = [self expectationWithDescription:@""]; - - [AnyPromise promiseWithValue:@"HI"].then(^(id o){ - XCTAssertEqualObjects(o, @"HI"); - [ex1 fulfill]; - return nil; - }).then(^{ - return nil; - }).then(^{ - [ex2 fulfill]; - return nil; - }); - - [self waitForExpectationsWithTimeout:1 handler:nil]; -} - -- (void)test_36_promise_with_value_nil { - id ex1 = [self expectationWithDescription:@""]; - - [AnyPromise promiseWithValue:nil].then(^(id o){ - XCTAssertNil(o); - [ex1 fulfill]; - }); - [self waitForExpectationsWithTimeout:1 handler:nil]; -} - -- (void)test_42 { - id ex1 = [self expectationWithDescription:@""]; - - [AnyPromise promiseWithValue:@1].then(^{ - return fulfillLater(); - }).then(^{ - [ex1 fulfill]; - }); - - [self waitForExpectationsWithTimeout:1 handler:nil]; -} - -- (void)test_43_return_promise_from_itself { - id ex1 = [self expectationWithDescription:@""]; - - AnyPromise *p = fulfillLater().then(^{ return @1; }); - p.then(^{ - return p; - }).then(^{ - [ex1 fulfill]; - }); - - [self waitForExpectationsWithTimeout:1 handler:nil]; -} - -- (void)test_44_reseal { - id ex1 = [self expectationWithDescription:@""]; - - [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) { - resolve(@123); - resolve(@234); - }].then(^(id o){ - XCTAssertEqualObjects(o, @123); - [ex1 fulfill]; - }); - - [self waitForExpectationsWithTimeout:1 handler:nil]; -} - -- (void)test_46_test_then_on { - id ex1 = [self expectationWithDescription:@""]; - - dispatch_queue_t q1 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0); - dispatch_queue_t q2 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0); - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - [AnyPromise promiseWithValue:@1].thenOn(q1, ^{ - XCTAssertFalse([NSThread isMainThread]); - return dispatch_get_current_queue(); - }).thenOn(q2, ^(id q){ - XCTAssertFalse([NSThread isMainThread]); - XCTAssertNotEqualObjects(q, dispatch_get_current_queue()); - [ex1 fulfill]; - }); -#pragma clang diagnostic pop - - [self waitForExpectationsWithTimeout:1 handler:nil]; -} - -- (void)test_47_finally_plus { - id ex1 = [self expectationWithDescription:@""]; - - [AnyPromise promiseWithValue:@1].then(^{ - return @1; - }).ensure(^{ - [ex1 fulfill]; - }); - - [self waitForExpectationsWithTimeout:1 handler:nil]; -} - -- (void)test_48_finally_negative { - @autoreleasepool { - id ex1 = [self expectationWithDescription:@"always"]; - id ex2 = [self expectationWithDescription:@"errorUnhandler"]; - - [AnyPromise promiseWithValue:@1].then(^{ - return dummy(); - }).ensure(^{ - [ex1 fulfill]; - }).catch(^(NSError *err){ - XCTAssertEqualObjects(err.domain, PMKTestErrorDomain); - [ex2 fulfill]; - }); - } - - [self waitForExpectationsWithTimeout:1 handler:nil]; -} - -- (void)test_49_finally_negative_later { - id ex1 = [self expectationWithDescription:@""]; - __block int x = 0; - - [AnyPromise promiseWithValue:@1].then(^{ - XCTAssertEqual(++x, 1); - return dummy(); - }).catch(^{ - XCTAssertEqual(++x, 2); - }).then(^{ - XCTAssertEqual(++x, 3); - }).ensure(^{ - XCTAssertEqual(++x, 4); - [ex1 fulfill]; - }); - - [self waitForExpectationsWithTimeout:1 handler:nil]; -} - -- (void)test_50_fulfill_with_pending_promise { - id ex1 = [self expectationWithDescription:@""]; - - [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) { - resolve(fulfillLater().then(^{ return @"HI"; })); - }].then(^(id hi){ - XCTAssertEqualObjects(hi, @"HI"); - [ex1 fulfill]; - }); - - [self waitForExpectationsWithTimeout:1 handler:nil]; -} - -- (void)test_51_fulfill_with_fulfilled_promise { - id ex1 = [self expectationWithDescription:@""]; - - [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) { - resolve([AnyPromise promiseWithValue:@1]); - }].then(^(id o){ - XCTAssertEqualObjects(o, @1); - [ex1 fulfill]; - }); - - [self waitForExpectationsWithTimeout:1 handler:nil]; -} - -- (void)test_52_fulfill_with_rejected_promise { //NEEDEDanypr - id ex1 = [self expectationWithDescription:@""]; - fulfillLater().then(^{ - return [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) { - resolve([AnyPromise promiseWithValue:dummy()]); - }]; - }).catch(^(NSError *err){ - [ex1 fulfill]; - }); - [self waitForExpectationsWithTimeout:1 handler:nil]; -} - -- (void)test_53_return_rejected_promise { - id ex1 = [self expectationWithDescription:@""]; - fulfillLater().then(^{ - return @1; - }).then(^{ - return [AnyPromise promiseWithValue:dummy()]; - }).catch(^{ - [ex1 fulfill]; - }); - [self waitForExpectationsWithTimeout:1 handler:nil]; -} - -- (void)test_54_reject_with_rejected_promise { - id ex1 = [self expectationWithDescription:@""]; - - [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) { - id err = [NSError errorWithDomain:@"a" code:123 userInfo:nil]; - resolve([AnyPromise promiseWithValue:err]); - }].catch(^(NSError *err){ - XCTAssertEqual(err.code, 123); - [ex1 fulfill]; - }); - - [self waitForExpectationsWithTimeout:1 handler:nil]; -} - -- (void)test_58_just_finally { - id ex1 = [self expectationWithDescription:@""]; - - AnyPromise *promise = fulfillLater().then(^{ - return nil; - }).ensure(^{ - [ex1 fulfill]; - }); - - [self waitForExpectationsWithTimeout:1 handler:nil]; - - id ex2 = [self expectationWithDescription:@""]; - - promise.ensure(^{ - [ex2 fulfill]; - }); - - [self waitForExpectationsWithTimeout:1 handler:nil]; -} - -- (void)test_59_catch_in_background { - id ex1 = [self expectationWithDescription:@""]; - - [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) { - id err = [NSError errorWithDomain:@"a" code:123 userInfo:nil]; - resolve(err); - }].catchInBackground(^(NSError *err){ - XCTAssertEqual(err.code, 123); - XCTAssertFalse([NSThread isMainThread]); - [ex1 fulfill]; - }); - - [self waitForExpectationsWithTimeout:1 handler:nil]; -} - -- (void)test_60_catch_on_specific_queue { - id ex1 = [self expectationWithDescription:@""]; - - NSString *expectedQueueName = @"specific queue 123"; - dispatch_queue_t q = dispatch_queue_create(expectedQueueName.UTF8String, DISPATCH_QUEUE_SERIAL); - - [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) { - id err = [NSError errorWithDomain:@"a" code:123 userInfo:nil]; - resolve(err); - }].catchOn(q, ^(NSError *err){ - XCTAssertEqual(err.code, 123); - XCTAssertFalse([NSThread isMainThread]); - NSString *currentQueueName = [NSString stringWithFormat:@"%s", dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL)]; - XCTAssertEqualObjects(expectedQueueName, currentQueueName); - [ex1 fulfill]; - }); - - [self waitForExpectationsWithTimeout:1 handler:nil]; -} - -- (void)test_61_wait_for_value { - id o = [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) { - resolve(@1); - }].wait; - - XCTAssertEqualObjects(o, @1); -} - -- (void)test_62_wait_for_error { - NSError* err = [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) { - resolve([NSError errorWithDomain:@"a" code:123 userInfo:nil]); - }].wait; - - XCTAssertEqual(err.code, 123); -} - -- (void)test_properties { - XCTAssertEqualObjects([AnyPromise promiseWithValue:@1].value, @1); - XCTAssertEqualObjects([[AnyPromise promiseWithValue:dummyWithCode(2)].value localizedDescription], @"2"); - XCTAssertNil([AnyPromise promiseWithResolverBlock:^(id a){}].value); - XCTAssertTrue([AnyPromise promiseWithResolverBlock:^(id a){}].pending); - XCTAssertFalse([AnyPromise promiseWithValue:@1].pending); - XCTAssertTrue([AnyPromise promiseWithValue:@1].fulfilled); - XCTAssertFalse([AnyPromise promiseWithValue:@1].rejected); -} - -- (void)test_promiseWithValue { - XCTAssertEqual([AnyPromise promiseWithValue:@1].value, @1); - XCTAssertEqualObjects([[AnyPromise promiseWithValue:dummyWithCode(2)].value localizedDescription], @"2"); - XCTAssertEqual([AnyPromise promiseWithValue:[AnyPromise promiseWithValue:@1]].value, @1); -} - -- (void)test_race { - id ex = [self expectationWithDescription:@""]; - id p = PMKAfter(0.1).then(^{ return @2; }); - PMKRace(@[PMKAfter(10), PMKAfter(20), p]).then(^(id obj){ - XCTAssertEqual(2, [obj integerValue]); - [ex fulfill]; - }); - [self waitForExpectationsWithTimeout:1 handler:nil]; -} - -- (void)testInBackground { - id ex = [self expectationWithDescription:@""]; - PMKAfter(0.1).thenInBackground(^{ [ex fulfill]; }); - [self waitForExpectationsWithTimeout:1 handler:nil]; -} - -- (void)testEnsureOn { - id ex = [self expectationWithDescription:@""]; - PMKAfter(0.1).ensureOn(dispatch_get_global_queue(0, 0), ^{ [ex fulfill]; }); - [self waitForExpectationsWithTimeout:1 handler:nil]; -} - -- (void)testAdapterBlock { - void (^fetch)(PMKAdapter) = ^(PMKAdapter block){ - block(@1, nil); - }; - id ex = [self expectationWithDescription:@""]; - [AnyPromise promiseWithAdapterBlock:fetch].then(^(id obj){ - XCTAssertEqualObjects(obj, @1); - [ex fulfill]; - }); - [self waitForExpectationsWithTimeout:1 handler:nil]; -} - -- (void)testIntegerAdapterBlock { - void (^fetch)(PMKIntegerAdapter) = ^(PMKIntegerAdapter block){ - block(1, nil); - }; - id ex = [self expectationWithDescription:@""]; - [AnyPromise promiseWithIntegerAdapterBlock:fetch].then(^(id obj){ - XCTAssertEqualObjects(obj, @1); - [ex fulfill]; - }); - [self waitForExpectationsWithTimeout:1 handler:nil]; -} - -- (void)testBooleanAdapterBlock { - void (^fetch)(PMKBooleanAdapter) = ^(PMKBooleanAdapter block){ - block(YES, nil); - }; - id ex = [self expectationWithDescription:@""]; - [AnyPromise promiseWithBooleanAdapterBlock:fetch].then(^(id obj){ - XCTAssertEqualObjects(obj, @YES); - [ex fulfill]; - }); - [self waitForExpectationsWithTimeout:1 handler:nil]; -} - -static NSHashTable *errorArray; - -- (void)setUp { - [super setUp]; - errorArray = [NSHashTable weakObjectsHashTable]; -} - -- (void)testErrorLeaks { - id ex1 = [self expectationWithDescription:@""]; - NSError *error = dummyWithCode(1001); - [errorArray addObject:error]; - [AnyPromise promiseWithValue:error] - .then(^{ - XCTFail(); - }).catch(^(NSError *e){ - XCTAssertEqual(e.localizedDescription.intValue, 1001); - }).then(^{ - NSError *err = dummyWithCode(1002); - [errorArray addObject:err]; - return err; - }).catch(^(NSError *e){ - XCTAssertEqual(e.localizedDescription.intValue, 1002); - }).then(^{ - NSError *err = dummyWithCode(1003); - [errorArray addObject:err]; - return [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve){ - resolve(err); - }]; - }).catch(^(NSError *e){ - XCTAssertEqual(e.localizedDescription.intValue, 1003); - NSError *err = dummyWithCode(1004); - [errorArray addObject:err]; - return err; - }).catch(^(NSError *e){ - XCTAssertEqual(e.localizedDescription.intValue, 1004); - }).then(^{ - NSError *err = dummyWithCode(1005); - [errorArray addObject:err]; - // throw will lead to leak, if not use complie flag with "-fobjc-arc-exceptions" - @throw err; - }).catch(^(NSError *e){ - XCTAssertEqual(e.localizedDescription.intValue, 1005); - }).ensure(^{ - [ex1 fulfill]; - }); - - [self waitForExpectationsWithTimeout:1 handler:nil]; -} - -- (void)tearDown { - XCTAssertEqual(errorArray.allObjects.count, 0); - [super tearDown]; -} - -//- (void)test_nil_block { -// [AnyPromise promiseWithValue:@1].then(nil); -// [AnyPromise promiseWithValue:@1].thenOn(nil, nil); -// [AnyPromise promiseWithValue:@1].catch(nil); -// [AnyPromise promiseWithValue:@1].always(nil); -// [AnyPromise promiseWithValue:@1].alwaysOn(nil, nil); -//} - -@end diff --git a/Tests/CoreObjC/AnyPromiseTests.swift b/Tests/CoreObjC/AnyPromiseTests.swift deleted file mode 100644 index adbc68f78..000000000 --- a/Tests/CoreObjC/AnyPromiseTests.swift +++ /dev/null @@ -1,38 +0,0 @@ -import PromiseKit -import XCTest - -class AnyPromiseTests: XCTestCase { - func testFulfilledResult() { - switch AnyPromise(Promise.value(true)).result { - case .fulfilled(let obj as Bool)? where obj: - break - default: - XCTFail() - } - } - - func testRejectedResult() { - switch AnyPromise(Promise(error: PMKError.badInput)).result { - case .rejected(let err)?: - print(err) - break - default: - XCTFail() - } - } - - func testPendingResult() { - switch AnyPromise(Promise.pending().promise).result { - case nil: - break - default: - XCTFail() - } - } - - func testCustomStringConvertible() { - XCTAssertEqual("\(AnyPromise(Promise.pending().promise))", "AnyPromise(…)") - XCTAssertEqual("\(AnyPromise(Promise.value(1)))", "AnyPromise(1)") - XCTAssertEqual("\(AnyPromise(Promise.value(nil)))", "AnyPromise(nil)") - } -} diff --git a/Tests/CoreObjC/HangTests.m b/Tests/CoreObjC/HangTests.m deleted file mode 100644 index cf31ead97..000000000 --- a/Tests/CoreObjC/HangTests.m +++ /dev/null @@ -1,13 +0,0 @@ -@import PromiseKit; -@import XCTest; - -@interface HangTests: XCTestCase @end @implementation HangTests - -- (void)test { - __block int x = 0; - id value = PMKHang(PMKAfter(0.02).then(^{ x++; return 1; })); - XCTAssertEqual(x, 1); - XCTAssertEqualObjects(value, @1); -} - -@end diff --git a/Tests/CoreObjC/JoinTests.m b/Tests/CoreObjC/JoinTests.m deleted file mode 100644 index 1249cde0f..000000000 --- a/Tests/CoreObjC/JoinTests.m +++ /dev/null @@ -1,90 +0,0 @@ -@import Foundation; -@import PromiseKit; -@import XCTest; - - -@interface JoinTests: XCTestCase @end @implementation JoinTests - -- (void)test_73_join { - XCTestExpectation *ex1 = [self expectationWithDescription:@""]; - - __block void (^fulfiller)(id) = nil; - AnyPromise *promise = [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) { - fulfiller = resolve; - }]; - - PMKJoin(@[ - [AnyPromise promiseWithValue:[NSError errorWithDomain:@"dom" code:1 userInfo:nil]], - promise, - [AnyPromise promiseWithValue:[NSError errorWithDomain:@"dom" code:2 userInfo:nil]] - ]).then(^{ - XCTFail(); - }).catch(^(NSError *error){ - id promises = error.userInfo[PMKJoinPromisesKey]; - - int cume = 0, cumv = 0; - - for (AnyPromise *promise in promises) { - if ([promise.value isKindOfClass:[NSError class]]) { - cume |= [promise.value code]; - } else { - cumv |= [promise.value unsignedIntValue]; - } - } - - XCTAssertTrue(cumv == 4); - XCTAssertTrue(cume == 3); - - [ex1 fulfill]; - }); - fulfiller(@4); - [self waitForExpectationsWithTimeout:1 handler:nil]; -} - -- (void)test_74_join_no_errors { - XCTestExpectation *ex1 = [self expectationWithDescription:@""]; - PMKJoin(@[ - [AnyPromise promiseWithValue:@1], - [AnyPromise promiseWithValue:@2] - ]).then(^(NSArray *values, id errors) { - XCTAssertEqualObjects(values, (@[@1, @2])); - XCTAssertNil(errors); - [ex1 fulfill]; - }); - [self waitForExpectationsWithTimeout:1 handler:nil]; -} - - -- (void)test_75_join_no_success { - XCTestExpectation *ex1 = [self expectationWithDescription:@""]; - PMKJoin(@[ - [AnyPromise promiseWithValue:[NSError errorWithDomain:@"dom" code:1 userInfo:nil]], - [AnyPromise promiseWithValue:[NSError errorWithDomain:@"dom" code:2 userInfo:nil]], - ]).then(^{ - XCTFail(); - }).catch(^(NSError *error){ - XCTAssertNotNil(error.userInfo[PMKJoinPromisesKey]); - [ex1 fulfill]; - }); - [self waitForExpectationsWithTimeout:1 handler:nil]; -} - -- (void)test_76_join_fulfills_if_empty_input { - XCTestExpectation *ex1 = [self expectationWithDescription:@""]; - PMKJoin(@[]).then(^(id a, id b, id c){ - XCTAssertEqualObjects(@[], a); - XCTAssertNil(b); - XCTAssertNil(c); - [ex1 fulfill]; - }); - [self waitForExpectationsWithTimeout:1 handler:nil]; -} - -- (void)test_join_nil { - NSArray *foo = nil; - NSError *err = PMKJoin(foo).value; - XCTAssertEqual(err.domain, PMKErrorDomain); - XCTAssertEqual(err.code, PMKInvalidUsageError); -} - -@end diff --git a/Tests/CoreObjC/PMKManifoldTests.m b/Tests/CoreObjC/PMKManifoldTests.m deleted file mode 100644 index 78248d6a4..000000000 --- a/Tests/CoreObjC/PMKManifoldTests.m +++ /dev/null @@ -1,83 +0,0 @@ -@import PromiseKit; -@import XCTest; - -@interface PMKManifoldTests: XCTestCase @end @implementation PMKManifoldTests - -- (void)test_62_access_extra_elements { - id ex1 = [self expectationWithDescription:@""]; - - [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) { - resolve(PMKManifold(@1)); - }].then(^(id o, id m, id n){ - XCTAssertNil(m, @"Accessing extra elements should not crash"); - XCTAssertNil(n, @"Accessing extra elements should not crash"); - XCTAssertEqualObjects(o, @1); - [ex1 fulfill]; - }); - - [self waitForExpectationsWithTimeout:1 handler:nil]; -} - -- (void)test_63_then_manifold { - id ex1 = [self expectationWithDescription:@""]; - - [AnyPromise promiseWithValue:@0].then(^{ - return PMKManifold(@1, @2, @3); - }).then(^(id o1, id o2, id o3){ - XCTAssertEqualObjects(o1, @1); - XCTAssertEqualObjects(o2, @2); - XCTAssertEqualObjects(o3, @3); - [ex1 fulfill]; - }); - - [self waitForExpectationsWithTimeout:1 handler:nil]; -} - -- (void)test_63_then_manifold_with_nil { - id ex1 = [self expectationWithDescription:@""]; - - [AnyPromise promiseWithValue:@0].then(^{ - return PMKManifold(@1, nil, @3); - }).then(^(id o1, id o2, id o3){ - XCTAssertEqualObjects(o1, @1); - XCTAssertEqualObjects(o2, nil); - XCTAssertEqualObjects(o3, @3); - [ex1 fulfill]; - }); - - [self waitForExpectationsWithTimeout:1 handler:nil]; -} - -- (void)test_65_manifold_fulfill_value { - id ex1 = [self expectationWithDescription:@""]; - - AnyPromise *promise = [AnyPromise promiseWithValue:@1].then(^{ - return PMKManifold(@123, @2); - }); - - promise.then(^(id a, id b){ - XCTAssertNotNil(a); - XCTAssertNotNil(b); - [ex1 fulfill]; - }); - - [self waitForExpectationsWithTimeout:1 handler:nil]; - - XCTAssertEqualObjects(promise.value, @123); -} - -- (void)test_37_PMKMany_2 { - id ex1 = [self expectationWithDescription:@""]; - - PMKAfter(0.02).then(^{ - return PMKManifold(@1, @2); - }).then(^(id a, id b){ - XCTAssertEqualObjects(a, @1); - XCTAssertEqualObjects(b, @2); - [ex1 fulfill]; - }); - - [self waitForExpectationsWithTimeout:1 handler:nil]; -} - -@end diff --git a/Tests/CoreObjC/WhenTests.m b/Tests/CoreObjC/WhenTests.m deleted file mode 100644 index 20267c156..000000000 --- a/Tests/CoreObjC/WhenTests.m +++ /dev/null @@ -1,265 +0,0 @@ -@import Foundation; -@import PromiseKit; -@import XCTest; - - -@interface WhenTests: XCTestCase @end @implementation WhenTests - -- (void)testProgress { - - id ex = [self expectationWithDescription:@""]; - - XCTAssertNil([NSProgress currentProgress]); - - id p1 = PMKAfter(0.01); - id p2 = PMKAfter(0.02); - id p3 = PMKAfter(0.03); - id p4 = PMKAfter(0.04); - - NSProgress *progress = [NSProgress progressWithTotalUnitCount:1]; - [progress becomeCurrentWithPendingUnitCount:1]; - - PMKWhen(@[p1, p2, p3, p4]).then(^{ - XCTAssertEqual(progress.completedUnitCount, 1); - [ex fulfill]; - }); - - [progress resignCurrent]; - - [self waitForExpectationsWithTimeout:5 handler:nil]; -} - -- (void)testProgressDoesNotExceed100Percent { - - id ex1 = [self expectationWithDescription:@""]; - id ex2 = [self expectationWithDescription:@""]; - - XCTAssertNil([NSProgress currentProgress]); - - id p1 = PMKAfter(0.01); - id p2 = PMKAfter(0.02).then(^{ return [NSError errorWithDomain:@"a" code:1 userInfo:nil]; }); - id p3 = PMKAfter(0.03); - id p4 = PMKAfter(0.04); - - id promises = @[p1, p2, p3, p4]; - - NSProgress *progress = [NSProgress progressWithTotalUnitCount:1]; - [progress becomeCurrentWithPendingUnitCount:1]; - - PMKWhen(promises).catch(^{ - [ex2 fulfill]; - }); - - [progress resignCurrent]; - - PMKJoin(promises).catch(^{ - XCTAssertLessThanOrEqual(1, progress.fractionCompleted); - XCTAssertEqual(progress.completedUnitCount, 1); - [ex1 fulfill]; - }); - - [self waitForExpectationsWithTimeout:1 handler:nil]; -} - -- (void)testWhenManifolds { - id ex = [self expectationWithDescription:@""]; - id p1 = dispatch_promise(^{ return PMKManifold(@1, @2); }); - id p2 = dispatch_promise(^{}); - PMKWhen(@[p1, p2]).then(^(NSArray *results){ - XCTAssertEqualObjects(results[0], @1); - XCTAssertEqualObjects(results[1], [NSNull null]); - [ex fulfill]; - }); - [self waitForExpectationsWithTimeout:1 handler:nil]; -} - -- (void)test_55_all_dictionary { - id ex1 = [self expectationWithDescription:@""]; - - id promises = @{ - @1: @2, - @2: @"abc", - @"a": PMKAfter(0.1).then(^{ return @"HI"; }) - }; - PMKWhen(promises).then(^(NSDictionary *dict){ - XCTAssertEqual(dict.count, 3ul); - XCTAssertEqualObjects(dict[@1], @2); - XCTAssertEqualObjects(dict[@2], @"abc"); - XCTAssertEqualObjects(dict[@"a"], @"HI"); - [ex1 fulfill]; - }); - - [self waitForExpectationsWithTimeout:1 handler:nil]; -} - -- (void)test_56_empty_array_when { - id ex1 = [self expectationWithDescription:@""]; - - PMKWhen(@[]).then(^(NSArray *array){ - XCTAssertEqual(array.count, 0ul); - [ex1 fulfill]; - }); - - [self waitForExpectationsWithTimeout:1 handler:nil]; -} - -- (void)test_57_empty_array_all { - id ex1 = [self expectationWithDescription:@""]; - - PMKWhen(@[]).then(^(NSArray *array){ - XCTAssertEqual(array.count, 0ul); - [ex1 fulfill]; - }); - - [self waitForExpectationsWithTimeout:1 handler:nil]; -} - -- (void)test_18_when { - id ex1 = [self expectationWithDescription:@""]; - - id a = PMKAfter(0.02).then(^{ return @345; }); - id b = PMKAfter(0.03).then(^{ return @345; }); - PMKWhen(@[a, b]).then(^(NSArray *objs){ - XCTAssertEqual(objs.count, 2ul); - XCTAssertEqualObjects(objs[0], objs[1]); - [ex1 fulfill]; - }); - [self waitForExpectationsWithTimeout:1 handler:nil]; -} - -- (void)test_21_recursive_when { - id domain = @"sdjhfg"; - - id ex1 = [self expectationWithDescription:@""]; - id a = PMKAfter(0.03).then(^{ - return [NSError errorWithDomain:domain code:123 userInfo:nil]; - }); - id b = PMKAfter(0.02); - id c = PMKWhen(@[a, b]); - PMKWhen(c).then(^{ - XCTFail(); - }).catch(^(NSError *e){ - XCTAssertEqualObjects(e.userInfo[PMKFailingPromiseIndexKey], @0); - XCTAssertEqualObjects(e.domain, domain); - [ex1 fulfill]; - }); - [self waitForExpectationsWithTimeout:1 handler:nil]; -} - -- (void)test_22_already_resolved_and_bubble { - id ex1 = [self expectationWithDescription:@""]; - id ex2 = [self expectationWithDescription:@""]; - - PMKResolver resolve; - AnyPromise *promise = [[AnyPromise alloc] initWithResolver:&resolve]; - - promise.then(^{ - XCTFail(); - }).catch(^(NSError *e){ - [ex1 fulfill]; - }); - - resolve([NSError errorWithDomain:@"a" code:1 userInfo:nil]); - - PMKWhen(promise).then(^{ - XCTFail(); - }).catch(^{ - [ex2 fulfill]; - }); - - [self waitForExpectationsWithTimeout:1 handler:nil]; -} - -- (void)test_24_some_edge_case { - id ex1 = [self expectationWithDescription:@""]; - id a = PMKAfter(0.02).catch(^{}); - id b = PMKAfter(0.03); - PMKWhen(@[a, b]).then(^(NSArray *objs){ - [ex1 fulfill]; - }); - [self waitForExpectationsWithTimeout:1 handler:nil]; -} - -- (void)test_35_when_nil { - id ex1 = [self expectationWithDescription:@""]; - - AnyPromise *promise = [AnyPromise promiseWithValue:@"35"].then(^{ return nil; }); - PMKWhen(@[PMKAfter(0.02).then(^{ return @1; }), [AnyPromise promiseWithValue:nil], promise]).then(^(NSArray *results){ - XCTAssertEqual(results.count, 3ul); - XCTAssertEqualObjects(results[1], [NSNull null]); - [ex1 fulfill]; - }).catch(^(NSError *err){ - abort(); - }); - [self waitForExpectationsWithTimeout:1 handler:nil]; -} - - -- (void)test_39_when_with_some_values { - id ex1 = [self expectationWithDescription:@""]; - - id p = PMKAfter(0.02); - id v = @1; - PMKWhen(@[p, v]).then(^(NSArray *aa){ - XCTAssertEqual(aa.count, 2ul); - XCTAssertEqualObjects(aa[1], @1); - [ex1 fulfill]; - }); - - [self waitForExpectationsWithTimeout:1 handler:nil]; -} - -- (void)test_40_when_with_all_values { - id ex1 = [self expectationWithDescription:@""]; - - PMKWhen(@[@1, @2]).then(^(NSArray *aa){ - XCTAssertEqualObjects(aa[0], @1); - XCTAssertEqualObjects(aa[1], @2); - [ex1 fulfill]; - }); - - [self waitForExpectationsWithTimeout:1 handler:nil]; -} - -- (void)test_41_when_with_repeated_promises { - id ex1 = [self expectationWithDescription:@""]; - - id p = PMKAfter(0.02); - id v = @1; - PMKWhen(@[p, v, p, v]).then(^(NSArray *aa){ - XCTAssertEqual(aa.count, 4ul); - XCTAssertEqualObjects(aa[1], @1); - XCTAssertEqualObjects(aa[3], @1); - [ex1 fulfill]; - }); - - [self waitForExpectationsWithTimeout:1 handler:nil]; -} - -- (void)test_45_when_which_returns_void { - id ex1 = [self expectationWithDescription:@""]; - - AnyPromise *promise = [AnyPromise promiseWithValue:@1].then(^{}); - PMKWhen(@[promise, [AnyPromise promiseWithValue:@1]]).then(^(NSArray *stuff){ - XCTAssertEqual(stuff.count, 2ul); - XCTAssertEqualObjects(stuff[0], [NSNull null]); - [ex1 fulfill]; - }); - - [self waitForExpectationsWithTimeout:1 handler:nil]; -} - -- (void)test_when_nil { - NSArray *foo = nil; - NSError *err = PMKWhen(foo).value; - XCTAssertEqual(err.domain, PMKErrorDomain); - XCTAssertEqual(err.code, PMKInvalidUsageError); -} - - -- (void)test_when_bad_input { - id foo = @"a"; - XCTAssertEqual(PMKWhen(foo).value, foo); -} - -@end diff --git a/Tests/CorePromise/AfterTests.swift b/Tests/CorePromise/AfterTests.swift deleted file mode 100644 index 6b587c954..000000000 --- a/Tests/CorePromise/AfterTests.swift +++ /dev/null @@ -1,52 +0,0 @@ -import PromiseKit -import XCTest - -class AfterTests: XCTestCase { - func testZero() { - let ex2 = expectation(description: "") - after(seconds: 0).done(ex2.fulfill) - waitForExpectations(timeout: 2, handler: nil) - - let ex3 = expectation(description: "") - after(.seconds(0)).done(ex3.fulfill) - waitForExpectations(timeout: 2, handler: nil) - - #if !SWIFT_PACKAGE - let ex4 = expectation(description: "") - __PMKAfter(0).done{ _ in ex4.fulfill() }.silenceWarning() - waitForExpectations(timeout: 2, handler: nil) - #endif - } - - func testNegative() { - let ex2 = expectation(description: "") - after(seconds: -1).done(ex2.fulfill) - waitForExpectations(timeout: 2, handler: nil) - - let ex3 = expectation(description: "") - after(.seconds(-1)).done(ex3.fulfill) - waitForExpectations(timeout: 2, handler: nil) - - #if !SWIFT_PACKAGE - let ex4 = expectation(description: "") - __PMKAfter(-1).done{ _ in ex4.fulfill() }.silenceWarning() - waitForExpectations(timeout: 2, handler: nil) - #endif - } - - func testPositive() { - let ex2 = expectation(description: "") - after(seconds: 1).done(ex2.fulfill) - waitForExpectations(timeout: 2, handler: nil) - - let ex3 = expectation(description: "") - after(.seconds(1)).done(ex3.fulfill) - waitForExpectations(timeout: 2, handler: nil) - - #if !SWIFT_PACKAGE - let ex4 = expectation(description: "") - __PMKAfter(1).done{ _ in ex4.fulfill() }.silenceWarning() - waitForExpectations(timeout: 2, handler: nil) - #endif - } -} diff --git a/Tests/CorePromise/CatchableTests.swift b/Tests/CorePromise/CatchableTests.swift deleted file mode 100644 index d94b2b6f5..000000000 --- a/Tests/CorePromise/CatchableTests.swift +++ /dev/null @@ -1,267 +0,0 @@ -import PromiseKit -import Dispatch -import XCTest - -class CatchableTests: XCTestCase { - - func testFinally() { - let finallyQueue = DispatchQueue(label: "\(#file):\(#line)", attributes: .concurrent) - - func helper(error: Error, on queue: DispatchQueue = .main, flags: DispatchWorkItemFlags? = nil) { - let ex = (expectation(description: ""), expectation(description: "")) - var x = 0 - Promise(error: error).catch(policy: .allErrors) { _ in - XCTAssertEqual(x, 0) - x += 1 - ex.0.fulfill() - }.finally(on: queue, flags: flags) { - if let flags = flags, flags.contains(.barrier) { - dispatchPrecondition(condition: .onQueueAsBarrier(queue)) - } else { - dispatchPrecondition(condition: .onQueue(queue)) - } - XCTAssertEqual(x, 1) - x += 1 - ex.1.fulfill() - } - wait(for: [ex.0, ex.1], timeout: 10) - } - - helper(error: Error.dummy) - helper(error: Error.cancelled) - helper(error: Error.dummy, on: finallyQueue) - helper(error: Error.dummy, on: finallyQueue, flags: .barrier) - } - - func testCauterize() { - let ex = expectation(description: "") - let p = Promise(error: Error.dummy) - - // cannot test specifically that this outputs to console, - // but code-coverage will note that the line is run - p.cauterize() - - p.catch { _ in - ex.fulfill() - } - wait(for: [ex], timeout: 1) - } -} - - -/// `Promise.recover` -extension CatchableTests { - func test__void_specialized_full_recover() { - - func helper(error: Swift.Error) { - let ex = expectation(description: "") - Promise(error: error).recover { _ in }.done(ex.fulfill) - wait(for: [ex], timeout: 10) - } - - helper(error: Error.dummy) - helper(error: Error.cancelled) - } - - func test__void_specialized_full_recover__fulfilled_path() { - let ex = expectation(description: "") - Promise().recover { _ in XCTFail() }.done(ex.fulfill) - wait(for: [ex], timeout: 10) - } - - func test__void_specialized_conditional_recover() { - func helper(policy: CatchPolicy, error: Swift.Error, line: UInt = #line) { - let ex = expectation(description: "") - var x = 0 - Promise(error: error).recover(policy: policy) { err in - guard x < 1 else { throw err } - x += 1 - }.done(ex.fulfill).silenceWarning() - wait(for: [ex], timeout: 10) - } - - for error in [Error.dummy as Swift.Error, Error.cancelled] { - helper(policy: .allErrors, error: error) - } - helper(policy: .allErrorsExceptCancellation, error: Error.dummy) - } - - func test__void_specialized_conditional_recover__no_recover() { - - func helper(policy: CatchPolicy, error: Error, line: UInt = #line) { - let ex = expectation(description: "") - Promise(error: error).recover(policy: policy) { err in - throw err - }.catch(policy: .allErrors) { - XCTAssertEqual(error, $0 as? Error) - ex.fulfill() - } - wait(for: [ex], timeout: 10) - } - - for error in [Error.dummy, Error.cancelled] { - helper(policy: .allErrors, error: error) - } - helper(policy: .allErrorsExceptCancellation, error: Error.dummy) - } - - func test__void_specialized_conditional_recover__ignores_cancellation_but_fed_cancellation() { - let ex = expectation(description: "") - Promise(error: Error.cancelled).recover(policy: .allErrorsExceptCancellation) { _ in - XCTFail() - }.catch(policy: .allErrors) { - XCTAssertEqual(Error.cancelled, $0 as? Error) - ex.fulfill() - } - wait(for: [ex], timeout: 10) - } - - func test__void_specialized_conditional_recover__fulfilled_path() { - let ex = expectation(description: "") - Promise().recover { _ in - XCTFail() - }.catch { _ in - XCTFail() // this `catch` to ensure we are calling the `recover` variant we think we are - }.finally { - ex.fulfill() - } - wait(for: [ex], timeout: 10) - } -} - - -/// `Promise.recover` -extension CatchableTests { - func test__full_recover() { - - func helper(error: Swift.Error) { - let ex = expectation(description: "") - Promise(error: error).recover { _ in return .value(2) }.done { - XCTAssertEqual($0, 2) - ex.fulfill() - } - wait(for: [ex], timeout: 10) - } - - helper(error: Error.dummy) - helper(error: Error.cancelled) - } - - func test__full_recover__fulfilled_path() { - let ex = expectation(description: "") - Promise.value(1).recover { _ in XCTFail(); return .value(2) }.done{ - XCTAssertEqual($0, 1) - ex.fulfill() - } - wait(for: [ex], timeout: 10) - } - - - func test__conditional_recover() { - func helper(policy: CatchPolicy, error: Swift.Error, line: UInt = #line) { - let ex = expectation(description: "") - var x = 0 - Promise(error: error).recover(policy: policy) { err -> Promise in - guard x < 1 else { throw err } - x += 1 - return .value(x) - }.done { - XCTAssertEqual($0, x) - ex.fulfill() - }.silenceWarning() - wait(for: [ex], timeout: 10) - } - - for error in [Error.dummy as Swift.Error, Error.cancelled] { - helper(policy: .allErrors, error: error) - } - helper(policy: .allErrorsExceptCancellation, error: Error.dummy) - } - - func test__conditional_recover__no_recover() { - - func helper(policy: CatchPolicy, error: Error, line: UInt = #line) { - let ex = expectation(description: "") - Promise(error: error).recover(policy: policy) { err -> Promise in - throw err - }.catch(policy: .allErrors) { - XCTAssertEqual(error, $0 as? Error) - ex.fulfill() - } - wait(for: [ex], timeout: 10) - } - - for error in [Error.dummy, Error.cancelled] { - helper(policy: .allErrors, error: error) - } - helper(policy: .allErrorsExceptCancellation, error: Error.dummy) - } - - func test__conditional_recover__ignores_cancellation_but_fed_cancellation() { - let ex = expectation(description: "") - Promise(error: Error.cancelled).recover(policy: .allErrorsExceptCancellation) { _ -> Promise in - XCTFail() - return .value(1) - }.catch(policy: .allErrors) { - XCTAssertEqual(Error.cancelled, $0 as? Error) - ex.fulfill() - } - wait(for: [ex], timeout: 10) - } - - func test__conditional_recover__fulfilled_path() { - let ex = expectation(description: "") - Promise.value(1).recover { err -> Promise in - XCTFail() - throw err - }.done { - XCTAssertEqual($0, 1) - ex.fulfill() - }.catch { _ in - XCTFail() // this `catch` to ensure we are calling the `recover` variant we think we are - } - wait(for: [ex], timeout: 10) - } - - func testEnsureThen_Error() { - let ex = expectation(description: "") - - Promise.value(1).done { - XCTAssertEqual($0, 1) - throw Error.dummy - }.ensureThen { - after(seconds: 0.01) - }.catch { - XCTAssertEqual(Error.dummy, $0 as? Error) - }.finally { - ex.fulfill() - } - - wait(for: [ex], timeout: 10) - } - - func testEnsureThen_Value() { - let ex = expectation(description: "") - - Promise.value(1).ensureThen { - after(seconds: 0.01) - }.done { - XCTAssertEqual($0, 1) - }.catch { _ in - XCTFail() - }.finally { - ex.fulfill() - } - - wait(for: [ex], timeout: 10) - } -} - -private enum Error: CancellableError { - case dummy - case cancelled - - var isCancelled: Bool { - return self == Error.cancelled - } -} diff --git a/Tests/CorePromise/PromiseTests.swift b/Tests/CorePromise/PromiseTests.swift deleted file mode 100644 index fd010a0f5..000000000 --- a/Tests/CorePromise/PromiseTests.swift +++ /dev/null @@ -1,152 +0,0 @@ -import PromiseKit -import Dispatch -import XCTest - -class PromiseTests: XCTestCase { - func testIsPending() { - XCTAssertTrue(Promise.pending().promise.isPending) - XCTAssertFalse(Promise().isPending) - XCTAssertFalse(Promise(error: Error.dummy).isPending) - } - - func testIsResolved() { - XCTAssertFalse(Promise.pending().promise.isResolved) - XCTAssertTrue(Promise().isResolved) - XCTAssertTrue(Promise(error: Error.dummy).isResolved) - } - - func testIsFulfilled() { - XCTAssertFalse(Promise.pending().promise.isFulfilled) - XCTAssertTrue(Promise().isFulfilled) - XCTAssertFalse(Promise(error: Error.dummy).isFulfilled) - } - - func testIsRejected() { - XCTAssertFalse(Promise.pending().promise.isRejected) - XCTAssertTrue(Promise(error: Error.dummy).isRejected) - XCTAssertFalse(Promise().isRejected) - } - - @available(macOS 10.10, iOS 2.0, tvOS 10.0, watchOS 2.0, *) - func testDispatchQueueAsyncExtensionReturnsPromise() { - let ex = expectation(description: "") - - DispatchQueue.global().async(.promise) { () -> Int in - XCTAssertFalse(Thread.isMainThread) - return 1 - }.done { one in - XCTAssertEqual(one, 1) - ex.fulfill() - } - - waitForExpectations(timeout: 1) - } - - @available(macOS 10.10, iOS 2.0, tvOS 10.0, watchOS 2.0, *) - func testDispatchQueueAsyncExtensionCanThrowInBody() { - let ex = expectation(description: "") - - DispatchQueue.global().async(.promise) { () -> Int in - throw Error.dummy - }.done { _ in - XCTFail() - }.catch { _ in - ex.fulfill() - } - - waitForExpectations(timeout: 1) - } - - func testCustomStringConvertible() { - XCTAssertEqual(Promise.pending().promise.debugDescription, "Promise.pending(handlers: 0)") - XCTAssertEqual(Promise().debugDescription, "Promise<()>.fulfilled(())") - XCTAssertEqual(Promise(error: Error.dummy).debugDescription, "Promise.rejected(Error.dummy)") - - XCTAssertEqual("\(Promise.pending().promise)", "Promise(…Int)") - XCTAssertEqual("\(Promise.value(3))", "Promise(3)") - XCTAssertEqual("\(Promise(error: Error.dummy))", "Promise(dummy)") - } - - func testCannotFulfillWithError() { - - // sadly this test proves the opposite :( - // left here so maybe one day we can prevent instantiation of `Promise` - - _ = Promise { seal in - seal.fulfill(Error.dummy) - } - - _ = Promise.pending() - - _ = Promise.value(Error.dummy) - - _ = Promise().map { Error.dummy } - } - -#if swift(>=3.1) - func testCanMakeVoidPromise() { - _ = Promise() - _ = Guarantee() - } -#endif - - enum Error: Swift.Error { - case dummy - } - - func testThrowInInitializer() { - let p = Promise { _ in - throw Error.dummy - } - XCTAssertTrue(p.isRejected) - guard let err = p.error, case Error.dummy = err else { return XCTFail() } - } - - func testThrowInFirstly() { - let ex = expectation(description: "") - - firstly { () -> Promise in - throw Error.dummy - }.catch { - XCTAssertEqual($0 as? Error, Error.dummy) - ex.fulfill() - } - - wait(for: [ex], timeout: 10) - } - - func testWait() throws { - let p = after(.milliseconds(100)).then(on: nil){ Promise.value(1) } - XCTAssertEqual(try p.wait(), 1) - - do { - let p = after(.milliseconds(100)).map(on: nil){ throw Error.dummy } - try p.wait() - XCTFail() - } catch { - XCTAssertEqual(error as? Error, Error.dummy) - } - } - - func testPipeForResolved() { - let ex = expectation(description: "") - Promise.value(1).done { - XCTAssertEqual(1, $0) - ex.fulfill() - }.silenceWarning() - wait(for: [ex], timeout: 10) - } - - #if swift(>=3.1) - func testNoAmbiguityForValue() { - let ex = expectation(description: "") - let a = Promise.value - let b = Promise.value(Void()) - let c = Promise.value(()) - when(fulfilled: a, b, c).done { - ex.fulfill() - }.cauterize() - wait(for: [ex], timeout: 10) - } - #endif -} diff --git a/Tests/CorePromise/XCTestManifests.swift b/Tests/CorePromise/XCTestManifests.swift deleted file mode 100644 index 9ba889f08..000000000 --- a/Tests/CorePromise/XCTestManifests.swift +++ /dev/null @@ -1,311 +0,0 @@ -#if !canImport(ObjectiveC) -import XCTest - -extension AfterTests { - // DO NOT MODIFY: This is autogenerated, use: - // `swift test --generate-linuxmain` - // to regenerate. - static let __allTests__AfterTests = [ - ("testNegative", testNegative), - ("testPositive", testPositive), - ("testZero", testZero), - ] -} - -extension CancellationTests { - // DO NOT MODIFY: This is autogenerated, use: - // `swift test --generate-linuxmain` - // to regenerate. - static let __allTests__CancellationTests = [ - ("testBridgeToNSError", testBridgeToNSError), - ("testCancellation", testCancellation), - ("testDoesntCrashSwift", testDoesntCrashSwift), - ("testFoundationBridging1", testFoundationBridging1), - ("testFoundationBridging2", testFoundationBridging2), - ("testIsCancelled", testIsCancelled), - ("testRecoverWithCancellation", testRecoverWithCancellation), - ("testThrowCancellableErrorThatIsNotCancelled", testThrowCancellableErrorThatIsNotCancelled), - ] -} - -extension CatchableTests { - // DO NOT MODIFY: This is autogenerated, use: - // `swift test --generate-linuxmain` - // to regenerate. - static let __allTests__CatchableTests = [ - ("test__conditional_recover", test__conditional_recover), - ("test__conditional_recover__fulfilled_path", test__conditional_recover__fulfilled_path), - ("test__conditional_recover__ignores_cancellation_but_fed_cancellation", test__conditional_recover__ignores_cancellation_but_fed_cancellation), - ("test__conditional_recover__no_recover", test__conditional_recover__no_recover), - ("test__full_recover", test__full_recover), - ("test__full_recover__fulfilled_path", test__full_recover__fulfilled_path), - ("test__void_specialized_conditional_recover", test__void_specialized_conditional_recover), - ("test__void_specialized_conditional_recover__fulfilled_path", test__void_specialized_conditional_recover__fulfilled_path), - ("test__void_specialized_conditional_recover__ignores_cancellation_but_fed_cancellation", test__void_specialized_conditional_recover__ignores_cancellation_but_fed_cancellation), - ("test__void_specialized_conditional_recover__no_recover", test__void_specialized_conditional_recover__no_recover), - ("test__void_specialized_full_recover", test__void_specialized_full_recover), - ("test__void_specialized_full_recover__fulfilled_path", test__void_specialized_full_recover__fulfilled_path), - ("testCauterize", testCauterize), - ("testEnsureThen_Error", testEnsureThen_Error), - ("testEnsureThen_Value", testEnsureThen_Value), - ("testFinally", testFinally), - ] -} - -extension GuaranteeTests { - // DO NOT MODIFY: This is autogenerated, use: - // `swift test --generate-linuxmain` - // to regenerate. - static let __allTests__GuaranteeTests = [ - ("testCompactMapValues", testCompactMapValues), - ("testCompactMapValuesByKeyPath", testCompactMapValuesByKeyPath), - ("testFilterValues", testFilterValues), - ("testFilterValuesByKeyPath", testFilterValuesByKeyPath), - ("testFlatMapValues", testFlatMapValues), - ("testInit", testInit), - ("testMap", testMap), - ("testMapByKeyPath", testMapByKeyPath), - ("testMapValues", testMapValues), - ("testMapValuesByKeyPath", testMapValuesByKeyPath), - ("testNoAmbiguityForValue", testNoAmbiguityForValue), - ("testSorted", testSorted), - ("testSortedBy", testSortedBy), - ("testThenFlatMap", testThenFlatMap), - ("testThenMap", testThenMap), - ("testWait", testWait), - ] -} - -extension HangTests { - // DO NOT MODIFY: This is autogenerated, use: - // `swift test --generate-linuxmain` - // to regenerate. - static let __allTests__HangTests = [ - ("test", test), - ("testError", testError), - ] -} - -extension JoinTests { - // DO NOT MODIFY: This is autogenerated, use: - // `swift test --generate-linuxmain` - // to regenerate. - static let __allTests__JoinTests = [ - ("testFulfilledAfterAllResolve", testFulfilledAfterAllResolve), - ("testImmediates", testImmediates), - ] -} - -extension LoggingTests { - // DO NOT MODIFY: This is autogenerated, use: - // `swift test --generate-linuxmain` - // to regenerate. - static let __allTests__LoggingTests = [ - ("testCauterizeIsLogged", testCauterizeIsLogged), - ("testGuaranteeWaitOnMainThreadLogged", testGuaranteeWaitOnMainThreadLogged), - ("testLogging", testLogging), - ("testPendingGuaranteeDeallocatedIsLogged", testPendingGuaranteeDeallocatedIsLogged), - ("testPendingPromiseDeallocatedIsLogged", testPendingPromiseDeallocatedIsLogged), - ("testPromiseWaitOnMainThreadLogged", testPromiseWaitOnMainThreadLogged), - ] -} - -extension PMKDefaultDispatchQueueTest { - // DO NOT MODIFY: This is autogenerated, use: - // `swift test --generate-linuxmain` - // to regenerate. - static let __allTests__PMKDefaultDispatchQueueTest = [ - ("testOverrodeDefaultAlwaysQueue", testOverrodeDefaultAlwaysQueue), - ("testOverrodeDefaultCatchQueue", testOverrodeDefaultCatchQueue), - ("testOverrodeDefaultThenQueue", testOverrodeDefaultThenQueue), - ] -} - -extension PMKErrorTests { - // DO NOT MODIFY: This is autogenerated, use: - // `swift test --generate-linuxmain` - // to regenerate. - static let __allTests__PMKErrorTests = [ - ("testCustomDebugStringConvertible", testCustomDebugStringConvertible), - ("testCustomStringConvertible", testCustomStringConvertible), - ] -} - -extension PromiseTests { - // DO NOT MODIFY: This is autogenerated, use: - // `swift test --generate-linuxmain` - // to regenerate. - static let __allTests__PromiseTests = [ - ("testCanMakeVoidPromise", testCanMakeVoidPromise), - ("testCannotFulfillWithError", testCannotFulfillWithError), - ("testCustomStringConvertible", testCustomStringConvertible), - ("testDispatchQueueAsyncExtensionCanThrowInBody", testDispatchQueueAsyncExtensionCanThrowInBody), - ("testDispatchQueueAsyncExtensionReturnsPromise", testDispatchQueueAsyncExtensionReturnsPromise), - ("testIsFulfilled", testIsFulfilled), - ("testIsPending", testIsPending), - ("testIsRejected", testIsRejected), - ("testIsResolved", testIsResolved), - ("testNoAmbiguityForValue", testNoAmbiguityForValue), - ("testPipeForResolved", testPipeForResolved), - ("testThrowInFirstly", testThrowInFirstly), - ("testThrowInInitializer", testThrowInInitializer), - ("testWait", testWait), - ] -} - -extension RaceTests { - // DO NOT MODIFY: This is autogenerated, use: - // `swift test --generate-linuxmain` - // to regenerate. - static let __allTests__RaceTests = [ - ("test1", test1), - ("test1Array", test1Array), - ("test2", test2), - ("test2Array", test2Array), - ("testEmptyArray", testEmptyArray), - ("testFulfilled", testFulfilled), - ("testFulfilledEmptyArray", testFulfilledEmptyArray), - ("testFulfilledWithNoWinner", testFulfilledWithNoWinner), - ] -} - -extension RegressionTests { - // DO NOT MODIFY: This is autogenerated, use: - // `swift test --generate-linuxmain` - // to regenerate. - static let __allTests__RegressionTests = [ - ("testReturningPreviousPromiseWorks", testReturningPreviousPromiseWorks), - ] -} - -extension StressTests { - // DO NOT MODIFY: This is autogenerated, use: - // `swift test --generate-linuxmain` - // to regenerate. - static let __allTests__StressTests = [ - ("testThenDataRace", testThenDataRace), - ("testThensAreSequentialForLongTime", testThensAreSequentialForLongTime), - ("testZalgoDataRace", testZalgoDataRace), - ] -} - -extension ThenableTests { - // DO NOT MODIFY: This is autogenerated, use: - // `swift test --generate-linuxmain` - // to regenerate. - static let __allTests__ThenableTests = [ - ("testBarrier", testBarrier), - ("testCompactMap", testCompactMap), - ("testCompactMapByKeyPath", testCompactMapByKeyPath), - ("testCompactMapThrows", testCompactMapThrows), - ("testCompactMapValues", testCompactMapValues), - ("testCompactMapValuesByKeyPath", testCompactMapValuesByKeyPath), - ("testDispatchFlagsSyntax", testDispatchFlagsSyntax), - ("testFilterValues", testFilterValues), - ("testFilterValuesByKeyPath", testFilterValuesByKeyPath), - ("testFirstValueForEmpty", testFirstValueForEmpty), - ("testGet", testGet), - ("testLastValueForEmpty", testLastValueForEmpty), - ("testMap", testMap), - ("testMapByKeyPath", testMapByKeyPath), - ("testMapValues", testMapValues), - ("testMapValuesByKeyPath", testMapValuesByKeyPath), - ("testPMKErrorCompactMap", testPMKErrorCompactMap), - ("testRejectedPromiseCompactMap", testRejectedPromiseCompactMap), - ("testThenFlatMap", testThenFlatMap), - ("testThenMap", testThenMap), - ("testThenOffRejected", testThenOffRejected), - ] -} - -extension WhenConcurrentTestCase_Swift { - // DO NOT MODIFY: This is autogenerated, use: - // `swift test --generate-linuxmain` - // to regenerate. - static let __allTests__WhenConcurrentTestCase_Swift = [ - ("testStopsDequeueingOnceRejected", testStopsDequeueingOnceRejected), - ("testWhen", testWhen), - ("testWhenConcurrency", testWhenConcurrency), - ("testWhenConcurrencyLessThanZero", testWhenConcurrencyLessThanZero), - ("testWhenEmptyGenerator", testWhenEmptyGenerator), - ("testWhenGeneratorError", testWhenGeneratorError), - ("testWhenResolvedContinuesWhenRejected", testWhenResolvedContinuesWhenRejected), - ] -} - -extension WhenTests { - // DO NOT MODIFY: This is autogenerated, use: - // `swift test --generate-linuxmain` - // to regenerate. - static let __allTests__WhenTests = [ - ("testAllSealedRejectedFirstOneRejects", testAllSealedRejectedFirstOneRejects), - ("testDoubleTuple", testDoubleTuple), - ("testEmpty", testEmpty), - ("testGuaranteeWhen", testGuaranteeWhen), - ("testInt", testInt), - ("testProgress", testProgress), - ("testProgressDoesNotExceed100Percent", testProgressDoesNotExceed100Percent), - ("testQuadrupleTuple", testQuadrupleTuple), - ("testQuintupleTuple", testQuintupleTuple), - ("testRejected", testRejected), - ("testTripleTuple", testTripleTuple), - ("testUnhandledErrorHandlerDoesNotFire", testUnhandledErrorHandlerDoesNotFire), - ("testUnhandledErrorHandlerDoesNotFireForStragglers", testUnhandledErrorHandlerDoesNotFireForStragglers), - ("testVoid", testVoid), - ] -} - -extension WrapTests { - // DO NOT MODIFY: This is autogenerated, use: - // `swift test --generate-linuxmain` - // to regenerate. - static let __allTests__WrapTests = [ - ("testError", testError), - ("testInvalidCallingConvention", testInvalidCallingConvention), - ("testInvertedCallingConvention", testInvertedCallingConvention), - ("testIsFulfilled", testIsFulfilled), - ("testNonOptionalFirstParameter", testNonOptionalFirstParameter), - ("testPendingPromiseDeallocated", testPendingPromiseDeallocated), - ("testSuccess", testSuccess), - ("testSwiftResultError", testSwiftResultError), - ("testSwiftResultSuccess", testSwiftResultSuccess), - ("testVoidCompletionValue", testVoidCompletionValue), - ("testVoidResolverFulfillAmbiguity", testVoidResolverFulfillAmbiguity), - ] -} - -extension ZalgoTests { - // DO NOT MODIFY: This is autogenerated, use: - // `swift test --generate-linuxmain` - // to regenerate. - static let __allTests__ZalgoTests = [ - ("test1", test1), - ("test2", test2), - ("test3", test3), - ("test4", test4), - ] -} - -public func __allTests() -> [XCTestCaseEntry] { - return [ - testCase(AfterTests.__allTests__AfterTests), - testCase(CancellationTests.__allTests__CancellationTests), - testCase(CatchableTests.__allTests__CatchableTests), - testCase(GuaranteeTests.__allTests__GuaranteeTests), - testCase(HangTests.__allTests__HangTests), - testCase(JoinTests.__allTests__JoinTests), - testCase(LoggingTests.__allTests__LoggingTests), - testCase(PMKDefaultDispatchQueueTest.__allTests__PMKDefaultDispatchQueueTest), - testCase(PMKErrorTests.__allTests__PMKErrorTests), - testCase(PromiseTests.__allTests__PromiseTests), - testCase(RaceTests.__allTests__RaceTests), - testCase(RegressionTests.__allTests__RegressionTests), - testCase(StressTests.__allTests__StressTests), - testCase(ThenableTests.__allTests__ThenableTests), - testCase(WhenConcurrentTestCase_Swift.__allTests__WhenConcurrentTestCase_Swift), - testCase(WhenTests.__allTests__WhenTests), - testCase(WrapTests.__allTests__WrapTests), - testCase(ZalgoTests.__allTests__ZalgoTests), - ] -} -#endif diff --git a/Tests/DeprecationTests.swift b/Tests/DeprecationTests.swift deleted file mode 100644 index d382ce85e..000000000 --- a/Tests/DeprecationTests.swift +++ /dev/null @@ -1,158 +0,0 @@ -import PromiseKit -import XCTest - -class DeprecationTests: XCTestCase { - func testWrap1() { - let dummy = 10 - - func completion(_ body: (_ a: Int?, _ b: Error?) -> Void) { - body(dummy, nil) - } - - let ex = expectation(description: "") - wrap(completion).done { - XCTAssertEqual($0, dummy) - ex.fulfill() - } - wait(for: [ex], timeout: 10) - } - - func testWrap2() { - let dummy = 10 - - func completion(_ body: (_ a: Int, _ b: Error?) -> Void) { - body(dummy, nil) - } - - let ex = expectation(description: "") - wrap(completion).done { - XCTAssertEqual($0, dummy) - ex.fulfill() - } - wait(for: [ex], timeout: 10) - } - - func testWrap3() { - let dummy = 10 - - func completion(_ body: (_ a: Error?, _ b: Int?) -> Void) { - body(nil, dummy) - } - - let ex = expectation(description: "") - wrap(completion).done { - XCTAssertEqual($0, dummy) - ex.fulfill() - } - wait(for: [ex], timeout: 10) - } - - func testWrap4() { - let dummy = 10 - - func completion(_ body: (_ a: Error?) -> Void) { - body(nil) - } - - let ex = expectation(description: "") - wrap(completion).done { - ex.fulfill() - } - wait(for: [ex], timeout: 10) - } - - func testWrap5() { - let dummy = 10 - - func completion(_ body: (_ a: Int) -> Void) { - body(dummy) - } - - let ex = expectation(description: "") - wrap(completion).done { - XCTAssertEqual($0, dummy) - ex.fulfill() - } - wait(for: [ex], timeout: 10) - } - - func testAlways() { - let ex = expectation(description: "") - Promise.value(1).always(execute: ex.fulfill) - wait(for: [ex], timeout: 10) - } - -#if PMKFullDeprecations - func testFlatMap() { - let ex = expectation(description: "") - Promise.value(1).flatMap { _ -> Int? in - nil - }.catch { - //TODO should be `flatMap`, but how to enact that without causing - // compiler to warn when building PromiseKit for end-users? LOL - guard case PMKError.compactMap = $0 else { return XCTFail() } - ex.fulfill() - } - wait(for: [ex], timeout: 10) - } - - func testSequenceMap() { - let ex = expectation(description: "") - Promise.value([1, 2]).map { - $0 + 1 - }.done { - XCTAssertEqual($0, [2, 3]) - ex.fulfill() - }.silenceWarning() - wait(for: [ex], timeout: 10) - } - - func testSequenceFlatMap() { - let ex = expectation(description: "") - Promise.value([1, 2]).flatMap { - [$0 + 1, $0 + 2] - }.done { - XCTAssertEqual($0, [2, 3, 3, 4]) - ex.fulfill() - }.silenceWarning() - wait(for: [ex], timeout: 10) - } -#endif - - func testSequenceFilter() { - let ex = expectation(description: "") - Promise.value([0, 1, 2, 3]).filter { - $0 < 2 - }.done { - XCTAssertEqual($0, [0, 1]) - ex.fulfill() - }.silenceWarning() - wait(for: [ex], timeout: 10) - } - - func testSorted() { - let ex = expectation(description: "") - Promise.value([5, 2, 1, 8]).sorted().done { - XCTAssertEqual($0, [1,2,5,8]) - ex.fulfill() - } - wait(for: [ex], timeout: 10) - } - - func testFirst() { - XCTAssertEqual(Promise.value([1,2]).first.value, 1) - } - - func testLast() { - XCTAssertEqual(Promise.value([1,2]).last.value, 2) - } - - func testPMKErrorFlatMap() { - XCTAssertNotNil(PMKError.flatMap(1, Int.self).errorDescription) - } -} - - -extension Promise { - func silenceWarning() {} -} diff --git a/Tests/JS-A+/package-lock.json b/Tests/JS-A+/package-lock.json deleted file mode 100644 index 553072ec0..000000000 --- a/Tests/JS-A+/package-lock.json +++ /dev/null @@ -1,7869 +0,0 @@ -{ - "requires": true, - "lockfileVersion": 1, - "dependencies": { - "@sinonjs/formatio": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-2.0.0.tgz", - "integrity": "sha512-ls6CAMA6/5gG+O/IdsBcblvnd8qcO/l1TYoNeAzp3wcISOxlPXQEus0mLcdwazEkWjaBdaJ3TaxmNgCLWwvWzg==", - "requires": { - "samsam": "1.3.0" - }, - "dependencies": { - "samsam": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/samsam/-/samsam-1.3.0.tgz", - "integrity": "sha512-1HwIYD/8UlOtFS3QO3w7ey+SdSDFE4HRNLZoZRYVQefrOY3l17epswImeB1ijgJFQJodIaHcwkp3r/myBjFVbg==" - } - } - }, - "acorn": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.5.0.tgz", - "integrity": "sha512-arn53F07VXmls4o4pUhSzBa4fvaagPRe7AVZ8l7NHxFWUie2DsuFSBMMNAkgzRlOhEhzAnxeKyaWVzOH4xqp/g==" - }, - "acorn-dynamic-import": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/acorn-dynamic-import/-/acorn-dynamic-import-3.0.0.tgz", - "integrity": "sha512-zVWV8Z8lislJoOKKqdNMOB+s6+XV5WERty8MnKBeFgwA+19XJjJHs2RP5dzM57FftIs+jQnRToLiWazKr6sSWg==", - "requires": { - "acorn": "^5.0.0" - } - }, - "ajv": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.2.0.tgz", - "integrity": "sha1-r6wpW7qgFSRJ5SJ0LkVHwa6TKNI=", - "requires": { - "fast-deep-equal": "^1.0.0", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.3.0" - } - }, - "ajv-keywords": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.1.0.tgz", - "integrity": "sha1-rCsnk5xUPpXSwG5/f1wnvkqlQ74=" - }, - "ansi-escapes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.0.0.tgz", - "integrity": "sha512-O/klc27mWNUigtv0F8NJWbLF00OcegQalkqKURWdosW08YZKi4m6CnSUSvIZG1otNJbTWhN01Hhz389DW7mvDQ==" - }, - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" - }, - "ansi-styles": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", - "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "anymatch": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", - "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", - "requires": { - "micromatch": "^3.1.4", - "normalize-path": "^2.1.1" - } - }, - "aproba": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" - }, - "argv": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/argv/-/argv-0.0.2.tgz", - "integrity": "sha1-7L0W+JSbFXGDcRsb2jNPN4QBhas=" - }, - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=" - }, - "arr-flatten": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==" - }, - "arr-union": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=" - }, - "array-differ": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-1.0.0.tgz", - "integrity": "sha1-7/UuN1gknTO+QCuLuOVkuytdQDE=" - }, - "array-union": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", - "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", - "requires": { - "array-uniq": "^1.0.1" - } - }, - "array-uniq": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", - "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=" - }, - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=" - }, - "arrify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=" - }, - "asn1": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", - "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=" - }, - "asn1.js": { - "version": "4.10.1", - "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", - "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", - "requires": { - "bn.js": "^4.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" - } - }, - "assert": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/assert/-/assert-1.4.1.tgz", - "integrity": "sha1-mZEtWRg2tab1s0XA8H7vwI/GXZE=", - "requires": { - "util": "0.10.3" - } - }, - "assert-plus": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz", - "integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ=" - }, - "assign-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=" - }, - "ast-types": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.10.1.tgz", - "integrity": "sha512-UY7+9DPzlJ9VM8eY0b2TUZcZvF+1pO0hzMtAyjBYKhOmnvRlqYNYnWdtsMj0V16CGaMlpL0G1jnLbLo4AyotuQ==" - }, - "async": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", - "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=" - }, - "async-each": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz", - "integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0=" - }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" - }, - "atob": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.0.3.tgz", - "integrity": "sha1-GcenYEc3dEaPILLS0DNyrX1Mv10=" - }, - "aws-sign2": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz", - "integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8=" - }, - "aws4": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz", - "integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=" - }, - "babel-code-frame": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", - "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", - "requires": { - "chalk": "^1.1.3", - "esutils": "^2.0.2", - "js-tokens": "^3.0.2" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" - }, - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" - } - } - }, - "babel-core": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.26.0.tgz", - "integrity": "sha1-rzL3izGm/O8RnIew/Y2XU/A6C7g=", - "requires": { - "babel-code-frame": "^6.26.0", - "babel-generator": "^6.26.0", - "babel-helpers": "^6.24.1", - "babel-messages": "^6.23.0", - "babel-register": "^6.26.0", - "babel-runtime": "^6.26.0", - "babel-template": "^6.26.0", - "babel-traverse": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "convert-source-map": "^1.5.0", - "debug": "^2.6.8", - "json5": "^0.5.1", - "lodash": "^4.17.4", - "minimatch": "^3.0.4", - "path-is-absolute": "^1.0.1", - "private": "^0.1.7", - "slash": "^1.0.0", - "source-map": "^0.5.6" - }, - "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" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - } - } - }, - "babel-generator": { - "version": "6.26.1", - "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.1.tgz", - "integrity": "sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA==", - "requires": { - "babel-messages": "^6.23.0", - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "detect-indent": "^4.0.0", - "jsesc": "^1.3.0", - "lodash": "^4.17.4", - "source-map": "^0.5.7", - "trim-right": "^1.0.1" - }, - "dependencies": { - "jsesc": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", - "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=" - } - } - }, - "babel-helper-bindify-decorators": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-bindify-decorators/-/babel-helper-bindify-decorators-6.24.1.tgz", - "integrity": "sha1-FMGeXxQte0fxmlJDHlKxzLxAozA=", - "requires": { - "babel-runtime": "^6.22.0", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" - } - }, - "babel-helper-builder-binary-assignment-operator-visitor": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz", - "integrity": "sha1-zORReto1b0IgvK6KAsKzRvmlZmQ=", - "requires": { - "babel-helper-explode-assignable-expression": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" - } - }, - "babel-helper-call-delegate": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz", - "integrity": "sha1-7Oaqzdx25Bw0YfiL/Fdb0Nqi340=", - "requires": { - "babel-helper-hoist-variables": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" - } - }, - "babel-helper-define-map": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz", - "integrity": "sha1-pfVtq0GiX5fstJjH66ypgZ+Vvl8=", - "requires": { - "babel-helper-function-name": "^6.24.1", - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "lodash": "^4.17.4" - } - }, - "babel-helper-explode-assignable-expression": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz", - "integrity": "sha1-8luCz33BBDPFX3BZLVdGQArCLKo=", - "requires": { - "babel-runtime": "^6.22.0", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" - } - }, - "babel-helper-explode-class": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-explode-class/-/babel-helper-explode-class-6.24.1.tgz", - "integrity": "sha1-fcKjkQ3uAHBW4eMdZAztPVTqqes=", - "requires": { - "babel-helper-bindify-decorators": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" - } - }, - "babel-helper-function-name": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz", - "integrity": "sha1-00dbjAPtmCQqJbSDUasYOZ01gKk=", - "requires": { - "babel-helper-get-function-arity": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" - } - }, - "babel-helper-get-function-arity": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz", - "integrity": "sha1-j3eCqpNAfEHTqlCQj4mwMbG2hT0=", - "requires": { - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" - } - }, - "babel-helper-hoist-variables": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz", - "integrity": "sha1-HssnaJydJVE+rbyZFKc/VAi+enY=", - "requires": { - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" - } - }, - "babel-helper-optimise-call-expression": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz", - "integrity": "sha1-96E0J7qfc/j0+pk8VKl4gtEkQlc=", - "requires": { - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" - } - }, - "babel-helper-regex": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz", - "integrity": "sha1-MlxZ+QL4LyS3T6zu0DY5VPZJXnI=", - "requires": { - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "lodash": "^4.17.4" - } - }, - "babel-helper-remap-async-to-generator": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz", - "integrity": "sha1-XsWBgnrXI/7N04HxySg5BnbkVRs=", - "requires": { - "babel-helper-function-name": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" - } - }, - "babel-helper-replace-supers": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz", - "integrity": "sha1-v22/5Dk40XNpohPKiov3S2qQqxo=", - "requires": { - "babel-helper-optimise-call-expression": "^6.24.1", - "babel-messages": "^6.23.0", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" - } - }, - "babel-helpers": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz", - "integrity": "sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI=", - "requires": { - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1" - } - }, - "babel-loader": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-7.1.3.tgz", - "integrity": "sha512-PeN29YvOynPMvNk7QCzsHqxpmfXwKAC+uxkiSNFQsmXBBVltzEkVWmv/Ip3tx7yk149dQUwk497bTXNu+DZjLA==", - "requires": { - "find-cache-dir": "^1.0.0", - "loader-utils": "^1.0.2", - "mkdirp": "^0.5.1" - } - }, - "babel-messages": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", - "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", - "requires": { - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-check-es2015-constants": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz", - "integrity": "sha1-NRV7EBQm/S/9PaP3XH0ekYNbv4o=", - "requires": { - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-syntax-async-functions": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz", - "integrity": "sha1-ytnK0RkbWtY0vzCuCHI5HgZHvpU=" - }, - "babel-plugin-syntax-async-generators": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-async-generators/-/babel-plugin-syntax-async-generators-6.13.0.tgz", - "integrity": "sha1-a8lj67FuzLrmuStZbrfzXDQqi5o=" - }, - "babel-plugin-syntax-class-constructor-call": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-class-constructor-call/-/babel-plugin-syntax-class-constructor-call-6.18.0.tgz", - "integrity": "sha1-nLnTn+Q8hgC+yBRkVt3L1OGnZBY=" - }, - "babel-plugin-syntax-class-properties": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz", - "integrity": "sha1-1+sjt5oxf4VDlixQW4J8fWysJ94=" - }, - "babel-plugin-syntax-decorators": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-decorators/-/babel-plugin-syntax-decorators-6.13.0.tgz", - "integrity": "sha1-MSVjtNvePMgGzuPkFszurd0RrAs=" - }, - "babel-plugin-syntax-dynamic-import": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-dynamic-import/-/babel-plugin-syntax-dynamic-import-6.18.0.tgz", - "integrity": "sha1-jWomIpyDdFqZgqRBBRVyyqF5sdo=" - }, - "babel-plugin-syntax-exponentiation-operator": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz", - "integrity": "sha1-nufoM3KQ2pUoggGmpX9BcDF4MN4=" - }, - "babel-plugin-syntax-export-extensions": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-export-extensions/-/babel-plugin-syntax-export-extensions-6.13.0.tgz", - "integrity": "sha1-cKFITw+QiaToStRLrDU8lbmxJyE=" - }, - "babel-plugin-syntax-flow": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-flow/-/babel-plugin-syntax-flow-6.18.0.tgz", - "integrity": "sha1-TDqyCiryaqIM0lmVw5jE63AxDI0=" - }, - "babel-plugin-syntax-object-rest-spread": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz", - "integrity": "sha1-/WU28rzhODb/o6VFjEkDpZe7O/U=" - }, - "babel-plugin-syntax-trailing-function-commas": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz", - "integrity": "sha1-ugNgk3+NBuQBgKQ/4NVhb/9TLPM=" - }, - "babel-plugin-transform-async-generator-functions": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-async-generator-functions/-/babel-plugin-transform-async-generator-functions-6.24.1.tgz", - "integrity": "sha1-8FiQAUX9PpkHpt3yjaWfIVJYpds=", - "requires": { - "babel-helper-remap-async-to-generator": "^6.24.1", - "babel-plugin-syntax-async-generators": "^6.5.0", - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-async-to-generator": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz", - "integrity": "sha1-ZTbjeK/2yx1VF6wOQOs+n8jQh2E=", - "requires": { - "babel-helper-remap-async-to-generator": "^6.24.1", - "babel-plugin-syntax-async-functions": "^6.8.0", - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-class-constructor-call": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-class-constructor-call/-/babel-plugin-transform-class-constructor-call-6.24.1.tgz", - "integrity": "sha1-gNwoVQWsBn3LjWxl4vbxGrd2Xvk=", - "requires": { - "babel-plugin-syntax-class-constructor-call": "^6.18.0", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1" - } - }, - "babel-plugin-transform-class-properties": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.24.1.tgz", - "integrity": "sha1-anl2PqYdM9NvN7YRqp3vgagbRqw=", - "requires": { - "babel-helper-function-name": "^6.24.1", - "babel-plugin-syntax-class-properties": "^6.8.0", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1" - } - }, - "babel-plugin-transform-decorators": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-decorators/-/babel-plugin-transform-decorators-6.24.1.tgz", - "integrity": "sha1-eIAT2PjGtSIr33s0Q5Df13Vp4k0=", - "requires": { - "babel-helper-explode-class": "^6.24.1", - "babel-plugin-syntax-decorators": "^6.13.0", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1", - "babel-types": "^6.24.1" - } - }, - "babel-plugin-transform-es2015-arrow-functions": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz", - "integrity": "sha1-RSaSy3EdX3ncf4XkQM5BufJE0iE=", - "requires": { - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-es2015-block-scoped-functions": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz", - "integrity": "sha1-u8UbSflk1wy42OC5ToICRs46YUE=", - "requires": { - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-es2015-block-scoping": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz", - "integrity": "sha1-1w9SmcEwjQXBL0Y4E7CgnnOxiV8=", - "requires": { - "babel-runtime": "^6.26.0", - "babel-template": "^6.26.0", - "babel-traverse": "^6.26.0", - "babel-types": "^6.26.0", - "lodash": "^4.17.4" - } - }, - "babel-plugin-transform-es2015-classes": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz", - "integrity": "sha1-WkxYpQyclGHlZLSyo7+ryXolhNs=", - "requires": { - "babel-helper-define-map": "^6.24.1", - "babel-helper-function-name": "^6.24.1", - "babel-helper-optimise-call-expression": "^6.24.1", - "babel-helper-replace-supers": "^6.24.1", - "babel-messages": "^6.23.0", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" - } - }, - "babel-plugin-transform-es2015-computed-properties": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz", - "integrity": "sha1-b+Ko0WiV1WNPTNmZttNICjCBWbM=", - "requires": { - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1" - } - }, - "babel-plugin-transform-es2015-destructuring": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz", - "integrity": "sha1-mXux8auWf2gtKwh2/jWNYOdlxW0=", - "requires": { - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-es2015-duplicate-keys": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz", - "integrity": "sha1-c+s9MQypaePvnskcU3QabxV2Qj4=", - "requires": { - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" - } - }, - "babel-plugin-transform-es2015-for-of": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz", - "integrity": "sha1-9HyVsrYT3x0+zC/bdXNiPHUkhpE=", - "requires": { - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-es2015-function-name": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz", - "integrity": "sha1-g0yJhTvDaxrw86TF26qU/Y6sqos=", - "requires": { - "babel-helper-function-name": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" - } - }, - "babel-plugin-transform-es2015-literals": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz", - "integrity": "sha1-T1SgLWzWbPkVKAAZox0xklN3yi4=", - "requires": { - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-es2015-modules-amd": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz", - "integrity": "sha1-Oz5UAXI5hC1tGcMBHEvS8AoA0VQ=", - "requires": { - "babel-plugin-transform-es2015-modules-commonjs": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1" - } - }, - "babel-plugin-transform-es2015-modules-commonjs": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.0.tgz", - "integrity": "sha1-DYOUApt9xqvhqX7xgeAHWN0uXYo=", - "requires": { - "babel-plugin-transform-strict-mode": "^6.24.1", - "babel-runtime": "^6.26.0", - "babel-template": "^6.26.0", - "babel-types": "^6.26.0" - } - }, - "babel-plugin-transform-es2015-modules-systemjs": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz", - "integrity": "sha1-/4mhQrkRmpBhlfXxBuzzBdlAfSM=", - "requires": { - "babel-helper-hoist-variables": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1" - } - }, - "babel-plugin-transform-es2015-modules-umd": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz", - "integrity": "sha1-rJl+YoXNGO1hdq22B9YCNErThGg=", - "requires": { - "babel-plugin-transform-es2015-modules-amd": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1" - } - }, - "babel-plugin-transform-es2015-object-super": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz", - "integrity": "sha1-JM72muIcuDp/hgPa0CH1cusnj40=", - "requires": { - "babel-helper-replace-supers": "^6.24.1", - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-es2015-parameters": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz", - "integrity": "sha1-V6w1GrScrxSpfNE7CfZv3wpiXys=", - "requires": { - "babel-helper-call-delegate": "^6.24.1", - "babel-helper-get-function-arity": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" - } - }, - "babel-plugin-transform-es2015-shorthand-properties": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz", - "integrity": "sha1-JPh11nIch2YbvZmkYi5R8U3jiqA=", - "requires": { - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" - } - }, - "babel-plugin-transform-es2015-spread": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz", - "integrity": "sha1-1taKmfia7cRTbIGlQujdnxdG+NE=", - "requires": { - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-es2015-sticky-regex": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz", - "integrity": "sha1-AMHNsaynERLN8M9hJsLta0V8zbw=", - "requires": { - "babel-helper-regex": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" - } - }, - "babel-plugin-transform-es2015-template-literals": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz", - "integrity": "sha1-qEs0UPfp+PH2g51taH2oS7EjbY0=", - "requires": { - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-es2015-typeof-symbol": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz", - "integrity": "sha1-3sCfHN3/lLUqxz1QXITfWdzOs3I=", - "requires": { - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-es2015-unicode-regex": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz", - "integrity": "sha1-04sS9C6nMj9yk4fxinxa4frrNek=", - "requires": { - "babel-helper-regex": "^6.24.1", - "babel-runtime": "^6.22.0", - "regexpu-core": "^2.0.0" - } - }, - "babel-plugin-transform-exponentiation-operator": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz", - "integrity": "sha1-KrDJx/MJj6SJB3cruBP+QejeOg4=", - "requires": { - "babel-helper-builder-binary-assignment-operator-visitor": "^6.24.1", - "babel-plugin-syntax-exponentiation-operator": "^6.8.0", - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-export-extensions": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-export-extensions/-/babel-plugin-transform-export-extensions-6.22.0.tgz", - "integrity": "sha1-U3OLR+deghhYnuqUbLvTkQm75lM=", - "requires": { - "babel-plugin-syntax-export-extensions": "^6.8.0", - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-flow-strip-types": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-flow-strip-types/-/babel-plugin-transform-flow-strip-types-6.22.0.tgz", - "integrity": "sha1-hMtnKTXUNxT9wyvOhFaNh0Qc988=", - "requires": { - "babel-plugin-syntax-flow": "^6.18.0", - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-object-rest-spread": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.26.0.tgz", - "integrity": "sha1-DzZpLVD+9rfi1LOsFHgTepY7ewY=", - "requires": { - "babel-plugin-syntax-object-rest-spread": "^6.8.0", - "babel-runtime": "^6.26.0" - } - }, - "babel-plugin-transform-regenerator": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz", - "integrity": "sha1-4HA2lvveJ/Cj78rPi03KL3s6jy8=", - "requires": { - "regenerator-transform": "^0.10.0" - } - }, - "babel-plugin-transform-strict-mode": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz", - "integrity": "sha1-1fr3qleKZbvlkc9e2uBKDGcCB1g=", - "requires": { - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" - } - }, - "babel-preset-env": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/babel-preset-env/-/babel-preset-env-1.6.1.tgz", - "integrity": "sha512-W6VIyA6Ch9ePMI7VptNn2wBM6dbG0eSz25HEiL40nQXCsXGTGZSTZu1Iap+cj3Q0S5a7T9+529l/5Bkvd+afNA==", - "requires": { - "babel-plugin-check-es2015-constants": "^6.22.0", - "babel-plugin-syntax-trailing-function-commas": "^6.22.0", - "babel-plugin-transform-async-to-generator": "^6.22.0", - "babel-plugin-transform-es2015-arrow-functions": "^6.22.0", - "babel-plugin-transform-es2015-block-scoped-functions": "^6.22.0", - "babel-plugin-transform-es2015-block-scoping": "^6.23.0", - "babel-plugin-transform-es2015-classes": "^6.23.0", - "babel-plugin-transform-es2015-computed-properties": "^6.22.0", - "babel-plugin-transform-es2015-destructuring": "^6.23.0", - "babel-plugin-transform-es2015-duplicate-keys": "^6.22.0", - "babel-plugin-transform-es2015-for-of": "^6.23.0", - "babel-plugin-transform-es2015-function-name": "^6.22.0", - "babel-plugin-transform-es2015-literals": "^6.22.0", - "babel-plugin-transform-es2015-modules-amd": "^6.22.0", - "babel-plugin-transform-es2015-modules-commonjs": "^6.23.0", - "babel-plugin-transform-es2015-modules-systemjs": "^6.23.0", - "babel-plugin-transform-es2015-modules-umd": "^6.23.0", - "babel-plugin-transform-es2015-object-super": "^6.22.0", - "babel-plugin-transform-es2015-parameters": "^6.23.0", - "babel-plugin-transform-es2015-shorthand-properties": "^6.22.0", - "babel-plugin-transform-es2015-spread": "^6.22.0", - "babel-plugin-transform-es2015-sticky-regex": "^6.22.0", - "babel-plugin-transform-es2015-template-literals": "^6.22.0", - "babel-plugin-transform-es2015-typeof-symbol": "^6.23.0", - "babel-plugin-transform-es2015-unicode-regex": "^6.22.0", - "babel-plugin-transform-exponentiation-operator": "^6.22.0", - "babel-plugin-transform-regenerator": "^6.22.0", - "browserslist": "^2.1.2", - "invariant": "^2.2.2", - "semver": "^5.3.0" - } - }, - "babel-preset-es2015": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-preset-es2015/-/babel-preset-es2015-6.24.1.tgz", - "integrity": "sha1-1EBQ1rwsn+6nAqrzjXJ6AhBTiTk=", - "requires": { - "babel-plugin-check-es2015-constants": "^6.22.0", - "babel-plugin-transform-es2015-arrow-functions": "^6.22.0", - "babel-plugin-transform-es2015-block-scoped-functions": "^6.22.0", - "babel-plugin-transform-es2015-block-scoping": "^6.24.1", - "babel-plugin-transform-es2015-classes": "^6.24.1", - "babel-plugin-transform-es2015-computed-properties": "^6.24.1", - "babel-plugin-transform-es2015-destructuring": "^6.22.0", - "babel-plugin-transform-es2015-duplicate-keys": "^6.24.1", - "babel-plugin-transform-es2015-for-of": "^6.22.0", - "babel-plugin-transform-es2015-function-name": "^6.24.1", - "babel-plugin-transform-es2015-literals": "^6.22.0", - "babel-plugin-transform-es2015-modules-amd": "^6.24.1", - "babel-plugin-transform-es2015-modules-commonjs": "^6.24.1", - "babel-plugin-transform-es2015-modules-systemjs": "^6.24.1", - "babel-plugin-transform-es2015-modules-umd": "^6.24.1", - "babel-plugin-transform-es2015-object-super": "^6.24.1", - "babel-plugin-transform-es2015-parameters": "^6.24.1", - "babel-plugin-transform-es2015-shorthand-properties": "^6.24.1", - "babel-plugin-transform-es2015-spread": "^6.22.0", - "babel-plugin-transform-es2015-sticky-regex": "^6.24.1", - "babel-plugin-transform-es2015-template-literals": "^6.22.0", - "babel-plugin-transform-es2015-typeof-symbol": "^6.22.0", - "babel-plugin-transform-es2015-unicode-regex": "^6.24.1", - "babel-plugin-transform-regenerator": "^6.24.1" - } - }, - "babel-preset-stage-1": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-preset-stage-1/-/babel-preset-stage-1-6.24.1.tgz", - "integrity": "sha1-dpLNfc1oSZB+auSgqFWJz7niv7A=", - "requires": { - "babel-plugin-transform-class-constructor-call": "^6.24.1", - "babel-plugin-transform-export-extensions": "^6.22.0", - "babel-preset-stage-2": "^6.24.1" - } - }, - "babel-preset-stage-2": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-preset-stage-2/-/babel-preset-stage-2-6.24.1.tgz", - "integrity": "sha1-2eKWD7PXEYfw5k7sYrwHdnIZvcE=", - "requires": { - "babel-plugin-syntax-dynamic-import": "^6.18.0", - "babel-plugin-transform-class-properties": "^6.24.1", - "babel-plugin-transform-decorators": "^6.24.1", - "babel-preset-stage-3": "^6.24.1" - } - }, - "babel-preset-stage-3": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-preset-stage-3/-/babel-preset-stage-3-6.24.1.tgz", - "integrity": "sha1-g2raCp56f6N8sTj7kyb4eTSkg5U=", - "requires": { - "babel-plugin-syntax-trailing-function-commas": "^6.22.0", - "babel-plugin-transform-async-generator-functions": "^6.24.1", - "babel-plugin-transform-async-to-generator": "^6.24.1", - "babel-plugin-transform-exponentiation-operator": "^6.24.1", - "babel-plugin-transform-object-rest-spread": "^6.22.0" - } - }, - "babel-register": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz", - "integrity": "sha1-btAhFz4vy0htestFxgCahW9kcHE=", - "requires": { - "babel-core": "^6.26.0", - "babel-runtime": "^6.26.0", - "core-js": "^2.5.0", - "home-or-tmp": "^2.0.0", - "lodash": "^4.17.4", - "mkdirp": "^0.5.1", - "source-map-support": "^0.4.15" - } - }, - "babel-runtime": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", - "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", - "requires": { - "core-js": "^2.4.0", - "regenerator-runtime": "^0.11.0" - } - }, - "babel-template": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", - "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", - "requires": { - "babel-runtime": "^6.26.0", - "babel-traverse": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "lodash": "^4.17.4" - } - }, - "babel-traverse": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", - "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", - "requires": { - "babel-code-frame": "^6.26.0", - "babel-messages": "^6.23.0", - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "debug": "^2.6.8", - "globals": "^9.18.0", - "invariant": "^2.2.2", - "lodash": "^4.17.4" - }, - "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" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - } - } - }, - "babel-types": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", - "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", - "requires": { - "babel-runtime": "^6.26.0", - "esutils": "^2.0.2", - "lodash": "^4.17.4", - "to-fast-properties": "^1.0.3" - } - }, - "babylon": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", - "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==" - }, - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" - }, - "base": { - "version": "0.11.2", - "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", - "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", - "requires": { - "cache-base": "^1.0.1", - "class-utils": "^0.3.5", - "component-emitter": "^1.2.1", - "define-property": "^1.0.0", - "isobject": "^3.0.1", - "mixin-deep": "^1.2.0", - "pascalcase": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "requires": { - "is-descriptor": "^1.0.0" - } - } - } - }, - "base64-js": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.2.3.tgz", - "integrity": "sha512-MsAhsUW1GxCdgYSO6tAfZrNapmUKk7mWx/k5mFY/A1gBtkaCaNapTg+FExCw1r9yeaZhqx/xPg43xgTFH6KL5w==" - }, - "bcrypt-pbkdf": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz", - "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=", - "optional": true, - "requires": { - "tweetnacl": "^0.14.3" - } - }, - "big.js": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-3.2.0.tgz", - "integrity": "sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q==" - }, - "binary-extensions": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.11.0.tgz", - "integrity": "sha1-RqoXUftqL5PuXmibsQh9SxTGwgU=" - }, - "binaryextensions": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/binaryextensions/-/binaryextensions-2.1.1.tgz", - "integrity": "sha512-XBaoWE9RW8pPdPQNibZsW2zh8TW6gcarXp1FZPwT8Uop8ScSNldJEWf2k9l3HeTqdrEwsOsFcq74RiJECW34yA==" - }, - "bluebird": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz", - "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==" - }, - "bn.js": { - "version": "4.11.8", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", - "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==" - }, - "boom": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", - "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", - "requires": { - "hoek": "2.x.x" - } - }, - "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": "2.3.1", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.1.tgz", - "integrity": "sha512-SO5lYHA3vO6gz66erVvedSCkp7AKWdv6VcQ2N4ysXfPxdAlxAMMAdwegGGcv1Bqwm7naF1hNdk5d6AAIEHV2nQ==", - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "kind-of": "^6.0.2", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "brorand": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" - }, - "browser-stdout": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.0.tgz", - "integrity": "sha1-81HTKWnTL6XXpVZxVCY9korjvR8=" - }, - "browserify-aes": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.1.1.tgz", - "integrity": "sha512-UGnTYAnB2a3YuYKIRy1/4FB2HdM866E0qC46JXvVTYKlBlZlnvfpSfY6OKfXZAkv70eJ2a1SqzpAo5CRhZGDFg==", - "requires": { - "buffer-xor": "^1.0.3", - "cipher-base": "^1.0.0", - "create-hash": "^1.1.0", - "evp_bytestokey": "^1.0.3", - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "browserify-cipher": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.0.tgz", - "integrity": "sha1-mYgkSHS/XtTijalWZtzWasj8Njo=", - "requires": { - "browserify-aes": "^1.0.4", - "browserify-des": "^1.0.0", - "evp_bytestokey": "^1.0.0" - } - }, - "browserify-des": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.0.tgz", - "integrity": "sha1-2qJ3cXRwki7S/hhZQRihdUOXId0=", - "requires": { - "cipher-base": "^1.0.1", - "des.js": "^1.0.0", - "inherits": "^2.0.1" - } - }, - "browserify-rsa": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", - "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", - "requires": { - "bn.js": "^4.1.0", - "randombytes": "^2.0.1" - } - }, - "browserify-sign": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.0.4.tgz", - "integrity": "sha1-qk62jl17ZYuqa/alfmMMvXqT0pg=", - "requires": { - "bn.js": "^4.1.1", - "browserify-rsa": "^4.0.0", - "create-hash": "^1.1.0", - "create-hmac": "^1.1.2", - "elliptic": "^6.0.0", - "inherits": "^2.0.1", - "parse-asn1": "^5.0.0" - } - }, - "browserify-zlib": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", - "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", - "requires": { - "pako": "~1.0.5" - } - }, - "browserslist": { - "version": "2.11.3", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-2.11.3.tgz", - "integrity": "sha512-yWu5cXT7Av6mVwzWc8lMsJMHWn4xyjSuGYi4IozbVTLUOEYPSagUB8kiMDUHA1fS3zjr8nkxkn9jdvug4BBRmA==", - "requires": { - "caniuse-lite": "^1.0.30000792", - "electron-to-chromium": "^1.3.30" - } - }, - "buffer": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", - "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=", - "requires": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4", - "isarray": "^1.0.0" - } - }, - "buffer-xor": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", - "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=" - }, - "builtin-modules": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", - "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=" - }, - "builtin-status-codes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", - "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=" - }, - "cacache": { - "version": "10.0.4", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-10.0.4.tgz", - "integrity": "sha512-Dph0MzuH+rTQzGPNT9fAnrPmMmjKfST6trxJeK7NQuHRaVw24VzPRWTmg9MpcwOVQZO0E1FBICUlFeNaKPIfHA==", - "requires": { - "bluebird": "^3.5.1", - "chownr": "^1.0.1", - "glob": "^7.1.2", - "graceful-fs": "^4.1.11", - "lru-cache": "^4.1.1", - "mississippi": "^2.0.0", - "mkdirp": "^0.5.1", - "move-concurrently": "^1.0.1", - "promise-inflight": "^1.0.1", - "rimraf": "^2.6.2", - "ssri": "^5.2.4", - "unique-filename": "^1.1.0", - "y18n": "^4.0.0" - }, - "dependencies": { - "glob": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", - "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" - } - }, - "lru-cache": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.1.tgz", - "integrity": "sha512-q4spe4KTfsAS1SUHLO0wz8Qiyf1+vMIAgpRYioFYDMNqKfHQbg+AVDH3i4fvpl71/P1L0dBl+fQi+P37UYf0ew==", - "requires": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "requires": { - "brace-expansion": "^1.1.7" - } - } - } - }, - "cache-base": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", - "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", - "requires": { - "collection-visit": "^1.0.0", - "component-emitter": "^1.2.1", - "get-value": "^2.0.6", - "has-value": "^1.0.0", - "isobject": "^3.0.1", - "set-value": "^2.0.0", - "to-object-path": "^0.3.0", - "union-value": "^1.0.0", - "unset-value": "^1.0.0" - } - }, - "camelcase": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", - "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=" - }, - "caniuse-lite": { - "version": "1.0.30000812", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000812.tgz", - "integrity": "sha512-j+l55ayQ9BO4Sy9iVfbf99+G+4ddAmkXoiEt73WCW4vJ83usrlHzDkFEnNXe5/swkVqE7YBm5i8M2uRXlx9vWg==" - }, - "caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" - }, - "chalk": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.1.tgz", - "integrity": "sha512-QUU4ofkDoMIVO7hcx1iPTISs88wsO8jA92RQIm4JAwZvFGGAV2hSAA1NX7oVj2Ej2Q6NDTcRDjPTFrMCRZoJ6g==", - "requires": { - "ansi-styles": "^3.2.0", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.2.0" - }, - "dependencies": { - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" - }, - "supports-color": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.2.0.tgz", - "integrity": "sha512-F39vS48la4YvTZUPVeTqsjsFNrvcMwrV3RLZINsmHo+7djCvuUzSIeXOnZ5hmjef4bajL1dNccN+tg5XAliO5Q==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "chardet": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz", - "integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=" - }, - "chokidar": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.0.2.tgz", - "integrity": "sha512-l32Hw3wqB0L2kGVmSbK/a+xXLDrUEsc84pSgMkmwygHvD7ubRsP/vxxHa5BtB6oix1XLLVCHyYMsckRXxThmZw==", - "requires": { - "anymatch": "^2.0.0", - "async-each": "^1.0.0", - "braces": "^2.3.0", - "fsevents": "^1.0.0", - "glob-parent": "^3.1.0", - "inherits": "^2.0.1", - "is-binary-path": "^1.0.0", - "is-glob": "^4.0.0", - "normalize-path": "^2.1.1", - "path-is-absolute": "^1.0.0", - "readdirp": "^2.0.0", - "upath": "^1.0.0" - } - }, - "chownr": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.0.1.tgz", - "integrity": "sha1-4qdQQqlVGQi+vSW4Uj1fl2nXkYE=" - }, - "chrome-trace-event": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-0.1.2.tgz", - "integrity": "sha1-kPNohdU0WlBiEzLwcXtZWIPV2YI=" - }, - "cipher-base": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", - "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", - "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "class-utils": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", - "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", - "requires": { - "arr-union": "^3.1.0", - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "static-extend": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - } - }, - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" - } - } - }, - "cli-cursor": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", - "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", - "requires": { - "restore-cursor": "^2.0.0" - } - }, - "cli-spinners": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-0.1.2.tgz", - "integrity": "sha1-u3ZNiOGF+54eaiofGXcjGPYF4xw=" - }, - "cli-table": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/cli-table/-/cli-table-0.3.1.tgz", - "integrity": "sha1-9TsFJmqLGguTSz0IIebi3FkUriM=", - "requires": { - "colors": "1.0.3" - }, - "dependencies": { - "colors": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", - "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=" - } - } - }, - "cli-truncate": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-0.2.1.tgz", - "integrity": "sha1-nxXPuwcFAFNpIWxiasfQWrkN1XQ=", - "requires": { - "slice-ansi": "0.0.4", - "string-width": "^1.0.1" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "requires": { - "ansi-regex": "^2.0.0" - } - } - } - }, - "cli-width": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", - "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=" - }, - "cliui": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", - "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", - "requires": { - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wrap-ansi": "^2.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "requires": { - "ansi-regex": "^2.0.0" - } - } - } - }, - "clone": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.1.tgz", - "integrity": "sha1-0hfR6WERjjrJpLi7oyhVU79kfNs=" - }, - "clone-buffer": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/clone-buffer/-/clone-buffer-1.0.0.tgz", - "integrity": "sha1-4+JbIHrE5wGvch4staFnksrD3Fg=" - }, - "clone-stats": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-1.0.0.tgz", - "integrity": "sha1-s3gt/4u1R04Yuba/D9/ngvh3doA=" - }, - "cloneable-readable": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/cloneable-readable/-/cloneable-readable-1.0.0.tgz", - "integrity": "sha1-pikNQT8hemEjL5XkWP84QYz7ARc=", - "requires": { - "inherits": "^2.0.1", - "process-nextick-args": "^1.0.6", - "through2": "^2.0.1" - }, - "dependencies": { - "process-nextick-args": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", - "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=" - } - } - }, - "co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" - }, - "code-point-at": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" - }, - "codecov": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/codecov/-/codecov-3.0.0.tgz", - "integrity": "sha1-wnO4xPEpRXI+jcnSWAPYk0Pl8o4=", - "requires": { - "argv": "0.0.2", - "request": "2.81.0", - "urlgrey": "0.4.4" - } - }, - "collection-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", - "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", - "requires": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" - } - }, - "color-convert": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz", - "integrity": "sha512-mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==", - "requires": { - "color-name": "^1.1.1" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" - }, - "colors": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz", - "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=" - }, - "combined-stream": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz", - "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=", - "requires": { - "delayed-stream": "~1.0.0" - } - }, - "commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=" - }, - "component-emitter": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", - "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=" - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" - }, - "concat-stream": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.0.tgz", - "integrity": "sha1-CqxmL9Ur54lk1VMvaUeE5wEQrPc=", - "requires": { - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" - } - }, - "console-browserify": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz", - "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=", - "requires": { - "date-now": "^0.1.4" - } - }, - "constants-browserify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", - "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=" - }, - "convert-source-map": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.1.tgz", - "integrity": "sha1-uCeAl7m8IpNl3lxiz1/K7YtVmeU=" - }, - "copy-concurrently": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz", - "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==", - "requires": { - "aproba": "^1.1.1", - "fs-write-stream-atomic": "^1.0.8", - "iferr": "^0.1.5", - "mkdirp": "^0.5.1", - "rimraf": "^2.5.4", - "run-queue": "^1.0.0" - } - }, - "copy-descriptor": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=" - }, - "core-js": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.3.tgz", - "integrity": "sha1-isw4NFgk8W2DZbfJtCWRaOjtYD4=" - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" - }, - "create-ecdh": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.0.tgz", - "integrity": "sha1-iIxyNZbN92EvZJgjPuvXo1MBc30=", - "requires": { - "bn.js": "^4.1.0", - "elliptic": "^6.0.0" - } - }, - "create-hash": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.1.3.tgz", - "integrity": "sha1-YGBCrIuSYnUPSDyt2rD1gZFy2P0=", - "requires": { - "cipher-base": "^1.0.1", - "inherits": "^2.0.1", - "ripemd160": "^2.0.0", - "sha.js": "^2.4.0" - } - }, - "create-hmac": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.6.tgz", - "integrity": "sha1-rLniIaThe9sHbpBlfEK5PjcmzwY=", - "requires": { - "cipher-base": "^1.0.3", - "create-hash": "^1.1.0", - "inherits": "^2.0.1", - "ripemd160": "^2.0.0", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" - } - }, - "cross-spawn": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", - "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", - "requires": { - "lru-cache": "^4.0.1", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - }, - "dependencies": { - "lru-cache": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.1.tgz", - "integrity": "sha512-q4spe4KTfsAS1SUHLO0wz8Qiyf1+vMIAgpRYioFYDMNqKfHQbg+AVDH3i4fvpl71/P1L0dBl+fQi+P37UYf0ew==", - "requires": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - } - } - }, - "cryptiles": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz", - "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=", - "requires": { - "boom": "2.x.x" - } - }, - "crypto-browserify": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", - "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", - "requires": { - "browserify-cipher": "^1.0.0", - "browserify-sign": "^4.0.0", - "create-ecdh": "^4.0.0", - "create-hash": "^1.1.0", - "create-hmac": "^1.1.0", - "diffie-hellman": "^5.0.0", - "inherits": "^2.0.1", - "pbkdf2": "^3.0.3", - "public-encrypt": "^4.0.0", - "randombytes": "^2.0.0", - "randomfill": "^1.0.3" - } - }, - "cyclist": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-0.2.2.tgz", - "integrity": "sha1-GzN5LhHpFKL9bW7WRHRkRE5fpkA=" - }, - "dargs": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/dargs/-/dargs-5.1.0.tgz", - "integrity": "sha1-7H6lDHhWTNNsnV7Bj2Yyn63ieCk=" - }, - "dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", - "requires": { - "assert-plus": "^1.0.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" - } - } - }, - "date-fns": { - "version": "1.29.0", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-1.29.0.tgz", - "integrity": "sha512-lbTXWZ6M20cWH8N9S6afb0SBm6tMk+uUg6z3MqHPKE9atmsY3kJkTm8vKe93izJ2B2+q5MV990sM2CHgtAZaOw==" - }, - "date-now": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz", - "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=" - }, - "dateformat": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-2.2.0.tgz", - "integrity": "sha1-QGXiATz5+5Ft39gu+1Bq1MZ2kGI=" - }, - "debug": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", - "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", - "requires": { - "ms": "0.7.1" - } - }, - "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" - }, - "decode-uri-component": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=" - }, - "decompress-response": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", - "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", - "requires": { - "mimic-response": "^1.0.0" - } - }, - "deep-extend": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.4.2.tgz", - "integrity": "sha1-SLaZwn4zS/ifEIkr5DL25MfTSn8=" - }, - "define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", - "requires": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - } - }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" - }, - "des.js": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.0.tgz", - "integrity": "sha1-wHTS4qpqipoH29YfmhXCzYPsjsw=", - "requires": { - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" - } - }, - "detect-conflict": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/detect-conflict/-/detect-conflict-1.0.1.tgz", - "integrity": "sha1-CIZXpmqWHAUBnbfEIwiDsca0F24=" - }, - "detect-indent": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", - "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=", - "requires": { - "repeating": "^2.0.0" - } - }, - "diff": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-3.4.0.tgz", - "integrity": "sha512-QpVuMTEoJMF7cKzi6bvWhRulU1fZqZnvyVQgNhPaxxuTYwyjn/j1v9falseQ/uXWwPnO56RBfwtg4h/EQXmucA==" - }, - "diffie-hellman": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.2.tgz", - "integrity": "sha1-tYNXOScM/ias9jIJn97SoH8gnl4=", - "requires": { - "bn.js": "^4.1.0", - "miller-rabin": "^4.0.0", - "randombytes": "^2.0.0" - } - }, - "dom-walk": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.1.tgz", - "integrity": "sha1-ZyIm3HTI95mtNTB9+TaroRrNYBg=" - }, - "domain-browser": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", - "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==" - }, - "duplexer3": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", - "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=" - }, - "duplexify": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.5.3.tgz", - "integrity": "sha512-g8ID9OroF9hKt2POf8YLayy+9594PzmM3scI00/uBXocX3TWNgoB67hjzkFe9ITAbQOne/lLdBxHXvYUM4ZgGA==", - "requires": { - "end-of-stream": "^1.0.0", - "inherits": "^2.0.1", - "readable-stream": "^2.0.0", - "stream-shift": "^1.0.0" - } - }, - "ecc-jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", - "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", - "optional": true, - "requires": { - "jsbn": "~0.1.0" - } - }, - "editions": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/editions/-/editions-1.3.4.tgz", - "integrity": "sha512-gzao+mxnYDzIysXKMQi/+M1mjy/rjestjg6OPoYTtI+3Izp23oiGZitsl9lPDPiTGXbcSIk1iJWhliSaglxnUg==" - }, - "ejs": { - "version": "2.5.7", - "resolved": "https://registry.npmjs.org/ejs/-/ejs-2.5.7.tgz", - "integrity": "sha1-zIcsFoiArjxxiXYv1f/ACJbJUYo=" - }, - "electron-to-chromium": { - "version": "1.3.35", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.35.tgz", - "integrity": "sha1-aTwXz7k4QdOMtZuN8BnRfjVphfA=" - }, - "elegant-spinner": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/elegant-spinner/-/elegant-spinner-1.0.1.tgz", - "integrity": "sha1-2wQ1IcldfjA/2PNFvtwzSc+wcp4=" - }, - "elliptic": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.0.tgz", - "integrity": "sha1-ysmvh2LIWDYYcAPI3+GT5eLq5d8=", - "requires": { - "bn.js": "^4.4.0", - "brorand": "^1.0.1", - "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.0" - } - }, - "emojis-list": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", - "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=" - }, - "end-of-stream": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", - "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", - "requires": { - "once": "^1.4.0" - } - }, - "enhanced-resolve": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.0.0.tgz", - "integrity": "sha512-jox/62b2GofV1qTUQTMPEJSDIGycS43evqYzD/KVtEb9OCoki9cnacUPxCrZa7JfPzZSYOCZhu9O9luaMxAX8g==", - "requires": { - "graceful-fs": "^4.1.2", - "memory-fs": "^0.4.0", - "tapable": "^1.0.0" - } - }, - "errno": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", - "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", - "requires": { - "prr": "~1.0.1" - } - }, - "error": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/error/-/error-7.0.2.tgz", - "integrity": "sha1-pfdf/02ZJhJt2sDqXcOOaJFTywI=", - "requires": { - "string-template": "~0.2.1", - "xtend": "~4.0.0" - } - }, - "error-ex": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz", - "integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=", - "requires": { - "is-arrayish": "^0.2.1" - } - }, - "escape-string-regexp": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.2.tgz", - "integrity": "sha1-Tbwv5nTnGUnK8/smlc5/LcHZqNE=" - }, - "eslint-scope": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.1.tgz", - "integrity": "sha1-PWPD7f2gLgbgGkUq2IyqzHzctug=", - "requires": { - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" - } - }, - "esprima": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz", - "integrity": "sha512-oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw==" - }, - "esrecurse": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", - "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", - "requires": { - "estraverse": "^4.1.0" - } - }, - "estraverse": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", - "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=" - }, - "esutils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", - "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=" - }, - "events": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", - "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=" - }, - "evp_bytestokey": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", - "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", - "requires": { - "md5.js": "^1.3.4", - "safe-buffer": "^5.1.1" - } - }, - "execa": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", - "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", - "requires": { - "cross-spawn": "^5.0.1", - "get-stream": "^3.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - } - }, - "exit-hook": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz", - "integrity": "sha1-8FyiM7SMBdVP/wd2XfhQfpXAL/g=" - }, - "expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "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" - } - }, - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - } - }, - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - } - } - }, - "expand-range": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", - "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=", - "requires": { - "fill-range": "^2.1.0" - }, - "dependencies": { - "fill-range": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.3.tgz", - "integrity": "sha1-ULd9/X5Gm8dJJHCWNpn+eoSFpyM=", - "requires": { - "is-number": "^2.1.0", - "isobject": "^2.0.0", - "randomatic": "^1.1.3", - "repeat-element": "^1.1.2", - "repeat-string": "^1.5.2" - } - }, - "is-number": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", - "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", - "requires": { - "kind-of": "^3.0.2" - } - }, - "isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "requires": { - "isarray": "1.0.0" - } - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "expand-tilde": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", - "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", - "requires": { - "homedir-polyfill": "^1.0.1" - } - }, - "extend": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", - "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=" - }, - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "requires": { - "is-plain-object": "^2.0.4" - } - } - } - }, - "external-editor": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.1.0.tgz", - "integrity": "sha512-E44iT5QVOUJBKij4IIV3uvxuNlbKS38Tw1HiupxEIHPv9qtC2PrDYohbXV5U+1jnfIXttny8gUhj+oZvflFlzA==", - "requires": { - "chardet": "^0.4.0", - "iconv-lite": "^0.4.17", - "tmp": "^0.0.33" - } - }, - "extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" - }, - "fast-deep-equal": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", - "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=" - }, - "fast-json-stable-stringify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", - "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" - }, - "figures": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", - "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", - "requires": { - "escape-string-regexp": "^1.0.5" - }, - "dependencies": { - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" - } - } - }, - "filename-regex": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz", - "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=" - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "find-cache-dir": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-1.0.0.tgz", - "integrity": "sha1-kojj6ePMN0hxfTnq3hfPcfww7m8=", - "requires": { - "commondir": "^1.0.1", - "make-dir": "^1.0.0", - "pkg-dir": "^2.0.0" - } - }, - "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "requires": { - "locate-path": "^2.0.0" - } - }, - "first-chunk-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/first-chunk-stream/-/first-chunk-stream-2.0.0.tgz", - "integrity": "sha1-G97NuOCDwGZLkZRVgVd6Q6nzHXA=", - "requires": { - "readable-stream": "^2.0.2" - } - }, - "flow-parser": { - "version": "0.66.0", - "resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.66.0.tgz", - "integrity": "sha1-vlg/77ARkqpRZEFdMaYkGzVxiYM=" - }, - "flush-write-stream": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.0.2.tgz", - "integrity": "sha1-yBuQ2HRnZvGmCaRoCZRsRd2K5Bc=", - "requires": { - "inherits": "^2.0.1", - "readable-stream": "^2.0.4" - } - }, - "for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=" - }, - "for-own": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", - "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", - "requires": { - "for-in": "^1.0.1" - } - }, - "forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" - }, - "form-data": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz", - "integrity": "sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE=", - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.5", - "mime-types": "^2.1.12" - } - }, - "fragment-cache": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", - "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", - "requires": { - "map-cache": "^0.2.2" - } - }, - "from2": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", - "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", - "requires": { - "inherits": "^2.0.1", - "readable-stream": "^2.0.0" - } - }, - "fs-write-stream-atomic": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz", - "integrity": "sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=", - "requires": { - "graceful-fs": "^4.1.2", - "iferr": "^0.1.5", - "imurmurhash": "^0.1.4", - "readable-stream": "1 || 2" - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" - }, - "fsevents": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.1.3.tgz", - "integrity": "sha512-WIr7iDkdmdbxu/Gh6eKEZJL6KPE74/5MEsf2whTOFNxbIoIixogroLdKYqB6FDav4Wavh/lZdzzd3b2KxIXC5Q==", - "optional": true, - "requires": { - "nan": "^2.3.0", - "node-pre-gyp": "^0.6.39" - }, - "dependencies": { - "abbrev": { - "version": "1.1.0", - "bundled": true, - "optional": true - }, - "ajv": { - "version": "4.11.8", - "bundled": true, - "optional": true, - "requires": { - "co": "^4.6.0", - "json-stable-stringify": "^1.0.1" - } - }, - "ansi-regex": { - "version": "2.1.1", - "bundled": true - }, - "aproba": { - "version": "1.1.1", - "bundled": true, - "optional": true - }, - "are-we-there-yet": { - "version": "1.1.4", - "bundled": true, - "optional": true, - "requires": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" - } - }, - "asn1": { - "version": "0.2.3", - "bundled": true, - "optional": true - }, - "assert-plus": { - "version": "0.2.0", - "bundled": true, - "optional": true - }, - "asynckit": { - "version": "0.4.0", - "bundled": true, - "optional": true - }, - "aws-sign2": { - "version": "0.6.0", - "bundled": true, - "optional": true - }, - "aws4": { - "version": "1.6.0", - "bundled": true, - "optional": true - }, - "balanced-match": { - "version": "0.4.2", - "bundled": true - }, - "bcrypt-pbkdf": { - "version": "1.0.1", - "bundled": true, - "optional": true, - "requires": { - "tweetnacl": "^0.14.3" - } - }, - "block-stream": { - "version": "0.0.9", - "bundled": true, - "requires": { - "inherits": "~2.0.0" - } - }, - "boom": { - "version": "2.10.1", - "bundled": true, - "requires": { - "hoek": "2.x.x" - } - }, - "brace-expansion": { - "version": "1.1.7", - "bundled": true, - "requires": { - "balanced-match": "^0.4.1", - "concat-map": "0.0.1" - } - }, - "buffer-shims": { - "version": "1.0.0", - "bundled": true - }, - "caseless": { - "version": "0.12.0", - "bundled": true, - "optional": true - }, - "co": { - "version": "4.6.0", - "bundled": true, - "optional": true - }, - "code-point-at": { - "version": "1.1.0", - "bundled": true - }, - "combined-stream": { - "version": "1.0.5", - "bundled": true, - "requires": { - "delayed-stream": "~1.0.0" - } - }, - "concat-map": { - "version": "0.0.1", - "bundled": true - }, - "console-control-strings": { - "version": "1.1.0", - "bundled": true - }, - "core-util-is": { - "version": "1.0.2", - "bundled": true - }, - "cryptiles": { - "version": "2.0.5", - "bundled": true, - "requires": { - "boom": "2.x.x" - } - }, - "dashdash": { - "version": "1.14.1", - "bundled": true, - "optional": true, - "requires": { - "assert-plus": "^1.0.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "bundled": true, - "optional": true - } - } - }, - "debug": { - "version": "2.6.8", - "bundled": true, - "optional": true, - "requires": { - "ms": "2.0.0" - } - }, - "deep-extend": { - "version": "0.4.2", - "bundled": true, - "optional": true - }, - "delayed-stream": { - "version": "1.0.0", - "bundled": true - }, - "delegates": { - "version": "1.0.0", - "bundled": true, - "optional": true - }, - "detect-libc": { - "version": "1.0.2", - "bundled": true, - "optional": true - }, - "ecc-jsbn": { - "version": "0.1.1", - "bundled": true, - "optional": true, - "requires": { - "jsbn": "~0.1.0" - } - }, - "extend": { - "version": "3.0.1", - "bundled": true, - "optional": true - }, - "extsprintf": { - "version": "1.0.2", - "bundled": true - }, - "forever-agent": { - "version": "0.6.1", - "bundled": true, - "optional": true - }, - "form-data": { - "version": "2.1.4", - "bundled": true, - "optional": true, - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.5", - "mime-types": "^2.1.12" - } - }, - "fs.realpath": { - "version": "1.0.0", - "bundled": true - }, - "fstream": { - "version": "1.0.11", - "bundled": true, - "requires": { - "graceful-fs": "^4.1.2", - "inherits": "~2.0.0", - "mkdirp": ">=0.5 0", - "rimraf": "2" - } - }, - "fstream-ignore": { - "version": "1.0.5", - "bundled": true, - "optional": true, - "requires": { - "fstream": "^1.0.0", - "inherits": "2", - "minimatch": "^3.0.0" - } - }, - "gauge": { - "version": "2.7.4", - "bundled": true, - "optional": true, - "requires": { - "aproba": "^1.0.3", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", - "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" - } - }, - "getpass": { - "version": "0.1.7", - "bundled": true, - "optional": true, - "requires": { - "assert-plus": "^1.0.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "bundled": true, - "optional": true - } - } - }, - "glob": { - "version": "7.1.2", - "bundled": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "graceful-fs": { - "version": "4.1.11", - "bundled": true - }, - "har-schema": { - "version": "1.0.5", - "bundled": true, - "optional": true - }, - "har-validator": { - "version": "4.2.1", - "bundled": true, - "optional": true, - "requires": { - "ajv": "^4.9.1", - "har-schema": "^1.0.5" - } - }, - "has-unicode": { - "version": "2.0.1", - "bundled": true, - "optional": true - }, - "hawk": { - "version": "3.1.3", - "bundled": true, - "requires": { - "boom": "2.x.x", - "cryptiles": "2.x.x", - "hoek": "2.x.x", - "sntp": "1.x.x" - } - }, - "hoek": { - "version": "2.16.3", - "bundled": true - }, - "http-signature": { - "version": "1.1.1", - "bundled": true, - "optional": true, - "requires": { - "assert-plus": "^0.2.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - } - }, - "inflight": { - "version": "1.0.6", - "bundled": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.3", - "bundled": true - }, - "ini": { - "version": "1.3.4", - "bundled": true, - "optional": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "bundled": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "is-typedarray": { - "version": "1.0.0", - "bundled": true, - "optional": true - }, - "isarray": { - "version": "1.0.0", - "bundled": true - }, - "isstream": { - "version": "0.1.2", - "bundled": true, - "optional": true - }, - "jodid25519": { - "version": "1.0.2", - "bundled": true, - "optional": true, - "requires": { - "jsbn": "~0.1.0" - } - }, - "jsbn": { - "version": "0.1.1", - "bundled": true, - "optional": true - }, - "json-schema": { - "version": "0.2.3", - "bundled": true, - "optional": true - }, - "json-stable-stringify": { - "version": "1.0.1", - "bundled": true, - "optional": true, - "requires": { - "jsonify": "~0.0.0" - } - }, - "json-stringify-safe": { - "version": "5.0.1", - "bundled": true, - "optional": true - }, - "jsonify": { - "version": "0.0.0", - "bundled": true, - "optional": true - }, - "jsprim": { - "version": "1.4.0", - "bundled": true, - "optional": true, - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.0.2", - "json-schema": "0.2.3", - "verror": "1.3.6" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "bundled": true, - "optional": true - } - } - }, - "mime-db": { - "version": "1.27.0", - "bundled": true - }, - "mime-types": { - "version": "2.1.15", - "bundled": true, - "requires": { - "mime-db": "~1.27.0" - } - }, - "minimatch": { - "version": "3.0.4", - "bundled": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "0.0.8", - "bundled": true - }, - "mkdirp": { - "version": "0.5.1", - "bundled": true, - "requires": { - "minimist": "0.0.8" - } - }, - "ms": { - "version": "2.0.0", - "bundled": true, - "optional": true - }, - "node-pre-gyp": { - "version": "0.6.39", - "bundled": true, - "optional": true, - "requires": { - "detect-libc": "^1.0.2", - "hawk": "3.1.3", - "mkdirp": "^0.5.1", - "nopt": "^4.0.1", - "npmlog": "^4.0.2", - "rc": "^1.1.7", - "request": "2.81.0", - "rimraf": "^2.6.1", - "semver": "^5.3.0", - "tar": "^2.2.1", - "tar-pack": "^3.4.0" - } - }, - "nopt": { - "version": "4.0.1", - "bundled": true, - "optional": true, - "requires": { - "abbrev": "1", - "osenv": "^0.1.4" - } - }, - "npmlog": { - "version": "4.1.0", - "bundled": true, - "optional": true, - "requires": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "bundled": true - }, - "oauth-sign": { - "version": "0.8.2", - "bundled": true, - "optional": true - }, - "object-assign": { - "version": "4.1.1", - "bundled": true, - "optional": true - }, - "once": { - "version": "1.4.0", - "bundled": true, - "requires": { - "wrappy": "1" - } - }, - "os-homedir": { - "version": "1.0.2", - "bundled": true, - "optional": true - }, - "os-tmpdir": { - "version": "1.0.2", - "bundled": true, - "optional": true - }, - "osenv": { - "version": "0.1.4", - "bundled": true, - "optional": true, - "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "bundled": true - }, - "performance-now": { - "version": "0.2.0", - "bundled": true, - "optional": true - }, - "process-nextick-args": { - "version": "1.0.7", - "bundled": true - }, - "punycode": { - "version": "1.4.1", - "bundled": true, - "optional": true - }, - "qs": { - "version": "6.4.0", - "bundled": true, - "optional": true - }, - "rc": { - "version": "1.2.1", - "bundled": true, - "optional": true, - "requires": { - "deep-extend": "~0.4.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "bundled": true, - "optional": true - } - } - }, - "readable-stream": { - "version": "2.2.9", - "bundled": true, - "requires": { - "buffer-shims": "~1.0.0", - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "~1.0.0", - "process-nextick-args": "~1.0.6", - "string_decoder": "~1.0.0", - "util-deprecate": "~1.0.1" - } - }, - "request": { - "version": "2.81.0", - "bundled": true, - "optional": true, - "requires": { - "aws-sign2": "~0.6.0", - "aws4": "^1.2.1", - "caseless": "~0.12.0", - "combined-stream": "~1.0.5", - "extend": "~3.0.0", - "forever-agent": "~0.6.1", - "form-data": "~2.1.1", - "har-validator": "~4.2.1", - "hawk": "~3.1.3", - "http-signature": "~1.1.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.7", - "oauth-sign": "~0.8.1", - "performance-now": "^0.2.0", - "qs": "~6.4.0", - "safe-buffer": "^5.0.1", - "stringstream": "~0.0.4", - "tough-cookie": "~2.3.0", - "tunnel-agent": "^0.6.0", - "uuid": "^3.0.0" - } - }, - "rimraf": { - "version": "2.6.1", - "bundled": true, - "requires": { - "glob": "^7.0.5" - } - }, - "safe-buffer": { - "version": "5.0.1", - "bundled": true - }, - "semver": { - "version": "5.3.0", - "bundled": true, - "optional": true - }, - "set-blocking": { - "version": "2.0.0", - "bundled": true, - "optional": true - }, - "signal-exit": { - "version": "3.0.2", - "bundled": true, - "optional": true - }, - "sntp": { - "version": "1.0.9", - "bundled": true, - "requires": { - "hoek": "2.x.x" - } - }, - "sshpk": { - "version": "1.13.0", - "bundled": true, - "optional": true, - "requires": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jodid25519": "^1.0.0", - "jsbn": "~0.1.0", - "tweetnacl": "~0.14.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "bundled": true, - "optional": true - } - } - }, - "string-width": { - "version": "1.0.2", - "bundled": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - }, - "string_decoder": { - "version": "1.0.1", - "bundled": true, - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "stringstream": { - "version": "0.0.5", - "bundled": true, - "optional": true - }, - "strip-ansi": { - "version": "3.0.1", - "bundled": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "strip-json-comments": { - "version": "2.0.1", - "bundled": true, - "optional": true - }, - "tar": { - "version": "2.2.1", - "bundled": true, - "requires": { - "block-stream": "*", - "fstream": "^1.0.2", - "inherits": "2" - } - }, - "tar-pack": { - "version": "3.4.0", - "bundled": true, - "optional": true, - "requires": { - "debug": "^2.2.0", - "fstream": "^1.0.10", - "fstream-ignore": "^1.0.5", - "once": "^1.3.3", - "readable-stream": "^2.1.4", - "rimraf": "^2.5.1", - "tar": "^2.2.1", - "uid-number": "^0.0.6" - } - }, - "tough-cookie": { - "version": "2.3.2", - "bundled": true, - "optional": true, - "requires": { - "punycode": "^1.4.1" - } - }, - "tunnel-agent": { - "version": "0.6.0", - "bundled": true, - "optional": true, - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "tweetnacl": { - "version": "0.14.5", - "bundled": true, - "optional": true - }, - "uid-number": { - "version": "0.0.6", - "bundled": true, - "optional": true - }, - "util-deprecate": { - "version": "1.0.2", - "bundled": true - }, - "uuid": { - "version": "3.0.1", - "bundled": true, - "optional": true - }, - "verror": { - "version": "1.3.6", - "bundled": true, - "optional": true, - "requires": { - "extsprintf": "1.0.2" - } - }, - "wide-align": { - "version": "1.1.2", - "bundled": true, - "optional": true, - "requires": { - "string-width": "^1.0.2" - } - }, - "wrappy": { - "version": "1.0.2", - "bundled": true - } - } - }, - "get-caller-file": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.2.tgz", - "integrity": "sha1-9wLmMSfn4jHBYKgMFVSstw1QR+U=" - }, - "get-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", - "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=" - }, - "get-value": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=" - }, - "getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", - "requires": { - "assert-plus": "^1.0.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" - } - } - }, - "gh-got": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/gh-got/-/gh-got-6.0.0.tgz", - "integrity": "sha512-F/mS+fsWQMo1zfgG9MD8KWvTWPPzzhuVwY++fhQ5Ggd+0P+CAMHtzMZhNxG+TqGfHDChJKsbh6otfMGqO2AKBw==", - "requires": { - "got": "^7.0.0", - "is-plain-obj": "^1.1.0" - } - }, - "github-username": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/github-username/-/github-username-4.1.0.tgz", - "integrity": "sha1-y+KABBiDIG2kISrp5LXxacML9Bc=", - "requires": { - "gh-got": "^6.0.0" - } - }, - "glob-all": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/glob-all/-/glob-all-3.1.0.tgz", - "integrity": "sha1-iRPd+17hrHgSZWJBsD1SF8ZLAqs=", - "requires": { - "glob": "^7.0.5", - "yargs": "~1.2.6" - }, - "dependencies": { - "glob": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", - "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" - } - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.1.0.tgz", - "integrity": "sha1-md9lelJXTCHJBXSX33QnkLK0wN4=" - }, - "yargs": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-1.2.6.tgz", - "integrity": "sha1-nHtKgv1dWVsr8Xq23MQxNUMv40s=", - "requires": { - "minimist": "^0.1.0" - } - } - } - }, - "glob-base": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", - "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=", - "requires": { - "glob-parent": "^2.0.0", - "is-glob": "^2.0.0" - }, - "dependencies": { - "glob-parent": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", - "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", - "requires": { - "is-glob": "^2.0.0" - } - }, - "is-extglob": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", - "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=" - }, - "is-glob": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", - "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", - "requires": { - "is-extglob": "^1.0.0" - } - } - } - }, - "glob-parent": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", - "requires": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" - }, - "dependencies": { - "is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "requires": { - "is-extglob": "^2.1.0" - } - } - } - }, - "global": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/global/-/global-4.3.2.tgz", - "integrity": "sha1-52mJJopsdMOJCLEwWxD8DjlOnQ8=", - "requires": { - "min-document": "^2.19.0", - "process": "~0.5.1" - }, - "dependencies": { - "process": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/process/-/process-0.5.2.tgz", - "integrity": "sha1-FjjYqONML0QKkduVq5rrZ3/Bhc8=" - } - } - }, - "global-modules": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", - "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", - "requires": { - "global-prefix": "^1.0.1", - "is-windows": "^1.0.1", - "resolve-dir": "^1.0.0" - } - }, - "global-prefix": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", - "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", - "requires": { - "expand-tilde": "^2.0.2", - "homedir-polyfill": "^1.0.1", - "ini": "^1.3.4", - "is-windows": "^1.0.1", - "which": "^1.2.14" - } - }, - "globals": { - "version": "9.18.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", - "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==" - }, - "globby": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", - "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", - "requires": { - "array-union": "^1.0.1", - "glob": "^7.0.3", - "object-assign": "^4.0.1", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" - }, - "dependencies": { - "glob": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", - "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" - } - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" - } - } - }, - "got": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/got/-/got-7.1.0.tgz", - "integrity": "sha512-Y5WMo7xKKq1muPsxD+KmrR8DH5auG7fBdDVueZwETwV6VytKyU9OX/ddpq2/1hp1vIPvVb4T81dKQz3BivkNLw==", - "requires": { - "decompress-response": "^3.2.0", - "duplexer3": "^0.1.4", - "get-stream": "^3.0.0", - "is-plain-obj": "^1.1.0", - "is-retry-allowed": "^1.0.0", - "is-stream": "^1.0.0", - "isurl": "^1.0.0-alpha5", - "lowercase-keys": "^1.0.0", - "p-cancelable": "^0.3.0", - "p-timeout": "^1.1.1", - "safe-buffer": "^5.0.1", - "timed-out": "^4.0.0", - "url-parse-lax": "^1.0.0", - "url-to-options": "^1.0.1" - } - }, - "graceful-fs": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", - "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" - }, - "grouped-queue": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/grouped-queue/-/grouped-queue-0.3.3.tgz", - "integrity": "sha1-wWfSpTGcWg4JZO9qJbfC34mWyFw=", - "requires": { - "lodash": "^4.17.2" - } - }, - "har-schema": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-1.0.5.tgz", - "integrity": "sha1-0mMTX0MwfALGAq/I/pWXDAFRNp4=" - }, - "har-validator": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-4.2.1.tgz", - "integrity": "sha1-M0gdDxu/9gDdID11gSpqX7oALio=", - "requires": { - "ajv": "^4.9.1", - "har-schema": "^1.0.5" - }, - "dependencies": { - "ajv": { - "version": "4.11.8", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", - "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=", - "requires": { - "co": "^4.6.0", - "json-stable-stringify": "^1.0.1" - } - } - } - }, - "has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "requires": { - "ansi-regex": "^2.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" - } - } - }, - "has-color": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/has-color/-/has-color-0.1.7.tgz", - "integrity": "sha1-ZxRKUmDDT8PMpnfQQdr1L+e3iy8=" - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" - }, - "has-symbol-support-x": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz", - "integrity": "sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw==" - }, - "has-to-string-tag-x": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz", - "integrity": "sha512-vdbKfmw+3LoOYVr+mtxHaX5a96+0f3DljYd8JOqvOLsf5mw2Otda2qCDT9qRqLAhrjyQ0h7ual5nOiASpsGNFw==", - "requires": { - "has-symbol-support-x": "^1.4.1" - } - }, - "has-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", - "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", - "requires": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" - } - }, - "has-values": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", - "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", - "requires": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" - }, - "dependencies": { - "kind-of": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "hash-base": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-2.0.2.tgz", - "integrity": "sha1-ZuodhW206KVHDK32/OI65SRO8uE=", - "requires": { - "inherits": "^2.0.1" - } - }, - "hash.js": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.3.tgz", - "integrity": "sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA==", - "requires": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.0" - } - }, - "hawk": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", - "integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=", - "requires": { - "boom": "2.x.x", - "cryptiles": "2.x.x", - "hoek": "2.x.x", - "sntp": "1.x.x" - } - }, - "he": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", - "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=" - }, - "hmac-drbg": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", - "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", - "requires": { - "hash.js": "^1.0.3", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.1" - } - }, - "hoek": { - "version": "2.16.3", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", - "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=" - }, - "home-or-tmp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz", - "integrity": "sha1-42w/LSyufXRqhX440Y1fMqeILbg=", - "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.1" - } - }, - "homedir-polyfill": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz", - "integrity": "sha1-TCu8inWJmP7r9e1oWA921GdotLw=", - "requires": { - "parse-passwd": "^1.0.0" - } - }, - "hosted-git-info": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.5.0.tgz", - "integrity": "sha512-pNgbURSuab90KbTqvRPsseaTxOJCZBD0a7t+haSN33piP9cCM4l0CqdzAif2hUqm716UovKB2ROmiabGAKVXyg==" - }, - "http-signature": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz", - "integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=", - "requires": { - "assert-plus": "^0.2.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - } - }, - "https-browserify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", - "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=" - }, - "iconv-lite": { - "version": "0.4.19", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz", - "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ==" - }, - "ieee754": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.8.tgz", - "integrity": "sha1-vjPUCsEO8ZJnAfbwii2G+/0a0+Q=" - }, - "iferr": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz", - "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=" - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" - }, - "indent-string": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", - "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", - "requires": { - "repeating": "^2.0.0" - } - }, - "indexof": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", - "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=" - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" - }, - "ini": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", - "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" - }, - "inquirer": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.3.0.tgz", - "integrity": "sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ==", - "requires": { - "ansi-escapes": "^3.0.0", - "chalk": "^2.0.0", - "cli-cursor": "^2.1.0", - "cli-width": "^2.0.0", - "external-editor": "^2.0.4", - "figures": "^2.0.0", - "lodash": "^4.3.0", - "mute-stream": "0.0.7", - "run-async": "^2.2.0", - "rx-lite": "^4.0.8", - "rx-lite-aggregates": "^4.0.8", - "string-width": "^2.1.0", - "strip-ansi": "^4.0.0", - "through": "^2.3.6" - } - }, - "interpret": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.1.0.tgz", - "integrity": "sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ=" - }, - "invariant": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.3.tgz", - "integrity": "sha512-7Z5PPegwDTyjbaeCnV0efcyS6vdKAU51kpEmS7QFib3P4822l8ICYyMn7qvJnc+WzLoDsuI9gPMKbJ8pCu8XtA==", - "requires": { - "loose-envify": "^1.0.0" - } - }, - "invert-kv": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", - "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=" - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" - }, - "is-binary-path": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", - "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", - "requires": { - "binary-extensions": "^1.0.0" - } - }, - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" - }, - "is-builtin-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", - "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", - "requires": { - "builtin-modules": "^1.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "is-dotfile": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz", - "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=" - }, - "is-equal-shallow": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz", - "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=", - "requires": { - "is-primitive": "^2.0.0" - } - }, - "is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=" - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" - }, - "is-finite": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", - "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" - }, - "is-glob": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.0.tgz", - "integrity": "sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A=", - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-object": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.1.tgz", - "integrity": "sha1-iVJojF7C/9awPsyF52ngKQMINHA=" - }, - "is-odd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-odd/-/is-odd-2.0.0.tgz", - "integrity": "sha512-OTiixgpZAT1M4NHgS5IguFp/Vz2VI3U7Goh4/HA1adtwyLtSBrxYlcSYkhpAE07s4fKEcjrFxyvtQBND4vFQyQ==", - "requires": { - "is-number": "^4.0.0" - }, - "dependencies": { - "is-number": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", - "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==" - } - } - }, - "is-plain-obj": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", - "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=" - }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "requires": { - "isobject": "^3.0.1" - } - }, - "is-posix-bracket": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz", - "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=" - }, - "is-primitive": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz", - "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=" - }, - "is-promise": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", - "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=" - }, - "is-retry-allowed": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz", - "integrity": "sha1-EaBgVotnM5REAz0BJaYaINVk+zQ=" - }, - "is-scoped": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-scoped/-/is-scoped-1.0.0.tgz", - "integrity": "sha1-RJypgpnnEwOCViieyytUDcQ3yzA=", - "requires": { - "scoped-regex": "^1.0.0" - } - }, - "is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" - }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" - }, - "is-utf8": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", - "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=" - }, - "is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==" - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" - }, - "isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" - }, - "istextorbinary": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/istextorbinary/-/istextorbinary-2.2.1.tgz", - "integrity": "sha512-TS+hoFl8Z5FAFMK38nhBkdLt44CclNRgDHWeMgsV8ko3nDlr/9UI2Sf839sW7enijf8oKsZYXRvM8g0it9Zmcw==", - "requires": { - "binaryextensions": "2", - "editions": "^1.3.3", - "textextensions": "2" - } - }, - "isurl": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isurl/-/isurl-1.0.0.tgz", - "integrity": "sha512-1P/yWsxPlDtn7QeRD+ULKQPaIaN6yF368GZ2vDfv0AL0NwpStafjWCDDdn0k8wgFMWpVAqG7oJhxHnlud42i9w==", - "requires": { - "has-to-string-tag-x": "^1.2.0", - "is-object": "^1.0.1" - } - }, - "js-tokens": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", - "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=" - }, - "jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", - "optional": true - }, - "jscodeshift": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/jscodeshift/-/jscodeshift-0.4.1.tgz", - "integrity": "sha512-iOX6If+hsw0q99V3n31t4f5VlD1TQZddH08xbT65ZqA7T4Vkx68emrDZMUOLVvCEAJ6NpAk7DECe3fjC/t52AQ==", - "requires": { - "async": "^1.5.0", - "babel-plugin-transform-flow-strip-types": "^6.8.0", - "babel-preset-es2015": "^6.9.0", - "babel-preset-stage-1": "^6.5.0", - "babel-register": "^6.9.0", - "babylon": "^6.17.3", - "colors": "^1.1.2", - "flow-parser": "^0.*", - "lodash": "^4.13.1", - "micromatch": "^2.3.7", - "node-dir": "0.1.8", - "nomnom": "^1.8.1", - "recast": "^0.12.5", - "temp": "^0.8.1", - "write-file-atomic": "^1.2.0" - }, - "dependencies": { - "arr-diff": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", - "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", - "requires": { - "arr-flatten": "^1.0.1" - } - }, - "array-unique": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", - "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=" - }, - "braces": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", - "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", - "requires": { - "expand-range": "^1.8.1", - "preserve": "^0.2.0", - "repeat-element": "^1.1.2" - } - }, - "expand-brackets": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", - "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", - "requires": { - "is-posix-bracket": "^0.1.0" - } - }, - "extglob": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", - "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", - "requires": { - "is-extglob": "^1.0.0" - } - }, - "is-extglob": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", - "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=" - }, - "is-glob": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", - "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", - "requires": { - "is-extglob": "^1.0.0" - } - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - }, - "micromatch": { - "version": "2.3.11", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", - "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", - "requires": { - "arr-diff": "^2.0.0", - "array-unique": "^0.2.1", - "braces": "^1.8.2", - "expand-brackets": "^0.1.4", - "extglob": "^0.3.1", - "filename-regex": "^2.0.0", - "is-extglob": "^1.0.0", - "is-glob": "^2.0.1", - "kind-of": "^3.0.2", - "normalize-path": "^2.0.1", - "object.omit": "^2.0.0", - "parse-glob": "^3.0.4", - "regex-cache": "^0.4.2" - } - }, - "recast": { - "version": "0.12.9", - "resolved": "https://registry.npmjs.org/recast/-/recast-0.12.9.tgz", - "integrity": "sha512-y7ANxCWmMW8xLOaiopiRDlyjQ9ajKRENBH+2wjntIbk3A6ZR1+BLQttkmSHMY7Arl+AAZFwJ10grg2T6f1WI8A==", - "requires": { - "ast-types": "0.10.1", - "core-js": "^2.4.1", - "esprima": "~4.0.0", - "private": "~0.1.5", - "source-map": "~0.6.1" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "jsesc": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=" - }, - "json-schema": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" - }, - "json-schema-traverse": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", - "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=" - }, - "json-stable-stringify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", - "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", - "requires": { - "jsonify": "~0.0.0" - } - }, - "json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" - }, - "json5": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", - "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=" - }, - "jsonify": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", - "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=" - }, - "jsprim": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", - "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.2.3", - "verror": "1.10.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" - } - } - }, - "just-extend": { - "version": "1.1.27", - "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-1.1.27.tgz", - "integrity": "sha512-mJVp13Ix6gFo3SBAy9U/kL+oeZqzlYYYLQBwXVBlVzIsZwBqGREnOro24oC/8s8aox+rJhtZ2DiQof++IrkA+g==" - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" - }, - "lazy-cache": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-2.0.2.tgz", - "integrity": "sha1-uRkKT5EzVGlIQIWfio9whNiCImQ=", - "requires": { - "set-getter": "^0.1.0" - } - }, - "lcid": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", - "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", - "requires": { - "invert-kv": "^1.0.0" - } - }, - "listr": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/listr/-/listr-0.12.0.tgz", - "integrity": "sha1-a84sD1YD+klYDqF81qAMwOX6RRo=", - "requires": { - "chalk": "^1.1.3", - "cli-truncate": "^0.2.1", - "figures": "^1.7.0", - "indent-string": "^2.1.0", - "is-promise": "^2.1.0", - "is-stream": "^1.1.0", - "listr-silent-renderer": "^1.1.1", - "listr-update-renderer": "^0.2.0", - "listr-verbose-renderer": "^0.4.0", - "log-symbols": "^1.0.2", - "log-update": "^1.0.2", - "ora": "^0.2.3", - "p-map": "^1.1.1", - "rxjs": "^5.0.0-beta.11", - "stream-to-observable": "^0.1.0", - "strip-ansi": "^3.0.1" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" - }, - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "figures": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", - "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", - "requires": { - "escape-string-regexp": "^1.0.5", - "object-assign": "^4.1.0" - }, - "dependencies": { - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" - } - } - }, - "log-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-1.0.2.tgz", - "integrity": "sha1-N2/3tY6jCGoPCfrMdGF+ylAeGhg=", - "requires": { - "chalk": "^1.0.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" - } - } - }, - "listr-silent-renderer": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/listr-silent-renderer/-/listr-silent-renderer-1.1.1.tgz", - "integrity": "sha1-kktaN1cVN3C/Go4/v3S4u/P5JC4=" - }, - "listr-update-renderer": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/listr-update-renderer/-/listr-update-renderer-0.2.0.tgz", - "integrity": "sha1-yoDhd5tOcCZoB+ju0a1qvjmFUPk=", - "requires": { - "chalk": "^1.1.3", - "cli-truncate": "^0.2.1", - "elegant-spinner": "^1.0.1", - "figures": "^1.7.0", - "indent-string": "^3.0.0", - "log-symbols": "^1.0.2", - "log-update": "^1.0.2", - "strip-ansi": "^3.0.1" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" - }, - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "figures": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", - "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", - "requires": { - "escape-string-regexp": "^1.0.5", - "object-assign": "^4.1.0" - }, - "dependencies": { - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" - } - } - }, - "indent-string": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", - "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=" - }, - "log-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-1.0.2.tgz", - "integrity": "sha1-N2/3tY6jCGoPCfrMdGF+ylAeGhg=", - "requires": { - "chalk": "^1.0.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" - } - } - }, - "listr-verbose-renderer": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/listr-verbose-renderer/-/listr-verbose-renderer-0.4.1.tgz", - "integrity": "sha1-ggb0z21S3cWCfl/RSYng6WWTOjU=", - "requires": { - "chalk": "^1.1.3", - "cli-cursor": "^1.0.2", - "date-fns": "^1.27.2", - "figures": "^1.7.0" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" - }, - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "cli-cursor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz", - "integrity": "sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc=", - "requires": { - "restore-cursor": "^1.0.1" - } - }, - "figures": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", - "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", - "requires": { - "escape-string-regexp": "^1.0.5", - "object-assign": "^4.1.0" - }, - "dependencies": { - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" - } - } - }, - "onetime": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz", - "integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=" - }, - "restore-cursor": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz", - "integrity": "sha1-NGYfRohjJ/7SmRR5FSJS35LapUE=", - "requires": { - "exit-hook": "^1.0.0", - "onetime": "^1.0.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" - } - } - }, - "load-json-file": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", - "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", - "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "strip-bom": "^3.0.0" - }, - "dependencies": { - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" - } - } - }, - "loader-runner": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.3.0.tgz", - "integrity": "sha1-9IKuqC1UPgeSFwDVpG7yb9rGuKI=" - }, - "loader-utils": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.1.0.tgz", - "integrity": "sha1-yYrvSIvM7aL/teLeZG1qdUQp9c0=", - "requires": { - "big.js": "^3.1.3", - "emojis-list": "^2.0.0", - "json5": "^0.5.0" - } - }, - "locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", - "requires": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" - } - }, - "lodash": { - "version": "4.17.5", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.5.tgz", - "integrity": "sha512-svL3uiZf1RwhH+cWrfZn3A4+U58wbP0tGVTLQPbjplZxZ8ROD9VLuNgsRniTlLe7OlSqR79RUehXgpBW/s0IQw==" - }, - "lodash.get": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=" - }, - "log-symbols": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.1.0.tgz", - "integrity": "sha512-zLeLrzMA1A2vRF1e/0Mo+LNINzi6jzBylHj5WqvQ/WK/5WCZt8si9SyN4p9llr/HRYvVR1AoXHRHl4WTHyQAzQ==", - "requires": { - "chalk": "^2.0.1" - } - }, - "log-update": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/log-update/-/log-update-1.0.2.tgz", - "integrity": "sha1-GZKfZMQJPS0ucHWh2tivWcKWuNE=", - "requires": { - "ansi-escapes": "^1.0.0", - "cli-cursor": "^1.0.2" - }, - "dependencies": { - "ansi-escapes": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz", - "integrity": "sha1-06ioOzGapneTZisT52HHkRQiMG4=" - }, - "cli-cursor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz", - "integrity": "sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc=", - "requires": { - "restore-cursor": "^1.0.1" - } - }, - "onetime": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz", - "integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=" - }, - "restore-cursor": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz", - "integrity": "sha1-NGYfRohjJ/7SmRR5FSJS35LapUE=", - "requires": { - "exit-hook": "^1.0.0", - "onetime": "^1.0.0" - } - } - } - }, - "loose-envify": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz", - "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=", - "requires": { - "js-tokens": "^3.0.0" - } - }, - "lowercase-keys": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.0.tgz", - "integrity": "sha1-TjNms55/VFfjXxMkvfb4jQv8cwY=" - }, - "make-dir": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.2.0.tgz", - "integrity": "sha512-aNUAa4UMg/UougV25bbrU4ZaaKNjJ/3/xnvg/twpmKROPdKZPZ9wGgI0opdZzO8q/zUFawoUuixuOv33eZ61Iw==", - "requires": { - "pify": "^3.0.0" - } - }, - "map-cache": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=" - }, - "map-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", - "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", - "requires": { - "object-visit": "^1.0.0" - } - }, - "md5.js": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.4.tgz", - "integrity": "sha1-6b296UogpawYsENA/Fdk1bCdkB0=", - "requires": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1" - }, - "dependencies": { - "hash-base": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", - "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=", - "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - } - } - }, - "mem": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/mem/-/mem-1.1.0.tgz", - "integrity": "sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=", - "requires": { - "mimic-fn": "^1.0.0" - } - }, - "mem-fs": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/mem-fs/-/mem-fs-1.1.3.tgz", - "integrity": "sha1-uK6NLj/Lb10/kWXBLUVRoGXZicw=", - "requires": { - "through2": "^2.0.0", - "vinyl": "^1.1.0", - "vinyl-file": "^2.0.0" - }, - "dependencies": { - "clone": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.3.tgz", - "integrity": "sha1-KY1+IjFmD0DAA8LtMUDezz9TCF8=" - }, - "clone-stats": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz", - "integrity": "sha1-uI+UqCzzi4eR1YBG6kAprYjKmdE=" - }, - "replace-ext": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz", - "integrity": "sha1-KbvZIHinOfC8zitO5B6DeVNSKSQ=" - }, - "vinyl": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-1.2.0.tgz", - "integrity": "sha1-XIgDbPVl5d8FVYv8kR+GVt8hiIQ=", - "requires": { - "clone": "^1.0.0", - "clone-stats": "^0.0.1", - "replace-ext": "0.0.1" - } - } - } - }, - "mem-fs-editor": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/mem-fs-editor/-/mem-fs-editor-3.0.2.tgz", - "integrity": "sha1-3Qpuryu4prN3QAZ6pUnrUwEFr58=", - "requires": { - "commondir": "^1.0.1", - "deep-extend": "^0.4.0", - "ejs": "^2.3.1", - "glob": "^7.0.3", - "globby": "^6.1.0", - "mkdirp": "^0.5.0", - "multimatch": "^2.0.0", - "rimraf": "^2.2.8", - "through2": "^2.0.0", - "vinyl": "^2.0.1" - }, - "dependencies": { - "glob": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", - "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" - } - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "requires": { - "brace-expansion": "^1.1.7" - } - } - } - }, - "memory-fs": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", - "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=", - "requires": { - "errno": "^0.1.3", - "readable-stream": "^2.0.1" - } - }, - "micromatch": { - "version": "3.1.9", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.9.tgz", - "integrity": "sha512-SlIz6sv5UPaAVVFRKodKjCg48EbNoIhgetzfK/Cy0v5U52Z6zB136M8tp0UC9jM53LYbmIRihJszvvqpKkfm9g==", - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - } - }, - "miller-rabin": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", - "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", - "requires": { - "bn.js": "^4.0.0", - "brorand": "^1.0.1" - } - }, - "mime-db": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", - "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==" - }, - "mime-types": { - "version": "2.1.18", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", - "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", - "requires": { - "mime-db": "~1.33.0" - } - }, - "mimic-fn": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", - "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==" - }, - "mimic-response": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.0.tgz", - "integrity": "sha1-3z02Uqc/3ta5sLJBRub9BSNTRY4=" - }, - "min-document": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz", - "integrity": "sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU=", - "requires": { - "dom-walk": "^0.1.0" - } - }, - "minimalistic-assert": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz", - "integrity": "sha1-cCvi3aazf0g2vLP121ZkG2Sh09M=" - }, - "minimalistic-crypto-utils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", - "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=" - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" - }, - "mississippi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-2.0.0.tgz", - "integrity": "sha512-zHo8v+otD1J10j/tC+VNoGK9keCuByhKovAvdn74dmxJl9+mWHnx6EMsDN4lgRoMI/eYo2nchAxniIbUPb5onw==", - "requires": { - "concat-stream": "^1.5.0", - "duplexify": "^3.4.2", - "end-of-stream": "^1.1.0", - "flush-write-stream": "^1.0.0", - "from2": "^2.1.0", - "parallel-transform": "^1.1.0", - "pump": "^2.0.1", - "pumpify": "^1.3.3", - "stream-each": "^1.1.0", - "through2": "^2.0.0" - } - }, - "mixin-deep": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz", - "integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==", - "requires": { - "for-in": "^1.0.2", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "requires": { - "is-plain-object": "^2.0.4" - } - } - } - }, - "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "requires": { - "minimist": "0.0.8" - } - }, - "mocha": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-5.0.1.tgz", - "integrity": "sha512-SpwyojlnE/WRBNGtvJSNfllfm5PqEDFxcWluSIgLeSBJtXG4DmoX2NNAeEA7rP5kK+79VgtVq8nG6HskaL1ykg==", - "requires": { - "browser-stdout": "1.3.0", - "commander": "2.11.0", - "debug": "3.1.0", - "diff": "3.3.1", - "escape-string-regexp": "1.0.5", - "glob": "7.1.2", - "growl": "1.10.3", - "he": "1.1.1", - "mkdirp": "0.5.1", - "supports-color": "4.4.0" - }, - "dependencies": { - "commander": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz", - "integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==" - }, - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "requires": { - "ms": "2.0.0" - } - }, - "diff": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/diff/-/diff-3.3.1.tgz", - "integrity": "sha512-MKPHZDMB0o6yHyDryUOScqZibp914ksXwAMYMTHj6KO8UeKsRYNJD3oNCKjTqZon+V488P7N/HzXF8t7ZR95ww==" - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" - }, - "glob": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", - "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" - } - }, - "growl": { - "version": "1.10.3", - "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.3.tgz", - "integrity": "sha512-hKlsbA5Vu3xsh1Cg3J7jSmX/WaW6A5oBeqzM88oNbCRQFz+zUaXm6yxS4RVytp1scBoJzSYl4YAEOQIt6O8V1Q==" - }, - "has-flag": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", - "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=" - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "supports-color": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", - "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", - "requires": { - "has-flag": "^2.0.0" - } - } - } - }, - "move-concurrently": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", - "integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=", - "requires": { - "aproba": "^1.1.1", - "copy-concurrently": "^1.0.0", - "fs-write-stream-atomic": "^1.0.8", - "mkdirp": "^0.5.1", - "rimraf": "^2.5.4", - "run-queue": "^1.0.3" - } - }, - "ms": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", - "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=" - }, - "multimatch": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/multimatch/-/multimatch-2.1.0.tgz", - "integrity": "sha1-nHkGoi+0wCkZ4vX3UWG0zb1LKis=", - "requires": { - "array-differ": "^1.0.0", - "array-union": "^1.0.1", - "arrify": "^1.0.0", - "minimatch": "^3.0.0" - }, - "dependencies": { - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "requires": { - "brace-expansion": "^1.1.7" - } - } - } - }, - "mute-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", - "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=" - }, - "nan": { - "version": "2.9.2", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.9.2.tgz", - "integrity": "sha512-ltW65co7f3PQWBDbqVvaU1WtFJUsNW7sWWm4HINhbMQIyVyzIeyZ8toX5TC5eeooE6piZoaEh4cZkueSKG3KYw==", - "optional": true - }, - "nanomatch": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.9.tgz", - "integrity": "sha512-n8R9bS8yQ6eSXaV6jHUpKzD8gLsin02w1HSFiegwrs9E098Ylhw5jdyKPaYqvHknHaSCKTPp7C8dGCQ0q9koXA==", - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "fragment-cache": "^0.2.1", - "is-odd": "^2.0.0", - "is-windows": "^1.0.2", - "kind-of": "^6.0.2", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - } - }, - "neo-async": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.5.0.tgz", - "integrity": "sha512-nJmSswG4As/MkRq7QZFuH/sf/yuv8ODdMZrY4Bedjp77a5MK4A6s7YbBB64c9u79EBUOfXUXBvArmvzTD0X+6g==" - }, - "nise": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/nise/-/nise-1.2.7.tgz", - "integrity": "sha512-8LqP1pFLB1v5QU8KlT2WqWzhMRJ3o9LwnZHz+VCbVB8rTsRTFCjtOYv/BatcmLOWp21NedTrErVGinfxe6XYtA==", - "requires": { - "@sinonjs/formatio": "^2.0.0", - "just-extend": "^1.1.27", - "lolex": "^2.3.2", - "path-to-regexp": "^1.7.0", - "text-encoding": "^0.6.4" - }, - "dependencies": { - "lolex": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/lolex/-/lolex-2.3.2.tgz", - "integrity": "sha512-A5pN2tkFj7H0dGIAM6MFvHKMJcPnjZsOMvR7ujCjfgW5TbV6H9vb1PgxLtHvjqNZTHsUolz+6/WEO0N1xNx2ng==" - } - } - }, - "node-dir": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/node-dir/-/node-dir-0.1.8.tgz", - "integrity": "sha1-VfuN62mQcHB/tn+RpGDwRIKUx30=" - }, - "node-libs-browser": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.1.0.tgz", - "integrity": "sha512-5AzFzdoIMb89hBGMZglEegffzgRg+ZFoUmisQ8HI4j1KDdpx13J0taNp2y9xPbur6W61gepGDDotGBVQ7mfUCg==", - "requires": { - "assert": "^1.1.1", - "browserify-zlib": "^0.2.0", - "buffer": "^4.3.0", - "console-browserify": "^1.1.0", - "constants-browserify": "^1.0.0", - "crypto-browserify": "^3.11.0", - "domain-browser": "^1.1.1", - "events": "^1.0.0", - "https-browserify": "^1.0.0", - "os-browserify": "^0.3.0", - "path-browserify": "0.0.0", - "process": "^0.11.10", - "punycode": "^1.2.4", - "querystring-es3": "^0.2.0", - "readable-stream": "^2.3.3", - "stream-browserify": "^2.0.1", - "stream-http": "^2.7.2", - "string_decoder": "^1.0.0", - "timers-browserify": "^2.0.4", - "tty-browserify": "0.0.0", - "url": "^0.11.0", - "util": "^0.10.3", - "vm-browserify": "0.0.4" - } - }, - "nomnom": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/nomnom/-/nomnom-1.8.1.tgz", - "integrity": "sha1-IVH3Ikcrp55Qp2/BJbuMjy5Nwqc=", - "requires": { - "chalk": "~0.4.0", - "underscore": "~1.6.0" - }, - "dependencies": { - "ansi-styles": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-1.0.0.tgz", - "integrity": "sha1-yxAt8cVvUSPquLZ817mAJ6AnkXg=" - }, - "chalk": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-0.4.0.tgz", - "integrity": "sha1-UZmj3c0MHv4jvAjBsCewYXbgxk8=", - "requires": { - "ansi-styles": "~1.0.0", - "has-color": "~0.1.0", - "strip-ansi": "~0.1.0" - } - }, - "strip-ansi": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.1.1.tgz", - "integrity": "sha1-OeipjQRNFQZgq+SmgIrPcLt7yZE=" - }, - "underscore": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz", - "integrity": "sha1-izixDKze9jM3uLJOT/htRa6lKag=" - } - } - }, - "normalize-package-data": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", - "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", - "requires": { - "hosted-git-info": "^2.1.4", - "is-builtin-module": "^1.0.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", - "requires": { - "remove-trailing-separator": "^1.0.1" - } - }, - "npm-run-path": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", - "requires": { - "path-key": "^2.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" - }, - "oauth-sign": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", - "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=" - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" - }, - "object-copy": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", - "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", - "requires": { - "copy-descriptor": "^0.1.0", - "define-property": "^0.2.5", - "kind-of": "^3.0.3" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "requires": { - "kind-of": "^3.0.2" - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "requires": { - "kind-of": "^3.0.2" - } - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "dependencies": { - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" - } - } - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "object-visit": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", - "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", - "requires": { - "isobject": "^3.0.0" - } - }, - "object.omit": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz", - "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=", - "requires": { - "for-own": "^0.1.4", - "is-extendable": "^0.1.1" - } - }, - "object.pick": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", - "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", - "requires": { - "isobject": "^3.0.1" - } - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "requires": { - "wrappy": "1" - } - }, - "onetime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", - "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", - "requires": { - "mimic-fn": "^1.0.0" - } - }, - "ora": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/ora/-/ora-0.2.3.tgz", - "integrity": "sha1-N1J9Igrc1Tw5tzVx11QVbV22V6Q=", - "requires": { - "chalk": "^1.1.1", - "cli-cursor": "^1.0.2", - "cli-spinners": "^0.1.2", - "object-assign": "^4.0.1" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" - }, - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "cli-cursor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz", - "integrity": "sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc=", - "requires": { - "restore-cursor": "^1.0.1" - } - }, - "onetime": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz", - "integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=" - }, - "restore-cursor": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz", - "integrity": "sha1-NGYfRohjJ/7SmRR5FSJS35LapUE=", - "requires": { - "exit-hook": "^1.0.0", - "onetime": "^1.0.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" - } - } - }, - "os-browserify": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", - "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=" - }, - "os-homedir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" - }, - "os-locale": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz", - "integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==", - "requires": { - "execa": "^0.7.0", - "lcid": "^1.0.0", - "mem": "^1.1.0" - } - }, - "os-shim": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/os-shim/-/os-shim-0.1.3.tgz", - "integrity": "sha1-a2LDeRz3kJ6jXtRuF2WLtBfLORc=" - }, - "os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" - }, - "p-cancelable": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-0.3.0.tgz", - "integrity": "sha512-RVbZPLso8+jFeq1MfNvgXtCRED2raz/dKpacfTNxsx6pLEpEomM7gah6VeHSYV3+vo0OAi4MkArtQcWWXuQoyw==" - }, - "p-each-series": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-1.0.0.tgz", - "integrity": "sha1-kw89Et0fUOdDRFeiLNbwSsatf3E=", - "requires": { - "p-reduce": "^1.0.0" - } - }, - "p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=" - }, - "p-lazy": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-lazy/-/p-lazy-1.0.0.tgz", - "integrity": "sha1-7FPIAvLuOsKPFmzILQsrAt4nqDU=" - }, - "p-limit": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.2.0.tgz", - "integrity": "sha512-Y/OtIaXtUPr4/YpMv1pCL5L5ed0rumAaAeBSj12F+bSlMdys7i8oQF/GUJmfpTS/QoaRrS/k6pma29haJpsMng==", - "requires": { - "p-try": "^1.0.0" - } - }, - "p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", - "requires": { - "p-limit": "^1.1.0" - } - }, - "p-map": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-1.2.0.tgz", - "integrity": "sha512-r6zKACMNhjPJMTl8KcFH4li//gkrXWfbD6feV8l6doRHlzljFWGJ2AP6iKaCJXyZmAUMOPtvbW7EXkbWO/pLEA==" - }, - "p-reduce": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-reduce/-/p-reduce-1.0.0.tgz", - "integrity": "sha1-GMKw3ZNqRpClKfgjH1ig/bakffo=" - }, - "p-timeout": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-1.2.1.tgz", - "integrity": "sha1-XrOzU7f86Z8QGhA4iAuwVOu+o4Y=", - "requires": { - "p-finally": "^1.0.0" - } - }, - "p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=" - }, - "pako": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.6.tgz", - "integrity": "sha512-lQe48YPsMJAig+yngZ87Lus+NF+3mtu7DVOBu6b/gHO1YpKwIj5AWjZ/TOS7i46HD/UixzWb1zeWDZfGZ3iYcg==" - }, - "parallel-transform": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.1.0.tgz", - "integrity": "sha1-1BDwZbBdojCB/NEPKIVMKb2jOwY=", - "requires": { - "cyclist": "~0.2.2", - "inherits": "^2.0.3", - "readable-stream": "^2.1.5" - } - }, - "parse-asn1": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.0.tgz", - "integrity": "sha1-N8T5t+06tlx0gXtfJICTf7+XxxI=", - "requires": { - "asn1.js": "^4.0.0", - "browserify-aes": "^1.0.0", - "create-hash": "^1.1.0", - "evp_bytestokey": "^1.0.0", - "pbkdf2": "^3.0.3" - } - }, - "parse-glob": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", - "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=", - "requires": { - "glob-base": "^0.3.0", - "is-dotfile": "^1.0.0", - "is-extglob": "^1.0.0", - "is-glob": "^2.0.0" - }, - "dependencies": { - "is-extglob": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", - "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=" - }, - "is-glob": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", - "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", - "requires": { - "is-extglob": "^1.0.0" - } - } - } - }, - "parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", - "requires": { - "error-ex": "^1.2.0" - } - }, - "parse-passwd": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", - "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=" - }, - "pascalcase": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", - "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=" - }, - "path-browserify": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.0.tgz", - "integrity": "sha1-oLhwcpquIUAFt9UDLsLLuw+0RRo=" - }, - "path-dirname": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", - "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=" - }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" - }, - "path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=" - }, - "path-parse": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz", - "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=" - }, - "path-to-regexp": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.7.0.tgz", - "integrity": "sha1-Wf3g9DW62suhA6hOnTvGTpa5k30=", - "requires": { - "isarray": "0.0.1" - }, - "dependencies": { - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" - } - } - }, - "path-type": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", - "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", - "requires": { - "pify": "^2.0.0" - }, - "dependencies": { - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" - } - } - }, - "pbkdf2": { - "version": "3.0.14", - "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.14.tgz", - "integrity": "sha512-gjsZW9O34fm0R7PaLHRJmLLVfSoesxztjPjE9o6R+qtVJij90ltg1joIovN9GKrRW3t1PzhDDG3UMEMFfZ+1wA==", - "requires": { - "create-hash": "^1.1.2", - "create-hmac": "^1.1.4", - "ripemd160": "^2.0.1", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" - } - }, - "performance-now": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-0.2.0.tgz", - "integrity": "sha1-M+8wxcd9TqIcWlOGnZG1bY8lVeU=" - }, - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" - }, - "pinkie": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=" - }, - "pinkie-promise": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", - "requires": { - "pinkie": "^2.0.0" - } - }, - "pkg-dir": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", - "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", - "requires": { - "find-up": "^2.1.0" - } - }, - "posix-character-classes": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", - "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=" - }, - "prepend-http": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", - "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=" - }, - "preserve": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", - "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=" - }, - "prettier": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.11.1.tgz", - "integrity": "sha512-T/KD65Ot0PB97xTrG8afQ46x3oiVhnfGjGESSI9NWYcG92+OUPZKkwHqGWXH2t9jK1crnQjubECW0FuOth+hxw==" - }, - "pretty-bytes": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-4.0.2.tgz", - "integrity": "sha1-sr+C5zUNZcbDOqlaqlpPYyf2HNk=" - }, - "private": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", - "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==" - }, - "process": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", - "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=" - }, - "process-nextick-args": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", - "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" - }, - "promise-inflight": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", - "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=" - }, - "promises-aplus-tests": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/promises-aplus-tests/-/promises-aplus-tests-2.1.2.tgz", - "integrity": "sha1-drfFY4locghhlpz7zYeVr9J0iFw=", - "requires": { - "mocha": "^2.5.3", - "sinon": "^1.10.3", - "underscore": "~1.8.3" - } - }, - "prr": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", - "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=" - }, - "pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" - }, - "public-encrypt": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.0.tgz", - "integrity": "sha1-OfaZ86RlYN1eusvKaTyvfGXBjMY=", - "requires": { - "bn.js": "^4.1.0", - "browserify-rsa": "^4.0.0", - "create-hash": "^1.1.0", - "parse-asn1": "^5.0.0", - "randombytes": "^2.0.1" - } - }, - "pump": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", - "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "pumpify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.4.0.tgz", - "integrity": "sha512-2kmNR9ry+Pf45opRVirpNuIFotsxUGLaYqxIwuR77AYrYRMuFCz9eryHBS52L360O+NcR383CL4QYlMKPq4zYA==", - "requires": { - "duplexify": "^3.5.3", - "inherits": "^2.0.3", - "pump": "^2.0.0" - } - }, - "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" - }, - "qs": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.4.0.tgz", - "integrity": "sha1-E+JtKK1rD/qpExLNO/cI7TUecjM=" - }, - "querystring": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", - "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=" - }, - "querystring-es3": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", - "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=" - }, - "randomatic": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-1.1.7.tgz", - "integrity": "sha512-D5JUjPyJbaJDkuAazpVnSfVkLlpeO3wDlPROTMLGKG1zMFNFRgrciKo1ltz/AzNTkqE0HzDx655QOL51N06how==", - "requires": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" - }, - "dependencies": { - "kind-of": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "randombytes": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.0.6.tgz", - "integrity": "sha512-CIQ5OFxf4Jou6uOKe9t1AOgqpeU5fd70A8NPdHSGeYXqXsPe6peOwI0cUl88RWZ6sP1vPMV3avd/R6cZ5/sP1A==", - "requires": { - "safe-buffer": "^5.1.0" - } - }, - "randomfill": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", - "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", - "requires": { - "randombytes": "^2.0.5", - "safe-buffer": "^5.1.0" - } - }, - "read-chunk": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/read-chunk/-/read-chunk-2.1.0.tgz", - "integrity": "sha1-agTAkoAF7Z1C4aasVgDhnLx/9lU=", - "requires": { - "pify": "^3.0.0", - "safe-buffer": "^5.1.1" - } - }, - "read-pkg": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", - "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", - "requires": { - "load-json-file": "^2.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^2.0.0" - } - }, - "read-pkg-up": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", - "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", - "requires": { - "find-up": "^2.0.0", - "read-pkg": "^2.0.0" - } - }, - "readable-stream": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.4.tgz", - "integrity": "sha512-vuYxeWYM+fde14+rajzqgeohAI7YoJcHE7kXDAc4Nk0EbuKnJfqtY9YtRkLo/tqkuF7MsBQRhPnPeyjYITp3ZQ==", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.0.3", - "util-deprecate": "~1.0.1" - } - }, - "readdirp": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.1.0.tgz", - "integrity": "sha1-TtCtBg3zBzMAxIRANz9y0cxkLXg=", - "requires": { - "graceful-fs": "^4.1.2", - "minimatch": "^3.0.2", - "readable-stream": "^2.0.2", - "set-immediate-shim": "^1.0.1" - }, - "dependencies": { - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "requires": { - "brace-expansion": "^1.1.7" - } - } - } - }, - "recast": { - "version": "0.13.2", - "resolved": "https://registry.npmjs.org/recast/-/recast-0.13.2.tgz", - "integrity": "sha512-Xqo0mKljGUWGUhnkdbODk7oJGFrMcpgKQ9cCyZ4y+G9VfoTKdum8nHbf/SxIdKx5aBSZ29VpVy20bTyt7jyC8w==", - "requires": { - "ast-types": "0.10.2", - "esprima": "~4.0.0", - "private": "~0.1.5", - "source-map": "~0.6.1" - }, - "dependencies": { - "ast-types": { - "version": "0.10.2", - "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.10.2.tgz", - "integrity": "sha512-ufWX953VU1eIuWqxS0nRDMYlGyFH+yxln5CsmIHlpzEt3fdYqUnRtsFt0XAsQot8OaVCwFqxT1RiwvtzYjeYeg==" - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "rechoir": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", - "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", - "requires": { - "resolve": "^1.1.6" - } - }, - "regenerate": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.3.3.tgz", - "integrity": "sha512-jVpo1GadrDAK59t/0jRx5VxYWQEDkkEKi6+HjE3joFVLfDOh9Xrdh0dF1eSq+BI/SwvTQ44gSscJ8N5zYL61sg==" - }, - "regenerator-runtime": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", - "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" - }, - "regenerator-transform": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.10.1.tgz", - "integrity": "sha512-PJepbvDbuK1xgIgnau7Y90cwaAmO/LCLMI2mPvaXq2heGMR3aWW5/BQvYrhJ8jgmQjXewXvBjzfqKcVOmhjZ6Q==", - "requires": { - "babel-runtime": "^6.18.0", - "babel-types": "^6.19.0", - "private": "^0.1.6" - } - }, - "regex-cache": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz", - "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==", - "requires": { - "is-equal-shallow": "^0.1.3" - } - }, - "regex-not": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", - "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", - "requires": { - "extend-shallow": "^3.0.2", - "safe-regex": "^1.1.0" - } - }, - "regexpu-core": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-2.0.0.tgz", - "integrity": "sha1-SdA4g3uNz4v6W5pCE5k45uoq4kA=", - "requires": { - "regenerate": "^1.2.1", - "regjsgen": "^0.2.0", - "regjsparser": "^0.1.4" - } - }, - "regjsgen": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz", - "integrity": "sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc=" - }, - "regjsparser": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz", - "integrity": "sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw=", - "requires": { - "jsesc": "~0.5.0" - } - }, - "remove-trailing-separator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", - "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=" - }, - "repeat-element": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz", - "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=" - }, - "repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=" - }, - "repeating": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", - "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", - "requires": { - "is-finite": "^1.0.0" - } - }, - "replace-ext": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.0.tgz", - "integrity": "sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs=" - }, - "request": { - "version": "2.81.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.81.0.tgz", - "integrity": "sha1-xpKJRqDgbF+Nb4qTM0af/aRimKA=", - "requires": { - "aws-sign2": "~0.6.0", - "aws4": "^1.2.1", - "caseless": "~0.12.0", - "combined-stream": "~1.0.5", - "extend": "~3.0.0", - "forever-agent": "~0.6.1", - "form-data": "~2.1.1", - "har-validator": "~4.2.1", - "hawk": "~3.1.3", - "http-signature": "~1.1.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.7", - "oauth-sign": "~0.8.1", - "performance-now": "^0.2.0", - "qs": "~6.4.0", - "safe-buffer": "^5.0.1", - "stringstream": "~0.0.4", - "tough-cookie": "~2.3.0", - "tunnel-agent": "^0.6.0", - "uuid": "^3.0.0" - } - }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" - }, - "require-main-filename": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", - "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=" - }, - "resolve": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.5.0.tgz", - "integrity": "sha512-hgoSGrc3pjzAPHNBg+KnFcK2HwlHTs/YrAGUr6qgTVUZmXv1UEXXl0bZNBKMA9fud6lRYFdPGz0xXxycPzmmiw==", - "requires": { - "path-parse": "^1.0.5" - } - }, - "resolve-cwd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz", - "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=", - "requires": { - "resolve-from": "^3.0.0" - } - }, - "resolve-dir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", - "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=", - "requires": { - "expand-tilde": "^2.0.0", - "global-modules": "^1.0.0" - } - }, - "resolve-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", - "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=" - }, - "resolve-url": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=" - }, - "restore-cursor": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", - "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", - "requires": { - "onetime": "^2.0.0", - "signal-exit": "^3.0.2" - } - }, - "ret": { - "version": "0.1.15", - "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==" - }, - "rimraf": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", - "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", - "requires": { - "glob": "^7.0.5" - }, - "dependencies": { - "glob": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", - "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" - } - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "requires": { - "brace-expansion": "^1.1.7" - } - } - } - }, - "ripemd160": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.1.tgz", - "integrity": "sha1-D0WEKVxTo2KK9+bXmsohzlfRxuc=", - "requires": { - "hash-base": "^2.0.0", - "inherits": "^2.0.1" - } - }, - "run-async": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", - "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", - "requires": { - "is-promise": "^2.1.0" - } - }, - "run-queue": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz", - "integrity": "sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=", - "requires": { - "aproba": "^1.1.1" - } - }, - "rx": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/rx/-/rx-4.1.0.tgz", - "integrity": "sha1-pfE/957zt0D+MKqAP7CfmIBdR4I=" - }, - "rx-lite": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-4.0.8.tgz", - "integrity": "sha1-Cx4Rr4vESDbwSmQH6S2kJGe3lEQ=" - }, - "rx-lite-aggregates": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz", - "integrity": "sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74=", - "requires": { - "rx-lite": "*" - } - }, - "rxjs": { - "version": "5.5.6", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.5.6.tgz", - "integrity": "sha512-v4Q5HDC0FHAQ7zcBX7T2IL6O5ltl1a2GX4ENjPXg6SjDY69Cmx9v4113C99a4wGF16ClPv5Z8mghuYorVkg/kg==", - "requires": { - "symbol-observable": "1.0.1" - } - }, - "safe-buffer": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", - "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" - }, - "safe-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", - "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", - "requires": { - "ret": "~0.1.10" - } - }, - "schema-utils": { - "version": "0.4.5", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.4.5.tgz", - "integrity": "sha512-yYrjb9TX2k/J1Y5UNy3KYdZq10xhYcF8nMpAW6o3hy6Q8WSIEf9lJHG/ePnOBfziPM3fvQwfOwa13U/Fh8qTfA==", - "requires": { - "ajv": "^6.1.0", - "ajv-keywords": "^3.1.0" - } - }, - "scoped-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/scoped-regex/-/scoped-regex-1.0.0.tgz", - "integrity": "sha1-o0a7Gs1CB65wvXwMfKnlZra63bg=" - }, - "semver": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", - "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==" - }, - "serialize-javascript": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-1.4.0.tgz", - "integrity": "sha1-fJWFFNtqwkQ6irwGLcn3iGp/YAU=" - }, - "set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" - }, - "set-getter": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/set-getter/-/set-getter-0.1.0.tgz", - "integrity": "sha1-12nBgsnVpR9AkUXy+6guXoboA3Y=", - "requires": { - "to-object-path": "^0.3.0" - } - }, - "set-immediate-shim": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz", - "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=" - }, - "set-value": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz", - "integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==", - "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.3", - "split-string": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=" - }, - "sha.js": { - "version": "2.4.10", - "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.10.tgz", - "integrity": "sha512-vnwmrFDlOExK4Nm16J2KMWHLrp14lBrjxMxBJpu++EnsuBmpiYaM/MEs46Vxxm/4FvdP5yTwuCTO9it5FSjrqA==", - "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", - "requires": { - "shebang-regex": "^1.0.0" - } - }, - "shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=" - }, - "shelljs": { - "version": "0.7.8", - "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.7.8.tgz", - "integrity": "sha1-3svPh0sNHl+3LhSxZKloMEjprLM=", - "requires": { - "glob": "^7.0.0", - "interpret": "^1.0.0", - "rechoir": "^0.6.2" - }, - "dependencies": { - "glob": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", - "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" - } - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "requires": { - "brace-expansion": "^1.1.7" - } - } - } - }, - "signal-exit": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" - }, - "sinon": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-4.4.2.tgz", - "integrity": "sha512-cpOHpnRyY3Dk9dTHBYMfVBB0HUCSKIpxW07X6OGW2NiYPovs4AkcL8Q8MzecbAROjbfRA9esJCmlZgikxDz7DA==", - "requires": { - "@sinonjs/formatio": "^2.0.0", - "diff": "^3.1.0", - "lodash.get": "^4.4.2", - "lolex": "^2.2.0", - "nise": "^1.2.0", - "supports-color": "^5.1.0", - "type-detect": "^4.0.5" - }, - "dependencies": { - "lolex": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/lolex/-/lolex-2.3.2.tgz", - "integrity": "sha512-A5pN2tkFj7H0dGIAM6MFvHKMJcPnjZsOMvR7ujCjfgW5TbV6H9vb1PgxLtHvjqNZTHsUolz+6/WEO0N1xNx2ng==" - } - } - }, - "slash": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", - "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=" - }, - "slice-ansi": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz", - "integrity": "sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU=" - }, - "slide": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz", - "integrity": "sha1-VusCfWW00tzmyy4tMsTUr8nh1wc=" - }, - "snapdragon": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.1.tgz", - "integrity": "sha1-4StUh/re0+PeoKyR6UAL91tAE3A=", - "requires": { - "base": "^0.11.1", - "debug": "^2.2.0", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "map-cache": "^0.2.2", - "source-map": "^0.5.6", - "source-map-resolve": "^0.5.0", - "use": "^2.0.0" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - } - }, - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" - } - } - }, - "snapdragon-node": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", - "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", - "requires": { - "define-property": "^1.0.0", - "isobject": "^3.0.0", - "snapdragon-util": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "requires": { - "is-descriptor": "^1.0.0" - } - } - } - }, - "snapdragon-util": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", - "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", - "requires": { - "kind-of": "^3.2.0" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "sntp": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz", - "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=", - "requires": { - "hoek": "2.x.x" - } - }, - "source-list-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.0.tgz", - "integrity": "sha512-I2UmuJSRr/T8jisiROLU3A3ltr+swpniSmNPI4Ml3ZCX6tVnDsuZzK7F2hl5jTqbZBWCEKlj5HRQiPExXLgE8A==" - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" - }, - "source-map-resolve": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.1.tgz", - "integrity": "sha512-0KW2wvzfxm8NCTb30z0LMNyPqWCdDGE2viwzUaucqJdkTRXtZiSY3I+2A6nVAjmdOy0I4gU8DwnVVGsk9jvP2A==", - "requires": { - "atob": "^2.0.0", - "decode-uri-component": "^0.2.0", - "resolve-url": "^0.2.1", - "source-map-url": "^0.4.0", - "urix": "^0.1.0" - } - }, - "source-map-support": { - "version": "0.4.18", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", - "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", - "requires": { - "source-map": "^0.5.6" - } - }, - "source-map-url": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", - "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=" - }, - "spawn-sync": { - "version": "1.0.15", - "resolved": "https://registry.npmjs.org/spawn-sync/-/spawn-sync-1.0.15.tgz", - "integrity": "sha1-sAeZVX63+wyDdsKdROih6mfldHY=", - "requires": { - "concat-stream": "^1.4.7", - "os-shim": "^0.1.2" - } - }, - "spdx-correct": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.0.tgz", - "integrity": "sha512-N19o9z5cEyc8yQQPukRCZ9EUmb4HUpnrmaL/fxS2pBo2jbfcFRVuFZ/oFC+vZz0MNNk0h80iMn5/S6qGZOL5+g==", - "requires": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-exceptions": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz", - "integrity": "sha512-4K1NsmrlCU1JJgUrtgEeTVyfx8VaYea9J9LvARxhbHtVtohPs/gFGG5yy49beySjlIMhhXZ4QqujIZEfS4l6Cg==" - }, - "spdx-expression-parse": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", - "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", - "requires": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-license-ids": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz", - "integrity": "sha512-2+EPwgbnmOIl8HjGBXXMd9NAu02vLjOO1nWw4kmeRDFyHn+M/ETfHxQUK0oXg8ctgVnl9t3rosNVsZ1jG61nDA==" - }, - "split-string": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", - "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", - "requires": { - "extend-shallow": "^3.0.0" - } - }, - "sshpk": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.1.tgz", - "integrity": "sha1-US322mKHFEMW3EwY/hzx2UBzm+M=", - "requires": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "tweetnacl": "~0.14.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" - } - } - }, - "ssri": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-5.2.4.tgz", - "integrity": "sha512-UnEAgMZa15973iH7cUi0AHjJn1ACDIkaMyZILoqwN6yzt+4P81I8tBc5Hl+qwi5auMplZtPQsHrPBR5vJLcQtQ==", - "requires": { - "safe-buffer": "^5.1.1" - } - }, - "static-extend": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", - "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", - "requires": { - "define-property": "^0.2.5", - "object-copy": "^0.1.0" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - } - }, - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" - } - } - }, - "stream-browserify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.1.tgz", - "integrity": "sha1-ZiZu5fm9uZQKTkUUyvtDu3Hlyds=", - "requires": { - "inherits": "~2.0.1", - "readable-stream": "^2.0.2" - } - }, - "stream-each": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.2.tgz", - "integrity": "sha512-mc1dbFhGBxvTM3bIWmAAINbqiuAk9TATcfIQC8P+/+HJefgaiTlMn2dHvkX8qlI12KeYKSQ1Ua9RrIqrn1VPoA==", - "requires": { - "end-of-stream": "^1.1.0", - "stream-shift": "^1.0.0" - } - }, - "stream-http": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.0.tgz", - "integrity": "sha512-sZOFxI/5xw058XIRHl4dU3dZ+TTOIGJR78Dvo0oEAejIt4ou27k+3ne1zYmCV+v7UucbxIFQuOgnkTVHh8YPnw==", - "requires": { - "builtin-status-codes": "^3.0.0", - "inherits": "^2.0.1", - "readable-stream": "^2.3.3", - "to-arraybuffer": "^1.0.0", - "xtend": "^4.0.0" - } - }, - "stream-shift": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz", - "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=" - }, - "stream-to-observable": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/stream-to-observable/-/stream-to-observable-0.1.0.tgz", - "integrity": "sha1-Rb8dny19wJvtgfHDB8Qw5ouEz/4=" - }, - "string-template": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/string-template/-/string-template-0.2.1.tgz", - "integrity": "sha1-QpMuWYo1LQH8IuwzZ9nYTuxsmt0=" - }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - } - }, - "string_decoder": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", - "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", - "requires": { - "safe-buffer": "~5.1.0" - } - }, - "stringstream": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", - "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=" - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "requires": { - "ansi-regex": "^3.0.0" - } - }, - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=" - }, - "strip-bom-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-bom-stream/-/strip-bom-stream-2.0.0.tgz", - "integrity": "sha1-+H217yYT9paKpUWr/h7HKLaoKco=", - "requires": { - "first-chunk-stream": "^2.0.0", - "strip-bom": "^2.0.0" - }, - "dependencies": { - "strip-bom": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", - "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", - "requires": { - "is-utf8": "^0.2.0" - } - } - } - }, - "strip-eof": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", - "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=" - }, - "supports-color": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.2.0.tgz", - "integrity": "sha512-F39vS48la4YvTZUPVeTqsjsFNrvcMwrV3RLZINsmHo+7djCvuUzSIeXOnZ5hmjef4bajL1dNccN+tg5XAliO5Q==", - "requires": { - "has-flag": "^3.0.0" - } - }, - "symbol-observable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.0.1.tgz", - "integrity": "sha1-g0D8RwLDEi310iKI+IKD9RPT/dQ=" - }, - "tapable": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.0.0.tgz", - "integrity": "sha512-dQRhbNQkRnaqauC7WqSJ21EEksgT0fYZX2lqXzGkpo8JNig9zGZTYoMGvyI2nWmXlE2VSVXVDu7wLVGu/mQEsg==" - }, - "temp": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/temp/-/temp-0.8.3.tgz", - "integrity": "sha1-4Ma8TSa5AxJEEOT+2BEDAU38H1k=", - "requires": { - "os-tmpdir": "^1.0.0", - "rimraf": "~2.2.6" - }, - "dependencies": { - "rimraf": { - "version": "2.2.8", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz", - "integrity": "sha1-5Dm+Kq7jJzIZUnMPmaiSnk/FBYI=" - } - } - }, - "text-encoding": { - "version": "0.6.4", - "resolved": "https://registry.npmjs.org/text-encoding/-/text-encoding-0.6.4.tgz", - "integrity": "sha1-45mpgiV6J22uQou5KEXLcb3CbRk=" - }, - "text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=" - }, - "textextensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/textextensions/-/textextensions-2.2.0.tgz", - "integrity": "sha512-j5EMxnryTvKxwH2Cq+Pb43tsf6sdEgw6Pdwxk83mPaq0ToeFJt6WE4J3s5BqY7vmjlLgkgXvhtXUxo80FyBhCA==" - }, - "through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" - }, - "through2": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz", - "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=", - "requires": { - "readable-stream": "^2.1.5", - "xtend": "~4.0.1" - } - }, - "timed-out": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", - "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=" - }, - "timers-browserify": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.6.tgz", - "integrity": "sha512-HQ3nbYRAowdVd0ckGFvmJPPCOH/CHleFN/Y0YQCX1DVaB7t+KFvisuyN09fuP8Jtp1CpfSh8O8bMkHbdbPe6Pw==", - "requires": { - "setimmediate": "^1.0.4" - } - }, - "tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "requires": { - "os-tmpdir": "~1.0.2" - } - }, - "to-arraybuffer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", - "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=" - }, - "to-fast-properties": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", - "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=" - }, - "to-object-path": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", - "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "to-regex": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", - "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", - "requires": { - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "regex-not": "^1.0.2", - "safe-regex": "^1.1.0" - } - }, - "to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", - "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" - } - }, - "tough-cookie": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz", - "integrity": "sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA==", - "requires": { - "punycode": "^1.4.1" - } - }, - "trim-right": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", - "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=" - }, - "tty-browserify": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", - "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=" - }, - "tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", - "optional": true - }, - "type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==" - }, - "typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" - }, - "uglify-es": { - "version": "3.3.9", - "resolved": "https://registry.npmjs.org/uglify-es/-/uglify-es-3.3.9.tgz", - "integrity": "sha512-r+MU0rfv4L/0eeW3xZrd16t4NZfK8Ld4SWVglYBb7ez5uXFWHuVRs6xCTrf1yirs9a4j4Y27nn7SRfO6v67XsQ==", - "requires": { - "commander": "~2.13.0", - "source-map": "~0.6.1" - }, - "dependencies": { - "commander": { - "version": "2.13.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.13.0.tgz", - "integrity": "sha512-MVuS359B+YzaWqjCL/c+22gfryv+mCBPHAv3zyVI2GN8EY6IRP8VwtasXn8jyyhvvq84R4ImN1OKRtcbIasjYA==" - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "uglifyjs-webpack-plugin": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-1.2.2.tgz", - "integrity": "sha512-CG/NvzXfemUAm5Y4Guh5eEaJYHtkG7kKNpXEJHp9QpxsFVB5/qKvYWoMaq4sa99ccZ0hM3MK8vQV9XPZB4357A==", - "requires": { - "cacache": "^10.0.1", - "find-cache-dir": "^1.0.0", - "schema-utils": "^0.4.2", - "serialize-javascript": "^1.4.0", - "source-map": "^0.6.1", - "uglify-es": "^3.3.4", - "webpack-sources": "^1.1.0", - "worker-farm": "^1.5.2" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "underscore": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz", - "integrity": "sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI=" - }, - "union-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz", - "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=", - "requires": { - "arr-union": "^3.1.0", - "get-value": "^2.0.6", - "is-extendable": "^0.1.1", - "set-value": "^0.4.3" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - }, - "set-value": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz", - "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=", - "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.1", - "to-object-path": "^0.3.0" - } - } - } - }, - "unique-filename": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.0.tgz", - "integrity": "sha1-0F8v5AMlYIcfMOk8vnNe6iAVFPM=", - "requires": { - "unique-slug": "^2.0.0" - } - }, - "unique-slug": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.0.tgz", - "integrity": "sha1-22Z258fMBimHj/GWCXx4hVrp9Ks=", - "requires": { - "imurmurhash": "^0.1.4" - } - }, - "unset-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", - "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", - "requires": { - "has-value": "^0.3.1", - "isobject": "^3.0.0" - }, - "dependencies": { - "has-value": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", - "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", - "requires": { - "get-value": "^2.0.3", - "has-values": "^0.1.4", - "isobject": "^2.0.0" - }, - "dependencies": { - "isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "requires": { - "isarray": "1.0.0" - } - } - } - }, - "has-values": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", - "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=" - } - } - }, - "untildify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/untildify/-/untildify-2.1.0.tgz", - "integrity": "sha1-F+soB5h/dpUunASF/DEdBqgmouA=", - "requires": { - "os-homedir": "^1.0.0" - } - }, - "upath": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/upath/-/upath-1.0.4.tgz", - "integrity": "sha512-d4SJySNBXDaQp+DPrziv3xGS6w3d2Xt69FijJr86zMPBy23JEloMCEOUBBzuN7xCtjLCnmB9tI/z7SBCahHBOw==" - }, - "urix": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", - "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=" - }, - "url": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", - "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", - "requires": { - "punycode": "1.3.2", - "querystring": "0.2.0" - }, - "dependencies": { - "punycode": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", - "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=" - } - } - }, - "url-parse-lax": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz", - "integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=", - "requires": { - "prepend-http": "^1.0.1" - } - }, - "url-to-options": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/url-to-options/-/url-to-options-1.0.1.tgz", - "integrity": "sha1-FQWgOiiaSMvXpDTvuu7FBV9WM6k=" - }, - "urlgrey": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/urlgrey/-/urlgrey-0.4.4.tgz", - "integrity": "sha1-iS/pWWCAXoVRnxzUOJ8stMu3ZS8=" - }, - "use": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/use/-/use-2.0.2.tgz", - "integrity": "sha1-riig1y+TvyJCKhii43mZMRLeyOg=", - "requires": { - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "lazy-cache": "^2.0.2" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - } - }, - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" - } - } - }, - "util": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", - "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", - "requires": { - "inherits": "2.0.1" - }, - "dependencies": { - "inherits": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", - "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=" - } - } - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" - }, - "uuid": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.2.1.tgz", - "integrity": "sha512-jZnMwlb9Iku/O3smGWvZhauCf6cvvpKi4BKRiliS3cxnI+Gz9j5MEpTz2UFuXiKPJocb7gnsLHwiS05ige5BEA==" - }, - "v8-compile-cache": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-1.1.2.tgz", - "integrity": "sha512-ejdrifsIydN1XDH7EuR2hn8ZrkRKUYF7tUcBjBy/lhrCvs2K+zRlbW9UHc0IQ9RsYFZJFqJrieoIHfkCa0DBRA==" - }, - "validate-npm-package-license": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.3.tgz", - "integrity": "sha512-63ZOUnL4SIXj4L0NixR3L1lcjO38crAbgrTpl28t8jjrfuiOBL5Iygm+60qPs/KsZGzPNg6Smnc/oY16QTjF0g==", - "requires": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", - "requires": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" - } - } - }, - "vinyl": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.1.0.tgz", - "integrity": "sha1-Ah+cLPlR1rk5lDyJ617lrdT9kkw=", - "requires": { - "clone": "^2.1.1", - "clone-buffer": "^1.0.0", - "clone-stats": "^1.0.0", - "cloneable-readable": "^1.0.0", - "remove-trailing-separator": "^1.0.1", - "replace-ext": "^1.0.0" - } - }, - "vinyl-file": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/vinyl-file/-/vinyl-file-2.0.0.tgz", - "integrity": "sha1-p+v1/779obfRjRQPyweyI++2dRo=", - "requires": { - "graceful-fs": "^4.1.2", - "pify": "^2.3.0", - "pinkie-promise": "^2.0.0", - "strip-bom": "^2.0.0", - "strip-bom-stream": "^2.0.0", - "vinyl": "^1.1.0" - }, - "dependencies": { - "clone": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.3.tgz", - "integrity": "sha1-KY1+IjFmD0DAA8LtMUDezz9TCF8=" - }, - "clone-stats": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz", - "integrity": "sha1-uI+UqCzzi4eR1YBG6kAprYjKmdE=" - }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" - }, - "replace-ext": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz", - "integrity": "sha1-KbvZIHinOfC8zitO5B6DeVNSKSQ=" - }, - "strip-bom": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", - "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", - "requires": { - "is-utf8": "^0.2.0" - } - }, - "vinyl": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-1.2.0.tgz", - "integrity": "sha1-XIgDbPVl5d8FVYv8kR+GVt8hiIQ=", - "requires": { - "clone": "^1.0.0", - "clone-stats": "^0.0.1", - "replace-ext": "0.0.1" - } - } - } - }, - "vm-browserify": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-0.0.4.tgz", - "integrity": "sha1-XX6kW7755Kb/ZflUOOCofDV9WnM=", - "requires": { - "indexof": "0.0.1" - } - }, - "watchpack": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.5.0.tgz", - "integrity": "sha512-RSlipNQB1u48cq0wH/BNfCu1tD/cJ8ydFIkNYhp9o+3d+8unClkIovpW5qpFPgmL9OE48wfAnlZydXByWP82AA==", - "requires": { - "chokidar": "^2.0.2", - "graceful-fs": "^4.1.2", - "neo-async": "^2.5.0" - } - }, - "webpack": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.0.1.tgz", - "integrity": "sha512-jHQNMmKPElreOYLCxR7SHfPnbhcqRT9O7lYPOMDR6Gt5XueJ7tH7JReXm4uMFstBKf7rj2Y7AD3LiMKR2zexYA==", - "requires": { - "acorn": "^5.0.0", - "acorn-dynamic-import": "^3.0.0", - "ajv": "^6.1.0", - "ajv-keywords": "^3.1.0", - "chrome-trace-event": "^0.1.1", - "enhanced-resolve": "^4.0.0", - "eslint-scope": "^3.7.1", - "loader-runner": "^2.3.0", - "loader-utils": "^1.1.0", - "memory-fs": "~0.4.1", - "micromatch": "^3.1.8", - "mkdirp": "~0.5.0", - "neo-async": "^2.5.0", - "node-libs-browser": "^2.0.0", - "schema-utils": "^0.4.2", - "tapable": "^1.0.0", - "uglifyjs-webpack-plugin": "^1.1.1", - "watchpack": "^1.4.0", - "webpack-sources": "^1.0.1" - } - }, - "webpack-addons": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/webpack-addons/-/webpack-addons-1.1.5.tgz", - "integrity": "sha512-MGO0nVniCLFAQz1qv22zM02QPjcpAoJdy7ED0i3Zy7SY1IecgXCm460ib7H/Wq7e9oL5VL6S2BxaObxwIcag0g==", - "requires": { - "jscodeshift": "^0.4.0" - } - }, - "webpack-cli": { - "version": "2.0.9", - "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-2.0.9.tgz", - "integrity": "sha512-KIkOFHhrq8W7ovg5u8M7Xbduzr1aQ1Ch1aGGY0TvL5neO81T6/aCZ/NeG7R92UaXIF/BK4KCkla35wtoOoxyDQ==", - "requires": { - "chalk": "^2.0.1", - "codecov": "^3.0.0", - "cross-spawn": "^5.1.0", - "diff": "^3.3.0", - "enhanced-resolve": "^3.4.1", - "glob-all": "^3.1.0", - "global": "^4.3.2", - "global-modules": "^1.0.0", - "got": "^7.1.0", - "inquirer": "^3.2.0", - "interpret": "^1.0.4", - "jscodeshift": "^0.4.0", - "listr": "^0.12.0", - "loader-utils": "^1.1.0", - "lodash": "^4.17.4", - "log-symbols": "2.1.0", - "mkdirp": "^0.5.1", - "p-each-series": "^1.0.0", - "p-lazy": "^1.0.0", - "prettier": "^1.5.3", - "recast": "^0.13.0", - "resolve-cwd": "^2.0.0", - "supports-color": "^4.4.0", - "uglifyjs-webpack-plugin": "^1.2.2", - "v8-compile-cache": "^1.1.0", - "webpack-addons": "^1.1.5", - "webpack-fork-yeoman-generator": "^1.1.1", - "yargs": "9.0.1", - "yeoman-environment": "^2.0.0" - }, - "dependencies": { - "diff": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-3.4.0.tgz", - "integrity": "sha512-QpVuMTEoJMF7cKzi6bvWhRulU1fZqZnvyVQgNhPaxxuTYwyjn/j1v9falseQ/uXWwPnO56RBfwtg4h/EQXmucA==" - }, - "enhanced-resolve": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-3.4.1.tgz", - "integrity": "sha1-BCHjOf1xQZs9oT0Smzl5BAIwR24=", - "requires": { - "graceful-fs": "^4.1.2", - "memory-fs": "^0.4.0", - "object-assign": "^4.0.1", - "tapable": "^0.2.7" - } - }, - "has-flag": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", - "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=" - }, - "supports-color": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", - "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", - "requires": { - "has-flag": "^2.0.0" - } - }, - "tapable": { - "version": "0.2.8", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-0.2.8.tgz", - "integrity": "sha1-mTcqXJmb8t8WCvwNdL7U9HlIzSI=" - } - } - }, - "webpack-fork-yeoman-generator": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/webpack-fork-yeoman-generator/-/webpack-fork-yeoman-generator-1.1.1.tgz", - "integrity": "sha512-TrLT6Bw6gl9rJA7iZw+YJ+4xHhEUzfOQB3tHpyINBFdZDmO0tlDW9MtMSMZ5rsUNjHxcEba5yuGaAW86J84j/w==", - "requires": { - "async": "^2.0.0", - "chalk": "^1.0.0", - "cli-table": "^0.3.1", - "cross-spawn": "^5.0.1", - "dargs": "^5.1.0", - "dateformat": "^2.0.0", - "debug": "^2.1.0", - "detect-conflict": "^1.0.0", - "error": "^7.0.2", - "find-up": "^2.1.0", - "github-username": "^4.0.0", - "istextorbinary": "^2.1.0", - "lodash": "^4.11.1", - "mem-fs-editor": "^3.0.0", - "minimist": "^1.2.0", - "mkdirp": "^0.5.0", - "pretty-bytes": "^4.0.2", - "read-chunk": "^2.0.0", - "read-pkg-up": "^2.0.0", - "rimraf": "^2.2.0", - "run-async": "^2.0.0", - "shelljs": "^0.7.0", - "text-table": "^0.2.0", - "through2": "^2.0.0", - "yeoman-environment": "^1.1.0" - }, - "dependencies": { - "ansi-escapes": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz", - "integrity": "sha1-06ioOzGapneTZisT52HHkRQiMG4=" - }, - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" - }, - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" - }, - "async": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.0.tgz", - "integrity": "sha512-xAfGg1/NTLBBKlHFmnd7PlmUW9KhVQIUuSrYem9xzFUZy13ScvtyGGejaae9iAVRiRq9+Cx7DPFaAAhCpyxyPw==", - "requires": { - "lodash": "^4.14.0" - } - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "cli-cursor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz", - "integrity": "sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc=", - "requires": { - "restore-cursor": "^1.0.1" - } - }, - "diff": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/diff/-/diff-2.2.3.tgz", - "integrity": "sha1-YOr9DSjukG5Oj/ClLBIpUhAzv5k=" - }, - "external-editor": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-1.1.1.tgz", - "integrity": "sha1-Etew24UPf/fnCBuvQAVwAGDEYAs=", - "requires": { - "extend": "^3.0.0", - "spawn-sync": "^1.0.15", - "tmp": "^0.0.29" - } - }, - "figures": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", - "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", - "requires": { - "escape-string-regexp": "^1.0.5", - "object-assign": "^4.1.0" - }, - "dependencies": { - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" - } - } - }, - "glob": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz", - "integrity": "sha1-DwiGD2oVUSey+t1PnOJLGqtuTSI=", - "requires": { - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "2 || 3", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "globby": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-4.1.0.tgz", - "integrity": "sha1-CA9UVJ7BuCpsYOYx/ILhIR2+lfg=", - "requires": { - "array-union": "^1.0.1", - "arrify": "^1.0.0", - "glob": "^6.0.1", - "object-assign": "^4.0.1", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" - } - }, - "inquirer": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-1.2.3.tgz", - "integrity": "sha1-TexvMvN+97sLLtPx0aXD9UUHSRg=", - "requires": { - "ansi-escapes": "^1.1.0", - "chalk": "^1.0.0", - "cli-cursor": "^1.0.1", - "cli-width": "^2.0.0", - "external-editor": "^1.1.0", - "figures": "^1.3.5", - "lodash": "^4.3.0", - "mute-stream": "0.0.6", - "pinkie-promise": "^2.0.0", - "run-async": "^2.2.0", - "rx": "^4.1.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.0", - "through": "^2.3.6" - } - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "log-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-1.0.2.tgz", - "integrity": "sha1-N2/3tY6jCGoPCfrMdGF+ylAeGhg=", - "requires": { - "chalk": "^1.0.0" - } - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" - }, - "mute-stream": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.6.tgz", - "integrity": "sha1-SJYrGeFp/R38JAs/HnMXYnu8R9s=" - }, - "onetime": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz", - "integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=" - }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" - }, - "restore-cursor": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz", - "integrity": "sha1-NGYfRohjJ/7SmRR5FSJS35LapUE=", - "requires": { - "exit-hook": "^1.0.0", - "onetime": "^1.0.0" - } - }, - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" - }, - "tmp": { - "version": "0.0.29", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.29.tgz", - "integrity": "sha1-8lEl/w3Z2jzLDC3Tce4SiLuRKMA=", - "requires": { - "os-tmpdir": "~1.0.1" - } - }, - "yeoman-environment": { - "version": "1.6.6", - "resolved": "https://registry.npmjs.org/yeoman-environment/-/yeoman-environment-1.6.6.tgz", - "integrity": "sha1-zYX6Z9FWBg5EDXgH1+988NLR1nE=", - "requires": { - "chalk": "^1.0.0", - "debug": "^2.0.0", - "diff": "^2.1.2", - "escape-string-regexp": "^1.0.2", - "globby": "^4.0.0", - "grouped-queue": "^0.3.0", - "inquirer": "^1.0.2", - "lodash": "^4.11.1", - "log-symbols": "^1.0.1", - "mem-fs": "^1.1.0", - "text-table": "^0.2.0", - "untildify": "^2.0.0" - } - } - } - }, - "webpack-sources": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.1.0.tgz", - "integrity": "sha512-aqYp18kPphgoO5c/+NaUvEeACtZjMESmDChuD3NBciVpah3XpMEU9VAAtIaB1BsfJWWTSdv8Vv1m3T0aRk2dUw==", - "requires": { - "source-list-map": "^2.0.0", - "source-map": "~0.6.1" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "which": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.0.tgz", - "integrity": "sha512-xcJpopdamTuY5duC/KnTTNBraPK54YwpenP4lzxU8H91GudWpFv38u0CKjclE1Wi2EH2EDz5LRcHcKbCIzqGyg==", - "requires": { - "isexe": "^2.0.0" - } - }, - "which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" - }, - "worker-farm": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.5.4.tgz", - "integrity": "sha512-ITyClEvcfv0ozqJl1vmWFWhvI+OIrkbInYqkEPE50wFPXj8J9Gd3FYf8+CkZJXJJsQBYe+2DvmoK9Zhx5w8W+w==", - "requires": { - "errno": "~0.1.7", - "xtend": "~4.0.1" - } - }, - "wrap-ansi": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", - "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", - "requires": { - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "requires": { - "ansi-regex": "^2.0.0" - } - } - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" - }, - "write-file-atomic": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-1.3.4.tgz", - "integrity": "sha1-+Aek8LHZ6ROuekgRLmzDrxmRtF8=", - "requires": { - "graceful-fs": "^4.1.11", - "imurmurhash": "^0.1.4", - "slide": "^1.1.5" - } - }, - "xtend": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", - "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=" - }, - "y18n": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", - "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==" - }, - "yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" - }, - "yargs": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-9.0.1.tgz", - "integrity": "sha1-UqzCP+7Kw0BCB47njAwAf1CF20w=", - "requires": { - "camelcase": "^4.1.0", - "cliui": "^3.2.0", - "decamelize": "^1.1.1", - "get-caller-file": "^1.0.1", - "os-locale": "^2.0.0", - "read-pkg-up": "^2.0.0", - "require-directory": "^2.1.1", - "require-main-filename": "^1.0.1", - "set-blocking": "^2.0.0", - "string-width": "^2.0.0", - "which-module": "^2.0.0", - "y18n": "^3.2.1", - "yargs-parser": "^7.0.0" - }, - "dependencies": { - "y18n": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", - "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=" - } - } - }, - "yargs-parser": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-7.0.0.tgz", - "integrity": "sha1-jQrELxbqVd69MyyvTEA4s+P139k=", - "requires": { - "camelcase": "^4.1.0" - } - }, - "yeoman-environment": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/yeoman-environment/-/yeoman-environment-2.0.5.tgz", - "integrity": "sha512-6/W7/B54OPHJXob0n0+pmkwFsirC8cokuQkPSmT/D0lCcSxkKtg/BA6ZnjUBIwjuGqmw3DTrT4en++htaUju5g==", - "requires": { - "chalk": "^2.1.0", - "debug": "^3.1.0", - "diff": "^3.3.1", - "escape-string-regexp": "^1.0.2", - "globby": "^6.1.0", - "grouped-queue": "^0.3.3", - "inquirer": "^3.3.0", - "is-scoped": "^1.0.0", - "lodash": "^4.17.4", - "log-symbols": "^2.1.0", - "mem-fs": "^1.1.0", - "text-table": "^0.2.0", - "untildify": "^3.0.2" - }, - "dependencies": { - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "requires": { - "ms": "2.0.0" - } - }, - "diff": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-3.4.0.tgz", - "integrity": "sha512-QpVuMTEoJMF7cKzi6bvWhRulU1fZqZnvyVQgNhPaxxuTYwyjn/j1v9falseQ/uXWwPnO56RBfwtg4h/EQXmucA==" - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "untildify": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/untildify/-/untildify-3.0.2.tgz", - "integrity": "sha1-fx8wIFWz/qDz6B3HjrNnZstl4/E=" - } - } - } - } -} diff --git a/Tests/LinuxMain.swift b/Tests/LinuxMain.swift deleted file mode 100644 index f2291bab8..000000000 --- a/Tests/LinuxMain.swift +++ /dev/null @@ -1,10 +0,0 @@ -import XCTest - -import APlus -import CorePromise - -var tests = [XCTestCaseEntry]() -tests += APlus.__allTests() -tests += CorePromise.__allTests() - -XCTMain(tests) diff --git a/Tests/PMKCoreLocation/CLGeocoderTests.swift b/Tests/PMKCoreLocation/CLGeocoderTests.swift new file mode 100644 index 000000000..4cfa1217f --- /dev/null +++ b/Tests/PMKCoreLocation/CLGeocoderTests.swift @@ -0,0 +1,121 @@ +import PMKCoreLocation +import CoreLocation +import PromiseKit +import XCTest +#if os(iOS) || os(watchOS) || os(OSX) + import class Contacts.CNPostalAddress +#endif + +class CLGeocoderTests: XCTestCase { + func test_reverseGeocodeLocation() { + class MockGeocoder: CLGeocoder { + override func reverseGeocodeLocation(_ location: CLLocation, completionHandler: @escaping CLGeocodeCompletionHandler) { + after(.seconds(0)).done { + completionHandler([dummyPlacemark], nil) + } + } + } + + let ex = expectation(description: "") + MockGeocoder().reverseGeocode(location: CLLocation()).done { x in + XCTAssertEqual(x, [dummyPlacemark]) + ex.fulfill() + }.cauterize() + waitForExpectations(timeout: 5) + } + + func test_geocodeAddressDictionary() { + class MockGeocoder: CLGeocoder { + override func geocodeAddressDictionary(_ addressDictionary: [AnyHashable : Any], completionHandler: @escaping CLGeocodeCompletionHandler) { + after(.seconds(0)).done { + completionHandler([dummyPlacemark], nil) + } + } + } + + let ex = expectation(description: "") + MockGeocoder().geocode([:]).done { x in + XCTAssertEqual(x, [dummyPlacemark]) + ex.fulfill() + }.cauterize() + waitForExpectations(timeout: 5) + } + + func test_geocodeAddressString() { + class MockGeocoder: CLGeocoder { + override func geocodeAddressString(_ addressString: String, completionHandler: @escaping CLGeocodeCompletionHandler) { + after(.seconds(0)).done { + completionHandler([dummyPlacemark], nil) + } + } + } + + let ex = expectation(description: "") + MockGeocoder().geocode("").done { x in + XCTAssertEqual(x, [dummyPlacemark]) + ex.fulfill() + }.cauterize() + waitForExpectations(timeout: 5) + } + +#if !os(tvOS) && swift(>=3.2) + func test_geocodePostalAddress() { + guard #available(iOS 11.0, OSX 10.13, watchOS 4.0, *) else { return } + + class MockGeocoder: CLGeocoder { + override func geocodePostalAddress(_ postalAddress: CNPostalAddress, completionHandler: @escaping CLGeocodeCompletionHandler) { + after(.seconds(0)).done { + completionHandler([dummyPlacemark], nil) + } + } + } + + let ex = expectation(description: "") + MockGeocoder().geocodePostalAddress(CNPostalAddress()).done { x in + XCTAssertEqual(x, [dummyPlacemark]) + ex.fulfill() + }.cauterize() + waitForExpectations(timeout: 5) + } + + func test_geocodePostalAddressLocale() { + guard #available(iOS 11.0, OSX 10.13, watchOS 4.0, *) else { return } + + class MockGeocoder: CLGeocoder { + override func geocodePostalAddress(_ postalAddress: CNPostalAddress, preferredLocale locale: Locale?, completionHandler: @escaping CLGeocodeCompletionHandler) { + after(.seconds(0)).done { + completionHandler([dummyPlacemark], nil) + } + } + } + + let ex = expectation(description: "") + MockGeocoder().geocodePostalAddress(CNPostalAddress(), preferredLocale: nil).done { x in + XCTAssertEqual(x, [dummyPlacemark]) + ex.fulfill() + }.cauterize() + waitForExpectations(timeout: 5) + } + + func test_reverseGeocodeLocationLocale() { + guard #available(iOS 11.0, OSX 10.13, watchOS 4.0, *) else { return } + + class MockGeocoder: CLGeocoder { + override func reverseGeocodeLocation(_ location: CLLocation, preferredLocale locale: Locale?, completionHandler: @escaping CLGeocodeCompletionHandler) { + after(.seconds(0)).done { + completionHandler([dummyPlacemark], nil) + } + } + } + + let ex = expectation(description: "") + MockGeocoder().reverseGeocode(location: CLLocation(), preferredLocale: nil).done { x in + XCTAssertEqual(x, [dummyPlacemark]) + ex.fulfill() + }.cauterize() + waitForExpectations(timeout: 5) + } +#endif +} + +private let dummyPlacemark = CLPlacemark() diff --git a/Tests/PMKCoreLocation/CLLocationManagerTests.swift b/Tests/PMKCoreLocation/CLLocationManagerTests.swift new file mode 100644 index 000000000..e589a4bc6 --- /dev/null +++ b/Tests/PMKCoreLocation/CLLocationManagerTests.swift @@ -0,0 +1,95 @@ +import PMKCoreLocation +import CoreLocation +import PromiseKit +import XCTest + +#if !os(tvOS) + +class Test_CLLocationManager_Swift: XCTestCase { + func test_fulfills_with_multiple_locations() { + swizzle(CLLocationManager.self, #selector(CLLocationManager.startUpdatingLocation)) { + swizzle(CLLocationManager.self, #selector(CLLocationManager.authorizationStatus), isClassMethod: true) { + let ex = expectation(description: "") + + CLLocationManager.requestLocation().done { x in + XCTAssertEqual(x, dummy) + ex.fulfill() + }.cauterize() + + waitForExpectations(timeout: 5) + } + } + } + + func test_fufillsWithSatisfyingBlock() { + swizzle(CLLocationManager.self, #selector(CLLocationManager.startUpdatingLocation)) { + swizzle(CLLocationManager.self, #selector(CLLocationManager.authorizationStatus), isClassMethod: true) { + let ex = expectation(description: "") + let block: ((CLLocation) -> Bool) = { location in + return location.coordinate.latitude == dummy.last?.coordinate.latitude + } + CLLocationManager.requestLocation(satisfying: block).done({ locations in + locations.forEach { XCTAssert(block($0) == true, "Block should be successful for returned values") } + ex.fulfill() + }).cauterize() + waitForExpectations(timeout: 5) + } + } + } + +#if os(iOS) + func test_requestAuthorization() { + let ex = expectation(description: "") + + CLLocationManager.requestAuthorization().done { + XCTAssertEqual($0, CLAuthorizationStatus.restricted) + ex.fulfill() + } + + waitForExpectations(timeout: 5, handler: nil) + } +#endif +} + + +/////////////////////////////////////////////////////////////// resources +private let dummy = [CLLocation(latitude: 0, longitude: 0), CLLocation(latitude: 10, longitude: 20)] + +extension CLLocationManager { + @objc func pmk_startUpdatingLocation() { + after(.milliseconds(100)).done { + self.delegate!.locationManager?(self, didUpdateLocations: dummy) + } + } + + @objc static func pmk_authorizationStatus() -> CLAuthorizationStatus { + #if os(macOS) + return .authorized + #else + return .authorizedWhenInUse + #endif + } +} + + +/////////////////////////////////////////////////////////////// utilities +import ObjectiveC + +func swizzle(_ foo: AnyClass, _ from: Selector, isClassMethod: Bool = false, body: () -> Void) { + let originalMethod: Method + let swizzledMethod: Method + + if isClassMethod { + originalMethod = class_getClassMethod(foo, from)! + swizzledMethod = class_getClassMethod(foo, Selector("pmk_\(from)"))! + } else { + originalMethod = class_getInstanceMethod(foo, from)! + swizzledMethod = class_getInstanceMethod(foo, Selector("pmk_\(from)"))! + } + + method_exchangeImplementations(originalMethod, swizzledMethod) + body() + method_exchangeImplementations(swizzledMethod, originalMethod) +} + +#endif diff --git a/Tests/PMKFoundation/TestNSNotificationCenter.swift b/Tests/PMKFoundation/TestNSNotificationCenter.swift new file mode 100644 index 000000000..a4f99b12e --- /dev/null +++ b/Tests/PMKFoundation/TestNSNotificationCenter.swift @@ -0,0 +1,22 @@ +import PMKFoundation +import Foundation +import PromiseKit +import XCTest + +class NSNotificationCenterTests: XCTestCase { + func test() { + let ex = expectation(description: "") + let userInfo = ["a": 1] + + NotificationCenter.default.observe(once: PMKTestNotification).done { value in + XCTAssertEqual(value.userInfo?.count, 1) + ex.fulfill() + } + + NotificationCenter.default.post(name: PMKTestNotification, object: nil, userInfo: userInfo) + + waitForExpectations(timeout: 5) + } +} + +private let PMKTestNotification = Notification.Name("PMKTestNotification") diff --git a/Tests/PMKFoundation/TestNSObject.swift b/Tests/PMKFoundation/TestNSObject.swift new file mode 100644 index 000000000..2f23a6201 --- /dev/null +++ b/Tests/PMKFoundation/TestNSObject.swift @@ -0,0 +1,80 @@ +import PMKFoundation +import Foundation +import PromiseKit +import XCTest + +#if !os(Linux) && !os(Windows) + +class NSObjectTests: XCTestCase { + func testKVO() { + let ex = expectation(description: "") + + let foo = Foo() + foo.observe(.promise, keyPath: "bar").done { newValue in + XCTAssertEqual(newValue as? String, "moo") + ex.fulfill() + }.catch { _ in + XCTFail() + } + foo.bar = "moo" + + waitForExpectations(timeout: 5) + } + + func testAfterlife() { + let ex = expectation(description: "") + var killme: NSObject! + + autoreleasepool { + + func innerScope() { + killme = NSObject() + after(life: killme).done { _ in + //… + ex.fulfill() + } + } + + innerScope() + + after(.milliseconds(200)).done { + killme = nil + } + } + + waitForExpectations(timeout: 5) + } + + func testMultiObserveAfterlife() { + let ex1 = expectation(description: "") + let ex2 = expectation(description: "") + var killme: NSObject! + + autoreleasepool { + + func innerScope() { + killme = NSObject() + after(life: killme).done { _ in + ex1.fulfill() + } + after(life: killme).done { _ in + ex2.fulfill() + } + } + + innerScope() + + after(.milliseconds(200)).done { + killme = nil + } + } + + waitForExpectations(timeout: 5) + } +} + +private class Foo: NSObject { + @objc dynamic var bar: String = "bar" +} + +#endif diff --git a/Tests/PMKFoundation/TestNSTask.swift b/Tests/PMKFoundation/TestNSTask.swift new file mode 100644 index 000000000..65a47b523 --- /dev/null +++ b/Tests/PMKFoundation/TestNSTask.swift @@ -0,0 +1,50 @@ +import PMKFoundation +import Foundation +import PromiseKit +import XCTest + +#if os(macOS) + +class NSTaskTests: XCTestCase { + func test1() { + let ex = expectation(description: "") + let task = Process() + task.launchPath = "/usr/bin/basename" + task.arguments = ["/foo/doe/bar"] + task.launch(.promise).done { stdout, _ in + let stdout = String(data: stdout.fileHandleForReading.readDataToEndOfFile(), encoding: .utf8) + XCTAssertEqual(stdout, "bar\n") + ex.fulfill() + }.cauterize() + waitForExpectations(timeout: 5) + } + + func test2() { + let ex = expectation(description: "") + let dir = "PMKAbsentDirectory" + + let task = Process() + task.launchPath = "/bin/ls" + task.arguments = [dir] + + task.launch(.promise).done { _ in + XCTFail() + }.catch { err in + do { + throw err + } catch Process.PMKError.execution(let proc, let stdout, let stderr) { + let expectedStderr = "ls: \(dir): No such file or directory\n" + + XCTAssertEqual(stderr, expectedStderr) + XCTAssertEqual(proc.terminationStatus, 1) + XCTAssertEqual(stdout?.count ?? 0, 0) + } catch { + XCTFail() + } + ex.fulfill() + } + waitForExpectations(timeout: 5) + } +} + +#endif diff --git a/Tests/PMKFoundation/TestNSURLSession.swift b/Tests/PMKFoundation/TestNSURLSession.swift new file mode 100644 index 000000000..fc7c24ef6 --- /dev/null +++ b/Tests/PMKFoundation/TestNSURLSession.swift @@ -0,0 +1,81 @@ +#if !os(Linux) && !os(watchOS) && !os(Windows) + +import OHHTTPStubsSwift +import PMKFoundation +import OHHTTPStubs +import PromiseKit +import XCTest + +class NSURLSessionTests: XCTestCase { + func test1() { + let json: NSDictionary = ["key1": "value1", "key2": ["value2A", "value2B"]] + + stub(condition: { $0.url!.host == "example.com" }) { _ in + HTTPStubsResponse(jsonObject: json, statusCode: 200, headers: nil) + } + + let ex = expectation(description: "") + let rq = URLRequest(url: URL(string: "http://example.com")!) + firstly { + URLSession.shared.dataTask(.promise, with: rq) + }.compactMap { + try JSONSerialization.jsonObject(with: $0.data) as? NSDictionary + }.done { rsp in + XCTAssertEqual(json, rsp) + ex.fulfill() + }.cauterize() + waitForExpectations(timeout: 5) + } + + func test2() { + + // test that URLDataPromise chains thens + // this test because I don’t trust the Swift compiler + + let dummy = ("fred" as NSString).data(using: String.Encoding.utf8.rawValue)! + + stub(condition: { $0.url!.host == "example.com" }) { _ in + return HTTPStubsResponse(data: dummy, statusCode: 200, headers: [:]) + } + + let ex = expectation(description: "") + let rq = URLRequest(url: URL(string: "http://example.com")!) + + after(.milliseconds(100)).then { + URLSession.shared.dataTask(.promise, with: rq) + }.done { x in + XCTAssertEqual(x.data, dummy) + ex.fulfill() + }.cauterize() + + waitForExpectations(timeout: 5) + } + + /// test that our convenience String constructor applies + func test3() { + let dummy = "fred" + + stub(condition: { $0.url!.host == "example.com" }) { _ in + let data = dummy.data(using: .utf8)! + return HTTPStubsResponse(data: data, statusCode: 200, headers: [:]) + } + + let ex = expectation(description: "") + let rq = URLRequest(url: URL(string: "http://example.com")!) + + after(.milliseconds(100)).then { + URLSession.shared.dataTask(.promise, with: rq) + }.map(String.init(data:urlResponse:)).done { + XCTAssertEqual($0, dummy) + ex.fulfill() + }.cauterize() + + waitForExpectations(timeout: 5) + } + + override func tearDown() { + //OHHTTPStubs.removeAllStubs() + } +} + +#endif diff --git a/Tests/PMKHomeKit/HMAccessoryBrowserTests.swift b/Tests/PMKHomeKit/HMAccessoryBrowserTests.swift new file mode 100644 index 000000000..0ddfe55b5 --- /dev/null +++ b/Tests/PMKHomeKit/HMAccessoryBrowserTests.swift @@ -0,0 +1,84 @@ +// +// HMAccessoryBrowserTests.swift +// PMKHKTests +// +// Created by Chris Chares on 7/25/18. +// Copyright © 2018 Max Howell. All rights reserved. +// + +#if canImport(HomeKit) && !os(tvOS) && !os(watchOS) + +import XCTest +import PromiseKit +import HomeKit +@testable import PMKHomeKit + +class HMAccessoryBrowserTests: XCTestCase { + + func testBrowserScanReturningFirst() { + swizzle(HMAccessoryBrowser.self, #selector(HMAccessoryBrowser.startSearchingForNewAccessories)) { + let ex = expectation(description: "") + + HMPromiseAccessoryBrowser().start(scanInterval: .returnFirst(timeout: 0.5)) + .done { accessories in + XCTAssertEqual(accessories.count, 1) + ex.fulfill() + }.cauterize() + + waitForExpectations(timeout: 5, handler: nil) + } + } + + func testBrowserScanReturningTimeout() { + let ex = expectation(description: "") + + HMPromiseAccessoryBrowser().start(scanInterval: .returnFirst(timeout: 0.5)) + .catch { error in + // Why would we have discovered anything? + ex.fulfill() + } + + waitForExpectations(timeout: 5, handler: nil) + } +} + +extension HMAccessoryBrowser { + @objc func pmk_startSearchingForNewAccessories() { + after(.milliseconds(100)) + .done { swag in + self.delegate!.accessoryBrowser?(self, didFindNewAccessory: MockAccessory()) + } + } +} + +/// Mocks +class MockAccessory: HMAccessory { + var _uniqueID: UUID = UUID() + override var uniqueIdentifier: UUID { return _uniqueID } + + override init() { + super.init() + } +} + +// Utilty taken from https://github.com/PromiseKit/CoreLocation/blob/master/Tests/CLLocationManagerTests.swift +import ObjectiveC + +func swizzle(_ foo: AnyClass, _ from: Selector, isClassMethod: Bool = false, body: () -> Void) { + let originalMethod: Method + let swizzledMethod: Method + + if isClassMethod { + originalMethod = class_getClassMethod(foo, from)! + swizzledMethod = class_getClassMethod(foo, Selector("pmk_\(from)"))! + } else { + originalMethod = class_getInstanceMethod(foo, from)! + swizzledMethod = class_getInstanceMethod(foo, Selector("pmk_\(from)"))! + } + + method_exchangeImplementations(originalMethod, swizzledMethod) + body() + method_exchangeImplementations(swizzledMethod, originalMethod) +} + +#endif diff --git a/Tests/PMKHomeKit/UtilsTests.swift b/Tests/PMKHomeKit/UtilsTests.swift new file mode 100644 index 000000000..f334e2316 --- /dev/null +++ b/Tests/PMKHomeKit/UtilsTests.swift @@ -0,0 +1,67 @@ +// +// UtilsTests.swift +// PMKHKTests +// +// Created by Chris Chares on 7/25/18. +// Copyright © 2018 Max Howell. All rights reserved. +// + +#if canImport(HomeKit) && !os(tvOS) && !os(watchOS) + +import XCTest +import PromiseKit +@testable import PMKHomeKit + +class UtilsTests: XCTestCase { + + var strongProxy: PromiseProxy? = PromiseProxy() + + override func setUp() { + strongProxy = PromiseProxy() + } + + override func tearDown() { + strongProxy = nil + } + + // The proxy should create a retain cycle until the promise is resolved + func testRetainCycle() { + weak var weakVar = strongProxy + XCTAssertNotNil(weakVar) + + let exp = expectation(description: "") + strongProxy = nil + after(.milliseconds(50)) + .done { + XCTAssertNotNil(weakVar) + exp.fulfill() + } + waitForExpectations(timeout: 5, handler: nil) + } + + // Once resolved, the proxy should break the retain cycle + func testRelease() { + weak var weakVar = strongProxy + XCTAssertNotNil(weakVar) + + let exp = expectation(description: "") + strongProxy!.fulfill(42) + strongProxy = nil + + after(.milliseconds(50)) + .done { + XCTAssertNil(weakVar) + exp.fulfill() + } + waitForExpectations(timeout: 5, handler: nil) + } + + // Cancel should reject with a PMKError + func testCancel() { + let proxy = strongProxy! + proxy.cancel() + XCTAssertNotNil(proxy.promise.error) + } +} + +#endif diff --git a/Tests/PMKMapKit/TestMapKit.swift b/Tests/PMKMapKit/TestMapKit.swift new file mode 100644 index 000000000..581799564 --- /dev/null +++ b/Tests/PMKMapKit/TestMapKit.swift @@ -0,0 +1,67 @@ +#if !os(watchOS) + +import PromiseKit +import PMKMapKit +import MapKit +import XCTest + +class Test_MKDirections_Swift: XCTestCase { + func test_directions_response() { + let ex = expectation(description: "") + + class MockDirections: MKDirections { + override func calculate(completionHandler: @escaping MKDirections.DirectionsHandler) { + completionHandler(MKDirections.Response(), nil) + } + } + + let rq = MKDirections.Request() + let directions = MockDirections(request: rq) + + directions.calculate().done { _ in + ex.fulfill() + }.cauterize() + + waitForExpectations(timeout: 5, handler: nil) + } + + + func test_ETA_response() { + let ex = expectation(description: "") + + class MockDirections: MKDirections { + override func calculateETA(completionHandler: @escaping MKDirections.ETAHandler) { + completionHandler(MKDirections.ETAResponse(), nil) + } + } + + let rq = MKDirections.Request() + MockDirections(request: rq).calculateETA().done { rsp in + ex.fulfill() + }.cauterize() + + waitForExpectations(timeout: 5, handler: nil) + } + +} + +class Test_MKSnapshotter_Swift: XCTestCase { + func test() { + let ex = expectation(description: "") + + class MockSnapshotter: MKMapSnapshotter { + override func start(completionHandler: @escaping MKMapSnapshotter.CompletionHandler) { + completionHandler(MKMapSnapshotter.Snapshot(), nil) + } + } + + let snapshotter = MockSnapshotter() + snapshotter.start().done { _ in + ex.fulfill() + }.cauterize() + + waitForExpectations(timeout: 5, handler: nil) + } +} + +#endif