From 50d492f6de987cdfeacb5725a07a00936c07f4f0 Mon Sep 17 00:00:00 2001 From: Michael Wolz Date: Thu, 6 Jun 2024 17:10:09 +0200 Subject: [PATCH 01/28] chore(*): update podfile --- ios/Podfile.lock | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ios/Podfile.lock b/ios/Podfile.lock index e91cb488..7842c214 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -1,7 +1,7 @@ PODS: - - Capacitor (5.0.3): + - Capacitor (6.0.0): - CapacitorCordova - - CapacitorCordova (5.0.3) + - CapacitorCordova (6.0.0) DEPENDENCIES: - "Capacitor (from `../node_modules/@capacitor/ios`)" @@ -14,9 +14,9 @@ EXTERNAL SOURCES: :path: "../node_modules/@capacitor/ios" SPEC CHECKSUMS: - Capacitor: 304a960e431f9e6f78556554ca71c41c1b2b9680 - CapacitorCordova: def732a63679698df6fb392bbe6d269a0b61e937 + Capacitor: 559d073c4ca6c27f8e7002c807eea94c3ba435a9 + CapacitorCordova: 8c4bfdf69368512e85b1d8b724dd7546abeb30af PODFILE CHECKSUM: 14e8b2400457751b865e1c327e7cfa1c6fa67da6 -COCOAPODS: 1.11.3 +COCOAPODS: 1.15.2 From 9ec31def92b2557b046bad93748b04f77030b9bd Mon Sep 17 00:00:00 2001 From: Michael Wolz Date: Thu, 6 Jun 2024 17:10:53 +0200 Subject: [PATCH 02/28] fix(ios): use native camera selection for optimal focus The CameraController now prioritizes `builtInTripleCamera` and similar options to select the best fitting camera. This enhances continuous auto-focus on newer iPhones, especially Pro models. Closes: capacitor-community/camera-preview#324 Addresses: capacitor-community/camera-preview#256 --- ios/Plugin/CameraController.swift | 43 +++++++++++++++++-------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/ios/Plugin/CameraController.swift b/ios/Plugin/CameraController.swift index a09e72a0..795e5e21 100644 --- a/ios/Plugin/CameraController.swift +++ b/ios/Plugin/CameraController.swift @@ -45,25 +45,29 @@ extension CameraController { } func configureCaptureDevices() throws { - - let session = AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInWideAngleCamera], mediaType: AVMediaType.video, position: .unspecified) - - let cameras = session.devices.compactMap { $0 } - guard !cameras.isEmpty else { throw CameraControllerError.noCamerasAvailable } - - for camera in cameras { - if camera.position == .front { - self.frontCamera = camera - } - - if camera.position == .back { - self.rearCamera = camera - - try camera.lockForConfiguration() - camera.focusMode = .continuousAutoFocus - camera.unlockForConfiguration() - } - } + // For the front camera we are simply using the default one. iOS will automatically provide the best fit here + self.frontCamera = AVCaptureDevice.default(.builtInWideAngleCamera, for: AVMediaType.video, position: .front) + + // For the rear camera we'll use a discovery session that will follow the list of "best" cameras to choose from + let deviceTypes: [AVCaptureDevice.DeviceType] = [ + .builtInTripleCamera, + .builtInDualWideCamera, + .builtInDualCamera, + .builtInWideAngleCamera, + ] + + let discoverySession = AVCaptureDevice.DiscoverySession(deviceTypes: deviceTypes, mediaType: AVMediaType.video, position: .back) + + // We then define the first camera as rear camera. The devices are already sorted based on the provided device types + // See: https://developer.apple.com/documentation/avfoundation/capture_setup/choosing_a_capture_device#2958877 + guard let rearCamera = discoverySession.devices.first else { throw CameraControllerError.noCamerasAvailable } + + try rearCamera.lockForConfiguration() + rearCamera.focusMode = .continuousAutoFocus + rearCamera.unlockForConfiguration() + + self.rearCamera = rearCamera + if disableAudio == false { self.audioDevice = AVCaptureDevice.default(for: AVMediaType.audio) } @@ -138,7 +142,6 @@ extension CameraController { try configureDeviceInputs() try configurePhotoOutput() try configureDataOutput() - // try configureVideoOutput() } catch { DispatchQueue.main.async { completionHandler(error) From 9d7f6ac06d03f9d1ba3403524f56657886d72cf6 Mon Sep 17 00:00:00 2001 From: Michael Wolz Date: Tue, 11 Jun 2024 15:04:15 +0200 Subject: [PATCH 03/28] fix(camera-controller): prefer regular wide angle camera over dual wide angle --- ios/Plugin/CameraController.swift | 2 -- 1 file changed, 2 deletions(-) diff --git a/ios/Plugin/CameraController.swift b/ios/Plugin/CameraController.swift index 795e5e21..f7ee1a96 100644 --- a/ios/Plugin/CameraController.swift +++ b/ios/Plugin/CameraController.swift @@ -51,8 +51,6 @@ extension CameraController { // For the rear camera we'll use a discovery session that will follow the list of "best" cameras to choose from let deviceTypes: [AVCaptureDevice.DeviceType] = [ .builtInTripleCamera, - .builtInDualWideCamera, - .builtInDualCamera, .builtInWideAngleCamera, ] From 9e1a74438568e665b7b617c0f13a8fbaa4d3d693 Mon Sep 17 00:00:00 2001 From: Michael Wolz Date: Fri, 21 Jun 2024 17:51:55 +0200 Subject: [PATCH 04/28] feat: camera up and running --- ios/Plugin/CameraController.swift | 280 +++++++++--------------------- ios/Plugin/Plugin.swift | 233 +++++++++++-------------- src/definitions.ts | 9 +- 3 files changed, 188 insertions(+), 334 deletions(-) diff --git a/ios/Plugin/CameraController.swift b/ios/Plugin/CameraController.swift index f7ee1a96..667b77b4 100644 --- a/ios/Plugin/CameraController.swift +++ b/ios/Plugin/CameraController.swift @@ -11,182 +11,88 @@ import UIKit class CameraController: NSObject { var captureSession: AVCaptureSession? - + var currentCameraPosition: CameraPosition? - + var frontCamera: AVCaptureDevice? var frontCameraInput: AVCaptureDeviceInput? - - var dataOutput: AVCaptureVideoDataOutput? - var photoOutput: AVCapturePhotoOutput? - var rearCamera: AVCaptureDevice? var rearCameraInput: AVCaptureDeviceInput? - + + var photoOutput: AVCapturePhotoOutput? var previewLayer: AVCaptureVideoPreviewLayer? - + var flashMode = AVCaptureDevice.FlashMode.off + var photoCaptureCompletionBlock: ((UIImage?, Error?) -> Void)? - var sampleBufferCaptureCompletionBlock: ((UIImage?, Error?) -> Void)? - - var highResolutionOutput: Bool = false - - var audioDevice: AVCaptureDevice? - var audioInput: AVCaptureDeviceInput? - - var zoomFactor: CGFloat = 1.0 + + var zoomFactor: CGFloat = 1 } extension CameraController { - func prepare(cameraPosition: String, disableAudio: Bool, completionHandler: @escaping (Error?) -> Void) { - func createCaptureSession() { - self.captureSession = AVCaptureSession() - } - - func configureCaptureDevices() throws { - // For the front camera we are simply using the default one. iOS will automatically provide the best fit here - self.frontCamera = AVCaptureDevice.default(.builtInWideAngleCamera, for: AVMediaType.video, position: .front) - - // For the rear camera we'll use a discovery session that will follow the list of "best" cameras to choose from - let deviceTypes: [AVCaptureDevice.DeviceType] = [ - .builtInTripleCamera, - .builtInWideAngleCamera, - ] - - let discoverySession = AVCaptureDevice.DiscoverySession(deviceTypes: deviceTypes, mediaType: AVMediaType.video, position: .back) - - // We then define the first camera as rear camera. The devices are already sorted based on the provided device types - // See: https://developer.apple.com/documentation/avfoundation/capture_setup/choosing_a_capture_device#2958877 - guard let rearCamera = discoverySession.devices.first else { throw CameraControllerError.noCamerasAvailable } - - try rearCamera.lockForConfiguration() - rearCamera.focusMode = .continuousAutoFocus - rearCamera.unlockForConfiguration() - + func prepareCamera(cameraPosition: CameraPosition, zoomFactor: CGFloat, completionHandler: @escaping (Error?) -> Void) { + // Set up capture session + let captureSession = AVCaptureSession() + self.captureSession = captureSession + captureSession.beginConfiguration() + captureSession.sessionPreset = AVCaptureSession.Preset.high + + // Set up preview layer + let previewLayer = AVCaptureVideoPreviewLayer(session: captureSession) + previewLayer.videoGravity = AVLayerVideoGravity.resizeAspectFill + self.previewLayer = previewLayer + + // Configure camera input + let deviceDiscoverySession = AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInTripleCamera, .builtInDualCamera, .builtInDualWideCamera, .builtInWideAngleCamera], mediaType: AVMediaType.video, position: .unspecified) + if let rearCamera = deviceDiscoverySession.devices.first(where: { $0.position == .back }) { self.rearCamera = rearCamera - - if disableAudio == false { - self.audioDevice = AVCaptureDevice.default(for: AVMediaType.audio) - } - } - - func configureDeviceInputs() throws { - guard let captureSession = self.captureSession else { throw CameraControllerError.captureSessionIsMissing } - - if cameraPosition == "rear" { - if let rearCamera = self.rearCamera { - self.rearCameraInput = try AVCaptureDeviceInput(device: rearCamera) - - if captureSession.canAddInput(self.rearCameraInput!) { captureSession.addInput(self.rearCameraInput!) } - - self.currentCameraPosition = .rear - } - } else if cameraPosition == "front" { - if let frontCamera = self.frontCamera { - self.frontCameraInput = try AVCaptureDeviceInput(device: frontCamera) - - if captureSession.canAddInput(self.frontCameraInput!) { captureSession.addInput(self.frontCameraInput!) } else { throw CameraControllerError.inputsAreInvalid } - - self.currentCameraPosition = .front - } - } else { throw CameraControllerError.noCamerasAvailable } - - // Add audio input - if disableAudio == false { - if let audioDevice = self.audioDevice { - self.audioInput = try AVCaptureDeviceInput(device: audioDevice) - if captureSession.canAddInput(self.audioInput!) { - captureSession.addInput(self.audioInput!) - } else { - throw CameraControllerError.inputsAreInvalid - } - } - } } - - func configurePhotoOutput() throws { - guard let captureSession = self.captureSession else { throw CameraControllerError.captureSessionIsMissing } - - self.photoOutput = AVCapturePhotoOutput() - self.photoOutput!.setPreparedPhotoSettingsArray([AVCapturePhotoSettings(format: [AVVideoCodecKey: AVVideoCodecType.jpeg])], completionHandler: nil) - self.photoOutput?.isHighResolutionCaptureEnabled = self.highResolutionOutput - if captureSession.canAddOutput(self.photoOutput!) { captureSession.addOutput(self.photoOutput!) } - captureSession.startRunning() + + if let frontCamera = deviceDiscoverySession.devices.first(where: { $0.position == .front }) { + self.frontCamera = frontCamera } - - func configureDataOutput() throws { - guard let captureSession = self.captureSession else { throw CameraControllerError.captureSessionIsMissing } - - self.dataOutput = AVCaptureVideoDataOutput() - self.dataOutput?.videoSettings = [ - (kCVPixelBufferPixelFormatTypeKey as String): NSNumber(value: kCVPixelFormatType_32BGRA as UInt32) - ] - self.dataOutput?.alwaysDiscardsLateVideoFrames = true - if captureSession.canAddOutput(self.dataOutput!) { - captureSession.addOutput(self.dataOutput!) - } - - captureSession.commitConfiguration() - - let queue = DispatchQueue(label: "DataOutput", attributes: []) - self.dataOutput?.setSampleBufferDelegate(self, queue: queue) - } - - DispatchQueue(label: "prepare").async { - do { - createCaptureSession() - try configureCaptureDevices() - try configureDeviceInputs() - try configurePhotoOutput() - try configureDataOutput() - } catch { - DispatchQueue.main.async { - completionHandler(error) - } - + + self.currentCameraPosition = cameraPosition + do { + if cameraPosition == .front, let camera = frontCamera { + self.frontCameraInput = try AVCaptureDeviceInput(device: camera) + if captureSession.canAddInput(self.frontCameraInput!) { captureSession.addInput(self.frontCameraInput!) } + } else if let camera = rearCamera { + self.rearCameraInput = try AVCaptureDeviceInput(device: camera) + if captureSession.canAddInput(self.rearCameraInput!) { captureSession.addInput(self.rearCameraInput!) } + } else { + completionHandler(CameraControllerError.noCamerasAvailable) return } - - DispatchQueue.main.async { - completionHandler(nil) - } + } catch { + completionHandler(CameraControllerError.noCamerasAvailable) + return + } + + // Configure camera output + let photoOutput = AVCapturePhotoOutput() + photoOutput.setPreparedPhotoSettingsArray([AVCapturePhotoSettings(format: [AVVideoCodecKey: AVVideoCodecType.jpeg])], completionHandler: nil) + if captureSession.canAddOutput(photoOutput) { + captureSession.addOutput(photoOutput) + self.photoOutput = photoOutput } + + captureSession.commitConfiguration() + captureSession.startRunning() + + completionHandler(nil) } - - func displayPreview(on view: UIView) throws { - guard let captureSession = self.captureSession, captureSession.isRunning else { throw CameraControllerError.captureSessionIsMissing } - - self.previewLayer = AVCaptureVideoPreviewLayer(session: captureSession) - self.previewLayer?.videoGravity = AVLayerVideoGravity.resizeAspectFill - + + func displayPreview(on view: UIView) { view.layer.insertSublayer(self.previewLayer!, at: 0) self.previewLayer?.frame = view.frame - updateVideoOrientation() } - - func setupGestures(target: UIView, enableZoom: Bool) { - setupTapGesture(target: target, selector: #selector(handleTap(_:)), delegate: self) - if enableZoom { - setupPinchGesture(target: target, selector: #selector(handlePinch(_:)), delegate: self) - } - } - - func setupTapGesture(target: UIView, selector: Selector, delegate: UIGestureRecognizerDelegate?) { - let tapGesture = UITapGestureRecognizer(target: self, action: selector) - tapGesture.delegate = delegate - target.addGestureRecognizer(tapGesture) - } - - func setupPinchGesture(target: UIView, selector: Selector, delegate: UIGestureRecognizerDelegate?) { - let pinchGesture = UIPinchGestureRecognizer(target: self, action: selector) - pinchGesture.delegate = delegate - target.addGestureRecognizer(pinchGesture) - } - + func updateVideoOrientation() { - assert(Thread.isMainThread) // UIApplication.statusBarOrientation requires the main thread. + // UIApplication.statusBarOrientation requires the main thread. + assert(Thread.isMainThread) let videoOrientation: AVCaptureVideoOrientation switch UIApplication.shared.statusBarOrientation { @@ -205,17 +111,34 @@ extension CameraController { } previewLayer?.connection?.videoOrientation = videoOrientation - dataOutput?.connections.forEach { $0.videoOrientation = videoOrientation } photoOutput?.connections.forEach { $0.videoOrientation = videoOrientation } } + func setupGestures(target: UIView, enableZoom: Bool) { + setupTapGesture(target: target, selector: #selector(handleTap(_:)), delegate: self) + if enableZoom { + setupPinchGesture(target: target, selector: #selector(handlePinch(_:)), delegate: self) + } + } + + func setupTapGesture(target: UIView, selector: Selector, delegate: UIGestureRecognizerDelegate?) { + let tapGesture = UITapGestureRecognizer(target: self, action: selector) + tapGesture.delegate = delegate + target.addGestureRecognizer(tapGesture) + } + + func setupPinchGesture(target: UIView, selector: Selector, delegate: UIGestureRecognizerDelegate?) { + let pinchGesture = UIPinchGestureRecognizer(target: self, action: selector) + pinchGesture.delegate = delegate + target.addGestureRecognizer(pinchGesture) + } + func switchCameras() throws { guard let currentCameraPosition = currentCameraPosition, let captureSession = self.captureSession, captureSession.isRunning else { throw CameraControllerError.captureSessionIsMissing } captureSession.beginConfiguration() func switchToFrontCamera() throws { - guard let rearCameraInput = self.rearCameraInput, captureSession.inputs.contains(rearCameraInput), let frontCamera = self.frontCamera else { throw CameraControllerError.invalidOperation } @@ -233,7 +156,6 @@ extension CameraController { } func switchToRearCamera() throws { - guard let frontCameraInput = self.frontCameraInput, captureSession.inputs.contains(frontCameraInput), let rearCamera = self.rearCamera else { throw CameraControllerError.invalidOperation } @@ -264,7 +186,6 @@ extension CameraController { let settings = AVCapturePhotoSettings() settings.flashMode = self.flashMode - settings.isHighResolutionPhotoEnabled = self.highResolutionOutput self.photoOutput?.capturePhoto(with: settings, delegate: self) self.photoCaptureCompletionBlock = completion @@ -394,32 +315,6 @@ extension CameraController { } catch { throw CameraControllerError.invalidOperation } - - } - - func captureVideo(completion: @escaping (URL?, Error?) -> Void) { - guard let captureSession = self.captureSession, captureSession.isRunning else { - completion(nil, CameraControllerError.captureSessionIsMissing) - return - } - let path = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask)[0] - let identifier = UUID() - let randomIdentifier = identifier.uuidString.replacingOccurrences(of: "-", with: "") - let finalIdentifier = String(randomIdentifier.prefix(8)) - let fileName="cpcp_video_"+finalIdentifier+".mp4" - - let fileUrl = path.appendingPathComponent(fileName) - try? FileManager.default.removeItem(at: fileUrl) - /*videoOutput!.startRecording(to: fileUrl, recordingDelegate: self) - self.videoRecordCompletionBlock = completion*/ - } - - func stopRecording(completion: @escaping (Error?) -> Void) { - guard let captureSession = self.captureSession, captureSession.isRunning else { - completion(CameraControllerError.captureSessionIsMissing) - return - } - // self.videoOutput?.stopRecording() } } @@ -475,7 +370,7 @@ extension CameraController: UIGestureRecognizerDelegate { switch pinch.state { case .began: fallthrough case .changed: - let newScaleFactor = minMaxZoom(pinch.scale * zoomFactor) + let newScaleFactor = minMaxZoom(pinch.scale) update(scale: newScaleFactor) case .ended: zoomFactor = device.videoZoomFactor @@ -487,8 +382,12 @@ extension CameraController: UIGestureRecognizerDelegate { extension CameraController: AVCapturePhotoCaptureDelegate { public func photoOutput(_ captureOutput: AVCapturePhotoOutput, didFinishProcessingPhoto photoSampleBuffer: CMSampleBuffer?, previewPhoto previewPhotoSampleBuffer: CMSampleBuffer?, resolvedSettings: AVCaptureResolvedPhotoSettings, bracketSettings: AVCaptureBracketedStillImageSettings?, error: Swift.Error?) { - if let error = error { self.photoCaptureCompletionBlock?(nil, error) } else if let buffer = photoSampleBuffer, let data = AVCapturePhotoOutput.jpegPhotoDataRepresentation(forJPEGSampleBuffer: buffer, previewPhotoSampleBuffer: nil), - let image = UIImage(data: data) { + if let error = error { + self.photoCaptureCompletionBlock?(nil, error) + } else if + let buffer = photoSampleBuffer, + let data = AVCapturePhotoOutput.jpegPhotoDataRepresentation(forJPEGSampleBuffer: buffer, previewPhotoSampleBuffer: nil), + let image = UIImage(data: data) { self.photoCaptureCompletionBlock?(image.fixedOrientation(), nil) } else { self.photoCaptureCompletionBlock?(nil, CameraControllerError.unknown) @@ -573,7 +472,6 @@ extension CameraControllerError: LocalizedError { } extension UIImage { - func fixedOrientation() -> UIImage? { guard imageOrientation != UIImage.Orientation.up else { @@ -637,13 +535,3 @@ extension UIImage { return UIImage.init(cgImage: newCGImage, scale: 1, orientation: .up) } } - -extension CameraController: AVCaptureFileOutputRecordingDelegate { - func fileOutput(_ output: AVCaptureFileOutput, didFinishRecordingTo outputFileURL: URL, from connections: [AVCaptureConnection], error: Error?) { - /*if error == nil { - self.videoRecordCompletionBlock?(outputFileURL, nil) - } else { - self.videoRecordCompletionBlock?(nil, error) - }*/ - } -} diff --git a/ios/Plugin/Plugin.swift b/ios/Plugin/Plugin.swift index 044a9e68..fa36c264 100644 --- a/ios/Plugin/Plugin.swift +++ b/ios/Plugin/Plugin.swift @@ -7,110 +7,124 @@ import AVFoundation */ @objc(CameraPreview) public class CameraPreview: CAPPlugin { - - var previewView: UIView! - var cameraPosition = String() let cameraController = CameraController() - var x: CGFloat? - var y: CGFloat? - var width: CGFloat? - var height: CGFloat? - var paddingBottom: CGFloat? + var previewView: UIView! + var cameraPosition: CameraPosition = .rear + var x: CGFloat = 0.0 + var y: CGFloat = 0.0 + var width: CGFloat = UIScreen.main.bounds.size.width + var height: CGFloat = UIScreen.main.bounds.size.height + var paddingBottom: CGFloat = 0 var rotateWhenOrientationChanged: Bool? - var toBack: Bool? + var toBack: Bool = false var storeToFile: Bool? var enableZoom: Bool? - var highResolutionOutput: Bool = false - var disableAudio: Bool = false - + var zoomFactor: CGFloat = 1.0 + + private func hasCameraPermission() -> Bool { + let status = AVCaptureDevice.authorizationStatus(for: AVMediaType.video) + if (status == AVAuthorizationStatus.authorized) { + return true + } + return false + } + @objc func rotated() { - let height = self.paddingBottom != nil ? self.height! - self.paddingBottom!: self.height! - + let height = self.height - self.paddingBottom + if UIApplication.shared.statusBarOrientation.isLandscape { - self.previewView.frame = CGRect(x: self.y!, y: self.x!, width: max(height, self.width!), height: min(height, self.width!)) + self.previewView.frame = CGRect(x: self.y, y: self.x, width: max(height, self.width), height: min(height, self.width)) self.cameraController.previewLayer?.frame = self.previewView.frame } - + if UIApplication.shared.statusBarOrientation.isPortrait { if self.previewView != nil && self.x != nil && self.y != nil && self.width != nil && self.height != nil { - self.previewView.frame = CGRect(x: self.x!, y: self.y!, width: min(height, self.width!), height: max(height, self.width!)) + self.previewView.frame = CGRect(x: self.x, y: self.y, width: min(height, self.width), height: max(height, self.width)) } self.cameraController.previewLayer?.frame = self.previewView.frame } - + cameraController.updateVideoOrientation() } - + @objc func start(_ call: CAPPluginCall) { - self.cameraPosition = call.getString("position") ?? "rear" - self.highResolutionOutput = call.getBool("enableHighResolution") ?? false - self.cameraController.highResolutionOutput = self.highResolutionOutput - - if call.getInt("width") != nil { - self.width = CGFloat(call.getInt("width")!) - } else { - self.width = UIScreen.main.bounds.size.width + if (call.getString("position") == "front") { + self.cameraPosition = .front + } + + if let width = call.getInt("width") { + self.width = CGFloat(width) + } + + if let height = call.getInt("height") { + self.height = CGFloat(height) } - if call.getInt("height") != nil { - self.height = CGFloat(call.getInt("height")!) - } else { - self.height = UIScreen.main.bounds.size.height + + if let x = call.getInt("x") { + self.x = CGFloat(x) / 2 } - self.x = call.getInt("x") != nil ? CGFloat(call.getInt("x")!)/UIScreen.main.scale: 0 - self.y = call.getInt("y") != nil ? CGFloat(call.getInt("y")!)/UIScreen.main.scale: 0 - if call.getInt("paddingBottom") != nil { - self.paddingBottom = CGFloat(call.getInt("paddingBottom")!) + + if let y = call.getInt("y") { + self.y = CGFloat(y) / 2 } - + + if let paddingBottom = call.getInt("paddingBottom") { + self.paddingBottom = CGFloat(paddingBottom) + } + + if let zoomFactor = call.getFloat("zoomFactor") { + self.zoomFactor = CGFloat(zoomFactor) + } + self.rotateWhenOrientationChanged = call.getBool("rotateWhenOrientationChanged") ?? true self.toBack = call.getBool("toBack") ?? false self.storeToFile = call.getBool("storeToFile") ?? false self.enableZoom = call.getBool("enableZoom") ?? false - self.disableAudio = call.getBool("disableAudio") ?? false - - AVCaptureDevice.requestAccess(for: .video, completionHandler: { (granted: Bool) in - guard granted else { - call.reject("permission failed") + + + guard self.cameraController.captureSession?.isRunning ?? true else { + call.reject("camera already started") + return + } + + + self.cameraController.prepareCamera(cameraPosition: self.cameraPosition, zoomFactor: self.zoomFactor) { error in + if error != nil { + call.reject(error!.localizedDescription) return } - + DispatchQueue.main.async { - if self.cameraController.captureSession?.isRunning ?? false { - call.reject("camera already started") - } else { - self.cameraController.prepare(cameraPosition: self.cameraPosition, disableAudio: self.disableAudio) {error in - if let error = error { - print(error) - call.reject(error.localizedDescription) - return - } - let height = self.paddingBottom != nil ? self.height! - self.paddingBottom!: self.height! - self.previewView = UIView(frame: CGRect(x: self.x ?? 0, y: self.y ?? 0, width: self.width!, height: height)) - self.webView?.isOpaque = false - self.webView?.backgroundColor = UIColor.clear - self.webView?.scrollView.backgroundColor = UIColor.clear - self.webView?.superview?.addSubview(self.previewView) - if self.toBack! { - self.webView?.superview?.bringSubviewToFront(self.webView!) - } - try? self.cameraController.displayPreview(on: self.previewView) - - let frontView = self.toBack! ? self.webView : self.previewView - self.cameraController.setupGestures(target: frontView ?? self.previewView, enableZoom: self.enableZoom!) - - if self.rotateWhenOrientationChanged == true { - NotificationCenter.default.addObserver(self, selector: #selector(CameraPreview.rotated), name: UIDevice.orientationDidChangeNotification, object: nil) - } - - call.resolve() - - } + self.previewView = UIView(frame: CGRect(x: self.x, y: self.y, width: self.width, height: self.height - self.paddingBottom)) + self.webView?.isOpaque = false + self.webView?.backgroundColor = UIColor.clear + self.webView?.scrollView.backgroundColor = UIColor.clear + self.webView?.superview?.addSubview(self.previewView) + if self.toBack { + self.webView?.superview?.bringSubviewToFront(self.webView!) } + + + self.cameraController.displayPreview(on: self.previewView) + call.resolve() } - }) - + } } - + + @objc func stop(_ call: CAPPluginCall) { + guard self.cameraController.captureSession?.isRunning ?? false else { + call.reject("camera already stopped") + return; + } + + DispatchQueue.main.async { + self.cameraController.captureSession?.stopRunning() + self.previewView.removeFromSuperview() + self.webView?.isOpaque = true + call.resolve() + } + } + @objc func flip(_ call: CAPPluginCall) { do { try self.cameraController.switchCameras() @@ -119,19 +133,7 @@ public class CameraPreview: CAPPlugin { call.reject("failed to flip camera") } } - - @objc func stop(_ call: CAPPluginCall) { - DispatchQueue.main.async { - if self.cameraController.captureSession?.isRunning ?? false { - self.cameraController.captureSession?.stopRunning() - self.previewView.removeFromSuperview() - self.webView?.isOpaque = true - call.resolve() - } else { - call.reject("camera already stopped") - } - } - } + // Get user's cache directory path @objc func getTempFilePath() -> URL { let path = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask)[0] @@ -142,14 +144,13 @@ public class CameraPreview: CAPPlugin { let fileUrl=path.appendingPathComponent(fileName) return fileUrl } - + @objc func capture(_ call: CAPPluginCall) { DispatchQueue.main.async { - let quality: Int? = call.getInt("quality", 85) - + self.cameraController.captureImage { (image, error) in - + guard let image = image else { print(error ?? "Image capture error") guard let error = error else { @@ -166,7 +167,7 @@ public class CameraPreview: CAPPlugin { } else { imageData = image.jpegData(compressionQuality: CGFloat(quality!/100)) } - + if self.storeToFile == false { let imageBase64 = imageData?.base64EncodedString() call.resolve(["value": imageBase64!]) @@ -182,26 +183,26 @@ public class CameraPreview: CAPPlugin { } } } - + @objc func captureSample(_ call: CAPPluginCall) { DispatchQueue.main.async { let quality: Int? = call.getInt("quality", 85) - + self.cameraController.captureSample { image, error in guard let image = image else { print("Image capture error: \(String(describing: error))") call.reject("Image capture error: \(String(describing: error))") return } - + let imageData: Data? - if self.cameraPosition == "front" { + if self.cameraPosition == .front { let flippedImage = image.withHorizontallyFlippedOrientation() imageData = flippedImage.jpegData(compressionQuality: CGFloat(quality!/100)) } else { imageData = image.jpegData(compressionQuality: CGFloat(quality!/100)) } - + if self.storeToFile == false { let imageBase64 = imageData?.base64EncodedString() call.resolve(["value": imageBase64!]) @@ -217,7 +218,7 @@ public class CameraPreview: CAPPlugin { } } } - + @objc func getSupportedFlashModes(_ call: CAPPluginCall) { do { let supportedFlashModes = try self.cameraController.getSupportedFlashModes() @@ -226,7 +227,7 @@ public class CameraPreview: CAPPlugin { call.reject("failed to get supported flash modes") } } - + @objc func setFlashMode(_ call: CAPPluginCall) { guard let flashMode = call.getString("flashMode") else { call.reject("failed to set flash mode. required parameter flashMode is missing") @@ -256,36 +257,4 @@ public class CameraPreview: CAPPlugin { call.reject("failed to set flash mode") } } - - @objc func startRecordVideo(_ call: CAPPluginCall) { - DispatchQueue.main.async { - - let quality: Int? = call.getInt("quality", 85) - - self.cameraController.captureVideo { (image, error) in - - guard let image = image else { - print(error ?? "Image capture error") - guard let error = error else { - call.reject("Image capture error") - return - } - call.reject(error.localizedDescription) - return - } - - // self.videoUrl = image - - call.resolve(["value": image.absoluteString]) - } - } - } - - @objc func stopRecordVideo(_ call: CAPPluginCall) { - - self.cameraController.stopRecording { (_) in - - } - } - } diff --git a/src/definitions.ts b/src/definitions.ts index 1e4efe00..bb4b2643 100644 --- a/src/definitions.ts +++ b/src/definitions.ts @@ -24,16 +24,15 @@ export interface CameraPreviewOptions { storeToFile?: boolean; /** Defaults to false - Android Only - Disable automatic rotation of the image, and let the browser deal with it (keep reading on how to achieve it) */ disableExifHeaderStripping?: boolean; - /** Defaults to false - iOS only - Activate high resolution image capture so that output images are from the highest resolution possible on the device **/ - enableHighResolution?: boolean; - /** Defaults to false - Web only - Disables audio stream to prevent permission requests and output switching */ - disableAudio?: boolean; + /** Android Only - Locks device orientation when camera is showing. */ lockAndroidOrientation?: boolean; /** Defaults to false - Android and Web only. Set if camera preview can change opacity. */ enableOpacity?: boolean; /** Defaults to false - Android only. Set if camera preview will support pinch to zoom. */ enableZoom?: boolean; + /** Defaults to 1 - Zoom factor of the camera previe */ + zoomFactor?: number; } export interface CameraPreviewPictureOptions { /** The picture height, optional, default 0 (Device default) */ @@ -60,9 +59,7 @@ export interface CameraOpacityOptions { export interface CameraPreviewPlugin { start(options: CameraPreviewOptions): Promise<{}>; - startRecordVideo(options: CameraPreviewOptions): Promise<{}>; stop(): Promise<{}>; - stopRecordVideo(): Promise<{}>; capture(options: CameraPreviewPictureOptions): Promise<{ value: string }>; captureSample(options: CameraSampleOptions): Promise<{ value: string }>; getSupportedFlashModes(): Promise<{ From 30764a5b7ea01b3cf650c21ae3d5784502ab6fca Mon Sep 17 00:00:00 2001 From: Michael Wolz Date: Sat, 22 Jun 2024 16:52:05 +0200 Subject: [PATCH 05/28] refactor(ios): large refactoring --- ios/Plugin/CameraController.swift | 557 ++++++++++++------------------ ios/Plugin/Plugin.m | 2 - ios/Plugin/Plugin.swift | 288 ++++++++------- ios/Plugin/UIImage.swift | 56 +++ 4 files changed, 438 insertions(+), 465 deletions(-) create mode 100644 ios/Plugin/UIImage.swift diff --git a/ios/Plugin/CameraController.swift b/ios/Plugin/CameraController.swift index 667b77b4..7b9ff767 100644 --- a/ios/Plugin/CameraController.swift +++ b/ios/Plugin/CameraController.swift @@ -1,50 +1,98 @@ -// -// CameraController.swift -// Plugin -// -// Created by Ariel Hernandez Musa on 7/14/19. -// Copyright © 2019 Max Lynch. All rights reserved. -// - import AVFoundation import UIKit +enum CameraControllerError: Swift.Error { + case captureSessionAlreadyRunning + case captureSessionIsMissing + case inputsAreInvalid + case invalidOperation + case noCamerasAvailable + case unknown +} + +public enum CameraPosition { + case front + case rear +} + +extension CameraControllerError: LocalizedError { + public var errorDescription: String? { + switch self { + case .captureSessionAlreadyRunning: + return NSLocalizedString("Capture Session is Already Running", comment: "Capture Session Already Running") + case .captureSessionIsMissing: + return NSLocalizedString("Capture Session is Missing", comment: "Capture Session Missing") + case .inputsAreInvalid: + return NSLocalizedString("Inputs Are Invalid", comment: "Inputs Are Invalid") + case .invalidOperation: + return NSLocalizedString("Invalid Operation", comment: "invalid Operation") + case .noCamerasAvailable: + return NSLocalizedString("Failed to access device camera(s)", comment: "No Cameras Available") + case .unknown: + return NSLocalizedString("Unknown", comment: "Unknown") + + } + } +} + class CameraController: NSObject { var captureSession: AVCaptureSession? - var currentCameraPosition: CameraPosition? + var photoOutput = AVCapturePhotoOutput() + var photoCaptureCompletionBlock: ((UIImage?, Error?) -> Void)? + var sampleBufferCaptureCompletionBlock: ((UIImage?, Error?) -> Void)? + + var previewLayer = AVCaptureVideoPreviewLayer() var frontCamera: AVCaptureDevice? - var frontCameraInput: AVCaptureDeviceInput? var rearCamera: AVCaptureDevice? - var rearCameraInput: AVCaptureDeviceInput? - - var photoOutput: AVCapturePhotoOutput? - var previewLayer: AVCaptureVideoPreviewLayer? + var currentCamera: AVCaptureDevice? + var cameraInput: AVCaptureDeviceInput? var flashMode = AVCaptureDevice.FlashMode.off - - var photoCaptureCompletionBlock: ((UIImage?, Error?) -> Void)? - var sampleBufferCaptureCompletionBlock: ((UIImage?, Error?) -> Void)? - var zoomFactor: CGFloat = 1 -} -extension CameraController { - func prepareCamera(cameraPosition: CameraPosition, zoomFactor: CGFloat, completionHandler: @escaping (Error?) -> Void) { + public func prepare(cameraPosition: CameraPosition, zoomFactor: CGFloat, completionHandler: @escaping (Error?) -> Void) { // Set up capture session let captureSession = AVCaptureSession() - self.captureSession = captureSession - captureSession.beginConfiguration() captureSession.sessionPreset = AVCaptureSession.Preset.high + self.captureSession = captureSession // Set up preview layer - let previewLayer = AVCaptureVideoPreviewLayer(session: captureSession) + previewLayer.session = captureSession previewLayer.videoGravity = AVLayerVideoGravity.resizeAspectFill - self.previewLayer = previewLayer + + // Initialize front and back camera + do { + try intializeCameraDevices(forPosistion: cameraPosition, zoomFactor: zoomFactor) + try initializeCameraInput() + } catch { + completionHandler(error) + return + } + + // Configure camera output + self.photoOutput.setPreparedPhotoSettingsArray([AVCapturePhotoSettings(format: [AVVideoCodecKey: AVVideoCodecType.jpeg])], completionHandler: nil) + if captureSession.canAddOutput(self.photoOutput) { + captureSession.addOutput(self.photoOutput) + } + + captureSession.startRunning() + completionHandler(nil) + } + + /** + Initialize the available camera devices by choosing the best fit for the current iOS device + This method will set the current camera device to the one that was requested but also initializes the oposite camera for easy switching later on + */ + private func intializeCameraDevices(forPosistion cameraPosition: CameraPosition, zoomFactor: CGFloat) throws { + let deviceDiscoverySession = AVCaptureDevice.DiscoverySession(deviceTypes: [ + .builtInTripleCamera, + .builtInDualCamera, + .builtInDualWideCamera, + .builtInWideAngleCamera + ], mediaType: AVMediaType.video, position: .unspecified) - // Configure camera input - let deviceDiscoverySession = AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInTripleCamera, .builtInDualCamera, .builtInDualWideCamera, .builtInWideAngleCamera], mediaType: AVMediaType.video, position: .unspecified) if let rearCamera = deviceDiscoverySession.devices.first(where: { $0.position == .back }) { self.rearCamera = rearCamera } @@ -53,49 +101,49 @@ extension CameraController { self.frontCamera = frontCamera } - self.currentCameraPosition = cameraPosition - do { - if cameraPosition == .front, let camera = frontCamera { - self.frontCameraInput = try AVCaptureDeviceInput(device: camera) - if captureSession.canAddInput(self.frontCameraInput!) { captureSession.addInput(self.frontCameraInput!) } - } else if let camera = rearCamera { - self.rearCameraInput = try AVCaptureDeviceInput(device: camera) - if captureSession.canAddInput(self.rearCameraInput!) { captureSession.addInput(self.rearCameraInput!) } - } else { - completionHandler(CameraControllerError.noCamerasAvailable) - return - } - } catch { - completionHandler(CameraControllerError.noCamerasAvailable) - return + guard cameraPosition == .rear && rearCamera != nil || cameraPosition == .front && frontCamera != nil else { + throw CameraControllerError.noCamerasAvailable } - // Configure camera output - let photoOutput = AVCapturePhotoOutput() - photoOutput.setPreparedPhotoSettingsArray([AVCapturePhotoSettings(format: [AVVideoCodecKey: AVVideoCodecType.jpeg])], completionHandler: nil) - if captureSession.canAddOutput(photoOutput) { - captureSession.addOutput(photoOutput) - self.photoOutput = photoOutput - } + self.currentCamera = cameraPosition == .rear ? rearCamera : frontCamera + } + + /** + Initialize the camera inputs + */ + private func initializeCameraInput() throws { + guard let captureSession = self.captureSession else { throw CameraControllerError.captureSessionIsMissing } - captureSession.commitConfiguration() - captureSession.startRunning() + guard let camera = self.currentCamera else { throw CameraControllerError.noCamerasAvailable } - completionHandler(nil) + do { + let cameraInput = try AVCaptureDeviceInput(device: camera) + if captureSession.canAddInput(cameraInput) { + captureSession.addInput(cameraInput) + } + self.cameraInput = cameraInput + } catch { + throw CameraControllerError.noCamerasAvailable + } } - func displayPreview(on view: UIView) { - view.layer.insertSublayer(self.previewLayer!, at: 0) - self.previewLayer?.frame = view.frame + public func displayPreview(on view: UIView) { + view.layer.insertSublayer(self.previewLayer, at: 0) + previewLayer.frame = view.frame updateVideoOrientation() } - func updateVideoOrientation() { - // UIApplication.statusBarOrientation requires the main thread. + public func updateVideoOrientation() { assert(Thread.isMainThread) + guard let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene else { + return + } + + let interfaceOrientation = windowScene.interfaceOrientation + let videoOrientation: AVCaptureVideoOrientation - switch UIApplication.shared.statusBarOrientation { + switch interfaceOrientation { case .portrait: videoOrientation = .portrait case .landscapeLeft: @@ -105,95 +153,82 @@ extension CameraController { case .portraitUpsideDown: videoOrientation = .portraitUpsideDown case .unknown: - fallthrough + videoOrientation = .portrait @unknown default: videoOrientation = .portrait } - previewLayer?.connection?.videoOrientation = videoOrientation - photoOutput?.connections.forEach { $0.videoOrientation = videoOrientation } - } - - func setupGestures(target: UIView, enableZoom: Bool) { - setupTapGesture(target: target, selector: #selector(handleTap(_:)), delegate: self) - if enableZoom { - setupPinchGesture(target: target, selector: #selector(handlePinch(_:)), delegate: self) - } - } - - func setupTapGesture(target: UIView, selector: Selector, delegate: UIGestureRecognizerDelegate?) { - let tapGesture = UITapGestureRecognizer(target: self, action: selector) - tapGesture.delegate = delegate - target.addGestureRecognizer(tapGesture) + previewLayer.connection?.videoOrientation = videoOrientation + photoOutput.connections.forEach { $0.videoOrientation = videoOrientation } } - func setupPinchGesture(target: UIView, selector: Selector, delegate: UIGestureRecognizerDelegate?) { - let pinchGesture = UIPinchGestureRecognizer(target: self, action: selector) - pinchGesture.delegate = delegate - target.addGestureRecognizer(pinchGesture) - } - - func switchCameras() throws { - guard let currentCameraPosition = currentCameraPosition, let captureSession = self.captureSession, captureSession.isRunning else { throw CameraControllerError.captureSessionIsMissing } + public func switchCameras() throws { + guard let captureSession = self.captureSession, captureSession.isRunning else { throw CameraControllerError.captureSessionIsMissing } + + guard let device = self.currentCamera else { throw CameraControllerError.noCamerasAvailable } captureSession.beginConfiguration() func switchToFrontCamera() throws { - guard let rearCameraInput = self.rearCameraInput, captureSession.inputs.contains(rearCameraInput), + guard let cameraInput = self.cameraInput, captureSession.inputs.contains(cameraInput), let frontCamera = self.frontCamera else { throw CameraControllerError.invalidOperation } - self.frontCameraInput = try AVCaptureDeviceInput(device: frontCamera) - - captureSession.removeInput(rearCameraInput) + captureSession.removeInput(cameraInput) + + let newCameraInput = try AVCaptureDeviceInput(device: frontCamera) - if captureSession.canAddInput(self.frontCameraInput!) { - captureSession.addInput(self.frontCameraInput!) - - self.currentCameraPosition = .front + if captureSession.canAddInput(newCameraInput) { + captureSession.addInput(newCameraInput) + self.cameraInput = newCameraInput } else { throw CameraControllerError.invalidOperation } } func switchToRearCamera() throws { - guard let frontCameraInput = self.frontCameraInput, captureSession.inputs.contains(frontCameraInput), + guard let cameraInput = self.cameraInput, captureSession.inputs.contains(cameraInput), let rearCamera = self.rearCamera else { throw CameraControllerError.invalidOperation } + + captureSession.removeInput(cameraInput) + + let newCameraInput = try AVCaptureDeviceInput(device: rearCamera) - self.rearCameraInput = try AVCaptureDeviceInput(device: rearCamera) - - captureSession.removeInput(frontCameraInput) - - if captureSession.canAddInput(self.rearCameraInput!) { - captureSession.addInput(self.rearCameraInput!) - - self.currentCameraPosition = .rear - } else { throw CameraControllerError.invalidOperation } + if captureSession.canAddInput(newCameraInput) { + captureSession.addInput(newCameraInput) + } else { + throw CameraControllerError.invalidOperation + } } - switch currentCameraPosition { + switch device.position { case .front: try switchToRearCamera() - - case .rear: + case .back: try switchToFrontCamera() + case .unspecified: + return + @unknown default: + return } captureSession.commitConfiguration() } func captureImage(completion: @escaping (UIImage?, Error?) -> Void) { - guard let captureSession = captureSession, captureSession.isRunning else { completion(nil, CameraControllerError.captureSessionIsMissing); return } + guard let captureSession = captureSession, captureSession.isRunning else { + completion(nil, CameraControllerError.captureSessionIsMissing); + return + } + let settings = AVCapturePhotoSettings() - settings.flashMode = self.flashMode - self.photoOutput?.capturePhoto(with: settings, delegate: self) + self.photoOutput.capturePhoto(with: settings, delegate: self) self.photoCaptureCompletionBlock = completion } func captureSample(completion: @escaping (UIImage?, Error?) -> Void) { - guard let captureSession = captureSession, - captureSession.isRunning else { + guard let captureSession = captureSession, captureSession.isRunning else { completion(nil, CameraControllerError.captureSessionIsMissing) return } @@ -202,29 +237,13 @@ extension CameraController { } func getSupportedFlashModes() throws -> [String] { - var currentCamera: AVCaptureDevice? - switch currentCameraPosition { - case .front: - currentCamera = self.frontCamera! - case .rear: - currentCamera = self.rearCamera! - default: break - } - - guard - let device = currentCamera - else { - throw CameraControllerError.noCamerasAvailable - } + guard let device = self.currentCamera else { throw CameraControllerError.noCamerasAvailable } var supportedFlashModesAsStrings: [String] = [] if device.hasFlash { - guard let supportedFlashModes: [AVCaptureDevice.FlashMode] = self.photoOutput?.supportedFlashModes else { - throw CameraControllerError.noCamerasAvailable - } - - for flashMode in supportedFlashModes { + for flashMode in self.photoOutput.supportedFlashModes { var flashModeValue: String? + switch flashMode { case AVCaptureDevice.FlashMode.off: flashModeValue = "off" @@ -234,76 +253,54 @@ extension CameraController { flashModeValue = "auto" default: break } + if flashModeValue != nil { supportedFlashModesAsStrings.append(flashModeValue!) } } } + if device.hasTorch { supportedFlashModesAsStrings.append("torch") } + return supportedFlashModesAsStrings - } func setFlashMode(flashMode: AVCaptureDevice.FlashMode) throws { - var currentCamera: AVCaptureDevice? - switch currentCameraPosition { - case .front: - currentCamera = self.frontCamera! - case .rear: - currentCamera = self.rearCamera! - default: break - } - - guard let device = currentCamera else { - throw CameraControllerError.noCamerasAvailable - } - - guard let supportedFlashModes: [AVCaptureDevice.FlashMode] = self.photoOutput?.supportedFlashModes else { - throw CameraControllerError.invalidOperation + guard let device = self.currentCamera else { throw CameraControllerError.noCamerasAvailable } + + if !self.photoOutput.supportedFlashModes.contains(flashMode) { + return } - if supportedFlashModes.contains(flashMode) { - do { - try device.lockForConfiguration() - - if device.hasTorch && device.isTorchAvailable && device.torchMode == AVCaptureDevice.TorchMode.on { - device.torchMode = AVCaptureDevice.TorchMode.off - } - self.flashMode = flashMode - let photoSettings = AVCapturePhotoSettings() - photoSettings.flashMode = flashMode - self.photoOutput?.photoSettingsForSceneMonitoring = photoSettings - - device.unlockForConfiguration() - } catch { - throw CameraControllerError.invalidOperation + + do { + try device.lockForConfiguration() + + if device.hasTorch && device.isTorchAvailable && device.torchMode == AVCaptureDevice.TorchMode.on { + device.torchMode = AVCaptureDevice.TorchMode.off } - } else { + + let photoSettings = AVCapturePhotoSettings() + photoSettings.flashMode = flashMode + + self.flashMode = flashMode + self.photoOutput.photoSettingsForSceneMonitoring = photoSettings + + device.unlockForConfiguration() + } catch { throw CameraControllerError.invalidOperation } } func setTorchMode() throws { - var currentCamera: AVCaptureDevice? - switch currentCameraPosition { - case .front: - currentCamera = self.frontCamera! - case .rear: - currentCamera = self.rearCamera! - default: break - } - - guard - let device = currentCamera, - device.hasTorch, - device.isTorchAvailable - else { + guard let device = self.currentCamera, device.hasTorch, device.isTorchAvailable else { throw CameraControllerError.invalidOperation } do { try device.lockForConfiguration() + if device.isTorchModeSupported(AVCaptureDevice.TorchMode.on) { device.torchMode = AVCaptureDevice.TorchMode.on } else if device.isTorchModeSupported(AVCaptureDevice.TorchMode.auto) { @@ -311,11 +308,48 @@ extension CameraController { } else { device.torchMode = AVCaptureDevice.TorchMode.off } + device.unlockForConfiguration() } catch { throw CameraControllerError.invalidOperation } } + + public func setupGestures(target: UIView, enableZoom: Bool) { + setupTapGesture(target: target, selector: #selector(handleTap(_:)), delegate: self) + if enableZoom { + setupPinchGesture(target: target, selector: #selector(handlePinch(_:)), delegate: self) + } + } + + private func setupTapGesture(target: UIView, selector: Selector, delegate: UIGestureRecognizerDelegate?) { + let tapGesture = UITapGestureRecognizer(target: self, action: selector) + tapGesture.delegate = delegate + target.addGestureRecognizer(tapGesture) + } + + private func setupPinchGesture(target: UIView, selector: Selector, delegate: UIGestureRecognizerDelegate?) { + let pinchGesture = UIPinchGestureRecognizer(target: self, action: selector) + pinchGesture.delegate = delegate + target.addGestureRecognizer(pinchGesture) + } + +} + +extension CameraController: AVCapturePhotoCaptureDelegate { + public func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: (any Error)?) { + if let error = error { + self.photoCaptureCompletionBlock?(nil, error) + return + } + + guard let data = photo.fileDataRepresentation(), let image = UIImage(data: data) else { + self.photoCaptureCompletionBlock?(nil, CameraControllerError.unknown) + return + } + + self.photoCaptureCompletionBlock?(image.fixedOrientation(), nil) + } } extension CameraController: UIGestureRecognizerDelegate { @@ -323,12 +357,11 @@ extension CameraController: UIGestureRecognizerDelegate { return true } - @objc - func handleTap(_ tap: UITapGestureRecognizer) { - guard let device = self.currentCameraPosition == .rear ? rearCamera : frontCamera else { return } + @objc func handleTap(_ tap: UITapGestureRecognizer) { + guard let device = self.currentCamera else { return } let point = tap.location(in: tap.view) - let devicePoint = self.previewLayer?.captureDevicePointConverted(fromLayerPoint: point) + let devicePoint = self.previewLayer.captureDevicePointConverted(fromLayerPoint: point) do { try device.lockForConfiguration() @@ -336,13 +369,13 @@ extension CameraController: UIGestureRecognizerDelegate { let focusMode = AVCaptureDevice.FocusMode.autoFocus if device.isFocusPointOfInterestSupported && device.isFocusModeSupported(focusMode) { - device.focusPointOfInterest = CGPoint(x: CGFloat(devicePoint?.x ?? 0), y: CGFloat(devicePoint?.y ?? 0)) + device.focusPointOfInterest = CGPoint(x: CGFloat(devicePoint.x), y: CGFloat(devicePoint.y)) device.focusMode = focusMode } let exposureMode = AVCaptureDevice.ExposureMode.autoExpose if device.isExposurePointOfInterestSupported && device.isExposureModeSupported(exposureMode) { - device.exposurePointOfInterest = CGPoint(x: CGFloat(devicePoint?.x ?? 0), y: CGFloat(devicePoint?.y ?? 0)) + device.exposurePointOfInterest = CGPoint(x: CGFloat(devicePoint.x), y: CGFloat(devicePoint.y)) device.exposureMode = exposureMode } } catch { @@ -350,11 +383,12 @@ extension CameraController: UIGestureRecognizerDelegate { } } - @objc - private func handlePinch(_ pinch: UIPinchGestureRecognizer) { - guard let device = self.currentCameraPosition == .rear ? rearCamera : frontCamera else { return } + @objc private func handlePinch(_ pinch: UIPinchGestureRecognizer) { + guard let device = self.currentCamera else { return } - func minMaxZoom(_ factor: CGFloat) -> CGFloat { return max(1.0, min(factor, device.activeFormat.videoMaxZoomFactor)) } + func minMaxZoom(_ factor: CGFloat) -> CGFloat { + return max(1.0, min(factor, device.activeFormat.videoMaxZoomFactor)) + } func update(scale factor: CGFloat) { do { @@ -378,160 +412,3 @@ extension CameraController: UIGestureRecognizerDelegate { } } } - -extension CameraController: AVCapturePhotoCaptureDelegate { - public func photoOutput(_ captureOutput: AVCapturePhotoOutput, didFinishProcessingPhoto photoSampleBuffer: CMSampleBuffer?, previewPhoto previewPhotoSampleBuffer: CMSampleBuffer?, - resolvedSettings: AVCaptureResolvedPhotoSettings, bracketSettings: AVCaptureBracketedStillImageSettings?, error: Swift.Error?) { - if let error = error { - self.photoCaptureCompletionBlock?(nil, error) - } else if - let buffer = photoSampleBuffer, - let data = AVCapturePhotoOutput.jpegPhotoDataRepresentation(forJPEGSampleBuffer: buffer, previewPhotoSampleBuffer: nil), - let image = UIImage(data: data) { - self.photoCaptureCompletionBlock?(image.fixedOrientation(), nil) - } else { - self.photoCaptureCompletionBlock?(nil, CameraControllerError.unknown) - } - } -} - -extension CameraController: AVCaptureVideoDataOutputSampleBufferDelegate { - func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) { - guard let completion = sampleBufferCaptureCompletionBlock else { return } - - guard let imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else { - completion(nil, CameraControllerError.unknown) - return - } - - CVPixelBufferLockBaseAddress(imageBuffer, .readOnly) - defer { CVPixelBufferUnlockBaseAddress(imageBuffer, .readOnly) } - - let baseAddress = CVPixelBufferGetBaseAddress(imageBuffer) - let bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer) - let width = CVPixelBufferGetWidth(imageBuffer) - let height = CVPixelBufferGetHeight(imageBuffer) - let colorSpace = CGColorSpaceCreateDeviceRGB() - let bitmapInfo: UInt32 = CGBitmapInfo.byteOrder32Little.rawValue | - CGImageAlphaInfo.premultipliedFirst.rawValue - - let context = CGContext( - data: baseAddress, - width: width, - height: height, - bitsPerComponent: 8, - bytesPerRow: bytesPerRow, - space: colorSpace, - bitmapInfo: bitmapInfo - ) - - guard let cgImage = context?.makeImage() else { - completion(nil, CameraControllerError.unknown) - return - } - - let image = UIImage(cgImage: cgImage) - completion(image.fixedOrientation(), nil) - - sampleBufferCaptureCompletionBlock = nil - } -} - -enum CameraControllerError: Swift.Error { - case captureSessionAlreadyRunning - case captureSessionIsMissing - case inputsAreInvalid - case invalidOperation - case noCamerasAvailable - case unknown -} - -public enum CameraPosition { - case front - case rear -} - -extension CameraControllerError: LocalizedError { - public var errorDescription: String? { - switch self { - case .captureSessionAlreadyRunning: - return NSLocalizedString("Capture Session is Already Running", comment: "Capture Session Already Running") - case .captureSessionIsMissing: - return NSLocalizedString("Capture Session is Missing", comment: "Capture Session Missing") - case .inputsAreInvalid: - return NSLocalizedString("Inputs Are Invalid", comment: "Inputs Are Invalid") - case .invalidOperation: - return NSLocalizedString("Invalid Operation", comment: "invalid Operation") - case .noCamerasAvailable: - return NSLocalizedString("Failed to access device camera(s)", comment: "No Cameras Available") - case .unknown: - return NSLocalizedString("Unknown", comment: "Unknown") - - } - } -} - -extension UIImage { - func fixedOrientation() -> UIImage? { - - guard imageOrientation != UIImage.Orientation.up else { - // This is default orientation, don't need to do anything - return self.copy() as? UIImage - } - - guard let cgImage = self.cgImage else { - // CGImage is not available - return nil - } - - guard let colorSpace = cgImage.colorSpace, let ctx = CGContext(data: nil, width: Int(size.width), height: Int(size.height), bitsPerComponent: cgImage.bitsPerComponent, bytesPerRow: 0, space: colorSpace, bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue) else { - return nil // Not able to create CGContext - } - - var transform: CGAffineTransform = CGAffineTransform.identity - switch imageOrientation { - case .down, .downMirrored: - transform = transform.translatedBy(x: size.width, y: size.height) - transform = transform.rotated(by: CGFloat.pi) - print("down") - break - case .left, .leftMirrored: - transform = transform.translatedBy(x: size.width, y: 0) - transform = transform.rotated(by: CGFloat.pi / 2.0) - print("left") - break - case .right, .rightMirrored: - transform = transform.translatedBy(x: 0, y: size.height) - transform = transform.rotated(by: CGFloat.pi / -2.0) - print("right") - break - case .up, .upMirrored: - break - } - - // Flip image one more time if needed to, this is to prevent flipped image - switch imageOrientation { - case .upMirrored, .downMirrored: - transform.translatedBy(x: size.width, y: 0) - transform.scaledBy(x: -1, y: 1) - break - case .leftMirrored, .rightMirrored: - transform.translatedBy(x: size.height, y: 0) - transform.scaledBy(x: -1, y: 1) - case .up, .down, .left, .right: - break - } - - ctx.concatenate(transform) - - switch imageOrientation { - case .left, .leftMirrored, .right, .rightMirrored: - ctx.draw(self.cgImage!, in: CGRect(x: 0, y: 0, width: size.height, height: size.width)) - default: - ctx.draw(self.cgImage!, in: CGRect(x: 0, y: 0, width: size.width, height: size.height)) - break - } - guard let newCGImage = ctx.makeImage() else { return nil } - return UIImage.init(cgImage: newCGImage, scale: 1, orientation: .up) - } -} diff --git a/ios/Plugin/Plugin.m b/ios/Plugin/Plugin.m index 06fb55e1..b504e03e 100644 --- a/ios/Plugin/Plugin.m +++ b/ios/Plugin/Plugin.m @@ -11,6 +11,4 @@ CAP_PLUGIN_METHOD(flip, CAPPluginReturnPromise); CAP_PLUGIN_METHOD(getSupportedFlashModes, CAPPluginReturnPromise); CAP_PLUGIN_METHOD(setFlashMode, CAPPluginReturnPromise); - CAP_PLUGIN_METHOD(startRecordVideo, CAPPluginReturnPromise); - CAP_PLUGIN_METHOD(stopRecordVideo, CAPPluginReturnPromise); ) diff --git a/ios/Plugin/Plugin.swift b/ios/Plugin/Plugin.swift index fa36c264..090ef7c0 100644 --- a/ios/Plugin/Plugin.swift +++ b/ios/Plugin/Plugin.swift @@ -8,110 +8,48 @@ import AVFoundation @objc(CameraPreview) public class CameraPreview: CAPPlugin { let cameraController = CameraController() - var previewView: UIView! var cameraPosition: CameraPosition = .rear var x: CGFloat = 0.0 var y: CGFloat = 0.0 - var width: CGFloat = UIScreen.main.bounds.size.width - var height: CGFloat = UIScreen.main.bounds.size.height + var previewView: UIView! + var previewWidth: CGFloat = UIScreen.main.bounds.size.width + var previewHeight: CGFloat = UIScreen.main.bounds.size.height var paddingBottom: CGFloat = 0 - var rotateWhenOrientationChanged: Bool? - var toBack: Bool = false - var storeToFile: Bool? - var enableZoom: Bool? + var rotateWhenOrientationChanged = true + var toBack = false + var storeToFile = false + var enableZoom = false var zoomFactor: CGFloat = 1.0 - private func hasCameraPermission() -> Bool { - let status = AVCaptureDevice.authorizationStatus(for: AVMediaType.video) - if (status == AVAuthorizationStatus.authorized) { - return true - } - return false - } - - @objc func rotated() { - let height = self.height - self.paddingBottom - - if UIApplication.shared.statusBarOrientation.isLandscape { - self.previewView.frame = CGRect(x: self.y, y: self.x, width: max(height, self.width), height: min(height, self.width)) - self.cameraController.previewLayer?.frame = self.previewView.frame - } - - if UIApplication.shared.statusBarOrientation.isPortrait { - if self.previewView != nil && self.x != nil && self.y != nil && self.width != nil && self.height != nil { - self.previewView.frame = CGRect(x: self.x, y: self.y, width: min(height, self.width), height: max(height, self.width)) - } - self.cameraController.previewLayer?.frame = self.previewView.frame - } - - cameraController.updateVideoOrientation() - } - - @objc func start(_ call: CAPPluginCall) { - if (call.getString("position") == "front") { - self.cameraPosition = .front - } - - if let width = call.getInt("width") { - self.width = CGFloat(width) - } - - if let height = call.getInt("height") { - self.height = CGFloat(height) - } - - if let x = call.getInt("x") { - self.x = CGFloat(x) / 2 - } - - if let y = call.getInt("y") { - self.y = CGFloat(y) / 2 - } - - if let paddingBottom = call.getInt("paddingBottom") { - self.paddingBottom = CGFloat(paddingBottom) - } - - if let zoomFactor = call.getFloat("zoomFactor") { - self.zoomFactor = CGFloat(zoomFactor) - } - - self.rotateWhenOrientationChanged = call.getBool("rotateWhenOrientationChanged") ?? true - self.toBack = call.getBool("toBack") ?? false - self.storeToFile = call.getBool("storeToFile") ?? false - self.enableZoom = call.getBool("enableZoom") ?? false - - + /** + Start the camera preview in a new UIView + */ + @objc public func start(_ call: CAPPluginCall) { + // Initialize settings provided via API call + initializePluginSettings(call: call) + guard self.cameraController.captureSession?.isRunning ?? true else { call.reject("camera already started") return } - - self.cameraController.prepareCamera(cameraPosition: self.cameraPosition, zoomFactor: self.zoomFactor) { error in - if error != nil { - call.reject(error!.localizedDescription) + self.cameraController.prepare(cameraPosition: self.cameraPosition, zoomFactor: self.zoomFactor) { error in + if let error = error { + call.reject(error.localizedDescription) return } DispatchQueue.main.async { - self.previewView = UIView(frame: CGRect(x: self.x, y: self.y, width: self.width, height: self.height - self.paddingBottom)) - self.webView?.isOpaque = false - self.webView?.backgroundColor = UIColor.clear - self.webView?.scrollView.backgroundColor = UIColor.clear - self.webView?.superview?.addSubview(self.previewView) - if self.toBack { - self.webView?.superview?.bringSubviewToFront(self.webView!) - } - - - self.cameraController.displayPreview(on: self.previewView) + self.displayCameraPreviewView() call.resolve() } } } - @objc func stop(_ call: CAPPluginCall) { + /** + Stops any currently running capture session + */ + @objc public func stop(_ call: CAPPluginCall) { guard self.cameraController.captureSession?.isRunning ?? false else { call.reject("camera already stopped") return; @@ -125,32 +63,14 @@ public class CameraPreview: CAPPlugin { } } - @objc func flip(_ call: CAPPluginCall) { - do { - try self.cameraController.switchCameras() - call.resolve() - } catch { - call.reject("failed to flip camera") - } - } - - // Get user's cache directory path - @objc func getTempFilePath() -> URL { - let path = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask)[0] - let identifier = UUID() - let randomIdentifier = identifier.uuidString.replacingOccurrences(of: "-", with: "") - let finalIdentifier = String(randomIdentifier.prefix(8)) - let fileName="cpcp_capture_"+finalIdentifier+".jpg" - let fileUrl=path.appendingPathComponent(fileName) - return fileUrl - } - + /** + Capture a photo with the currently active capture device + */ @objc func capture(_ call: CAPPluginCall) { DispatchQueue.main.async { - let quality: Int? = call.getInt("quality", 85) + let quality: Int = call.getInt("quality", 85) self.cameraController.captureImage { (image, error) in - guard let image = image else { print(error ?? "Image capture error") guard let error = error else { @@ -160,12 +80,13 @@ public class CameraPreview: CAPPlugin { call.reject(error.localizedDescription) return } + let imageData: Data? - if self.cameraController.currentCameraPosition == .front { + if self.cameraController.currentCamera?.position == .front { let flippedImage = image.withHorizontallyFlippedOrientation() - imageData = flippedImage.jpegData(compressionQuality: CGFloat(quality!/100)) + imageData = flippedImage.jpegData(compressionQuality: CGFloat(quality / 100)) } else { - imageData = image.jpegData(compressionQuality: CGFloat(quality!/100)) + imageData = image.jpegData(compressionQuality: CGFloat(quality / 100)) } if self.storeToFile == false { @@ -173,7 +94,7 @@ public class CameraPreview: CAPPlugin { call.resolve(["value": imageBase64!]) } else { do { - let fileUrl=self.getTempFilePath() + let fileUrl = self.getTempFilePath() try imageData?.write(to: fileUrl) call.resolve(["value": fileUrl.absoluteString]) } catch { @@ -184,9 +105,21 @@ public class CameraPreview: CAPPlugin { } } + @objc public func flip(_ call: CAPPluginCall) { + do { + try self.cameraController.switchCameras() + call.resolve() + } catch { + call.reject("failed to flip camera") + } + } + + /** + Captures a sample image from the video stream. + */ @objc func captureSample(_ call: CAPPluginCall) { DispatchQueue.main.async { - let quality: Int? = call.getInt("quality", 85) + let quality: Int = call.getInt("quality", 85) self.cameraController.captureSample { image, error in guard let image = image else { @@ -198,9 +131,9 @@ public class CameraPreview: CAPPlugin { let imageData: Data? if self.cameraPosition == .front { let flippedImage = image.withHorizontallyFlippedOrientation() - imageData = flippedImage.jpegData(compressionQuality: CGFloat(quality!/100)) + imageData = flippedImage.jpegData(compressionQuality: CGFloat(quality / 100)) } else { - imageData = image.jpegData(compressionQuality: CGFloat(quality!/100)) + imageData = image.jpegData(compressionQuality: CGFloat(quality / 100)) } if self.storeToFile == false { @@ -219,6 +152,9 @@ public class CameraPreview: CAPPlugin { } } + /** + Return an array of supported flash modes of the currently active capture device + */ @objc func getSupportedFlashModes(_ call: CAPPluginCall) { do { let supportedFlashModes = try self.cameraController.getSupportedFlashModes() @@ -228,22 +164,27 @@ public class CameraPreview: CAPPlugin { } } + /** + Set the flash mode for the currently active capture device + */ @objc func setFlashMode(_ call: CAPPluginCall) { guard let flashMode = call.getString("flashMode") else { call.reject("failed to set flash mode. required parameter flashMode is missing") return } + + var flashModeAsEnum: AVCaptureDevice.FlashMode? + switch flashMode { + case "off": + flashModeAsEnum = AVCaptureDevice.FlashMode.off + case "on": + flashModeAsEnum = AVCaptureDevice.FlashMode.on + case "auto": + flashModeAsEnum = AVCaptureDevice.FlashMode.auto + default: break + } + do { - var flashModeAsEnum: AVCaptureDevice.FlashMode? - switch flashMode { - case "off": - flashModeAsEnum = AVCaptureDevice.FlashMode.off - case "on": - flashModeAsEnum = AVCaptureDevice.FlashMode.on - case "auto": - flashModeAsEnum = AVCaptureDevice.FlashMode.auto - default: break - } if flashModeAsEnum != nil { try self.cameraController.setFlashMode(flashMode: flashModeAsEnum!) } else if flashMode == "torch" { @@ -252,9 +193,110 @@ public class CameraPreview: CAPPlugin { call.reject("Flash Mode not supported") return } + call.resolve() } catch { call.reject("failed to set flash mode") } } + + /** + Helper method for initializing the plugin settings based on the Capacitor call + */ + private func initializePluginSettings(call: CAPPluginCall) { + if call.getString("position") == "front" { + self.cameraPosition = .front + } + + if let width = call.getInt("width") { + self.previewWidth = CGFloat(width) + } + + if let height = call.getInt("height") { + self.previewHeight = CGFloat(height) + } + + if let x = call.getInt("x") { + self.x = CGFloat(x) / 2 + } + + if let y = call.getInt("y") { + self.y = CGFloat(y) / 2 + } + + if let paddingBottom = call.getInt("paddingBottom") { + self.paddingBottom = CGFloat(paddingBottom) + } + + if let zoomFactor = call.getFloat("zoomFactor") { + self.zoomFactor = CGFloat(zoomFactor) + } + + self.rotateWhenOrientationChanged = call.getBool("rotateWhenOrientationChanged") ?? true + + self.toBack = call.getBool("toBack") ?? false + + self.storeToFile = call.getBool("storeToFile") ?? false + + self.enableZoom = call.getBool("enableZoom") ?? false + } + + /** + Displays the camera preview view in the UI + */ + private func displayCameraPreviewView() { + self.previewView = UIView(frame: CGRect(x: self.x, y: self.y, width: self.previewWidth, height: self.previewHeight - self.paddingBottom)) + self.webView?.isOpaque = false + self.webView?.backgroundColor = UIColor.clear + self.webView?.scrollView.backgroundColor = UIColor.clear + self.webView?.superview?.addSubview(self.previewView) + + if self.toBack { + self.webView?.superview?.bringSubviewToFront(self.webView!) + } + + if self.rotateWhenOrientationChanged { + NotificationCenter.default.addObserver(self, selector: #selector(CameraPreview.rotated), name: UIDevice.orientationDidChangeNotification, object: nil) + } + + self.cameraController.displayPreview(on: self.previewView) + + let frontView = self.toBack ? self.webView : self.previewView + self.cameraController.setupGestures(target: frontView ?? self.previewView, enableZoom: self.enableZoom) + } + + /** + Handler funciton for updating the previewLayer frame based on plugin settings and the current device orientation + */ + @objc private func rotated() { + guard let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene else { + return + } + + let interfaceOrientation = windowScene.interfaceOrientation + let height = self.previewHeight - self.paddingBottom + + if interfaceOrientation.isLandscape { + previewView.frame = CGRect(x: self.y, y: self.x, width: max(height, self.previewWidth), height: min(height, self.previewWidth)) + cameraController.previewLayer.frame = previewView.frame + } else if interfaceOrientation.isPortrait { + previewView.frame = CGRect(x: self.x, y: self.y, width: min(height, self.previewWidth), height: max(height, self.previewWidth)) + cameraController.previewLayer.frame = previewView.frame + } + + cameraController.updateVideoOrientation() + } + + /** + Get user's cache directory path + */ + private func getTempFilePath() -> URL { + let path = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask)[0] + let randomIdentifier = UUID().uuidString.replacingOccurrences(of: "-", with: "") + let finalIdentifier = String(randomIdentifier.prefix(8)) + let fileName="cpcp_capture_"+finalIdentifier+".jpg" + let fileUrl=path.appendingPathComponent(fileName) + + return fileUrl + } } diff --git a/ios/Plugin/UIImage.swift b/ios/Plugin/UIImage.swift new file mode 100644 index 00000000..0596552c --- /dev/null +++ b/ios/Plugin/UIImage.swift @@ -0,0 +1,56 @@ +extension UIImage { + func fixedOrientation() -> UIImage? { + guard imageOrientation != UIImage.Orientation.up else { + // This is default orientation, don't need to do anything + return self.copy() as? UIImage + } + + guard let cgImage = self.cgImage else { + // CGImage is not available + return nil + } + + guard let colorSpace = cgImage.colorSpace, let ctx = CGContext(data: nil, width: Int(size.width), height: Int(size.height), bitsPerComponent: cgImage.bitsPerComponent, bytesPerRow: 0, space: colorSpace, bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue) else { + // Not able to create CGContext + return nil + } + + var transform: CGAffineTransform = CGAffineTransform.identity + + switch imageOrientation { + case .down, .downMirrored: + transform = transform.translatedBy(x: size.width, y: size.height) + transform = transform.rotated(by: CGFloat.pi) + print("down") + break + case .left, .leftMirrored: + transform = transform.translatedBy(x: size.width, y: 0) + transform = transform.rotated(by: CGFloat.pi / 2.0) + print("left") + break + case .right, .rightMirrored: + transform = transform.translatedBy(x: 0, y: size.height) + transform = transform.rotated(by: CGFloat.pi / -2.0) + print("right") + break + case .up, .upMirrored: + break + @unknown default: + break + } + + ctx.concatenate(transform) + + switch imageOrientation { + case .left, .leftMirrored, .right, .rightMirrored: + ctx.draw(self.cgImage!, in: CGRect(x: 0, y: 0, width: size.height, height: size.width)) + default: + ctx.draw(self.cgImage!, in: CGRect(x: 0, y: 0, width: size.width, height: size.height)) + break + } + + guard let newCGImage = ctx.makeImage() else { return nil } + + return UIImage.init(cgImage: newCGImage, scale: 1, orientation: .up) + } +} From f0fea9a2158e20d8224938aa5c1774fb9c0614db Mon Sep 17 00:00:00 2001 From: Michael Wolz Date: Sat, 22 Jun 2024 17:58:33 +0200 Subject: [PATCH 06/28] fix(ios): auto focus / zoom level --- ios/Plugin/CameraController.swift | 44 ++++++++++++++++++++++--------- ios/Plugin/Plugin.swift | 11 +++----- src/definitions.ts | 10 +++---- 3 files changed, 39 insertions(+), 26 deletions(-) diff --git a/ios/Plugin/CameraController.swift b/ios/Plugin/CameraController.swift index 7b9ff767..f9adb9fe 100644 --- a/ios/Plugin/CameraController.swift +++ b/ios/Plugin/CameraController.swift @@ -52,7 +52,7 @@ class CameraController: NSObject { var flashMode = AVCaptureDevice.FlashMode.off var zoomFactor: CGFloat = 1 - public func prepare(cameraPosition: CameraPosition, zoomFactor: CGFloat, completionHandler: @escaping (Error?) -> Void) { + public func prepare(cameraPosition: CameraPosition, completionHandler: @escaping (Error?) -> Void) { // Set up capture session let captureSession = AVCaptureSession() captureSession.sessionPreset = AVCaptureSession.Preset.high @@ -78,26 +78,46 @@ class CameraController: NSObject { } captureSession.startRunning() - completionHandler(nil) + + // Lastly setting the video zoom factor + do { + try self.currentCamera?.lockForConfiguration() + self.currentCamera?.videoZoomFactor = self.zoomFactor + self.currentCamera?.exposureMode = .continuousAutoExposure + self.currentCamera?.focusMode = .continuousAutoFocus + self.currentCamera?.unlockForConfiguration() + completionHandler(nil) + } catch { + completionHandler(error) + } + } + + public func stop() { + self.captureSession?.stopRunning() } /** - Initialize the available camera devices by choosing the best fit for the current iOS device + Initialize the available camera devices by choosing the best fit for the current iOS device. + This method will set the current camera device to the one that was requested but also initializes the oposite camera for easy switching later on + This will also set up virtual devices supporting ultra wide angle and better auto focus. For this to work the zoom factor is set to 2. This is done in + order to get the best available focus mode even when beeing super close to the object that is trying to get focused. + This resolves several issues with newer iPhones having focus issues. */ private func intializeCameraDevices(forPosistion cameraPosition: CameraPosition, zoomFactor: CGFloat) throws { - let deviceDiscoverySession = AVCaptureDevice.DiscoverySession(deviceTypes: [ - .builtInTripleCamera, - .builtInDualCamera, - .builtInDualWideCamera, - .builtInWideAngleCamera - ], mediaType: AVMediaType.video, position: .unspecified) - - if let rearCamera = deviceDiscoverySession.devices.first(where: { $0.position == .back }) { + if let rearCamera = AVCaptureDevice.default(.builtInTripleCamera, for: .video, position: .back) { + self.zoomFactor = 2 + self.rearCamera = rearCamera + } else if let rearCamera = AVCaptureDevice.default(.builtInDualCamera, for: .video, position: .back) { + self.rearCamera = rearCamera + } else if let rearCamera = AVCaptureDevice.default(.builtInDualWideCamera, for: .video, position: .back) { + self.zoomFactor = 2 self.rearCamera = rearCamera + } else { + self.rearCamera = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: .back) } - if let frontCamera = deviceDiscoverySession.devices.first(where: { $0.position == .front }) { + if let frontCamera = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: .front) { self.frontCamera = frontCamera } diff --git a/ios/Plugin/Plugin.swift b/ios/Plugin/Plugin.swift index 090ef7c0..8c35d582 100644 --- a/ios/Plugin/Plugin.swift +++ b/ios/Plugin/Plugin.swift @@ -19,7 +19,6 @@ public class CameraPreview: CAPPlugin { var toBack = false var storeToFile = false var enableZoom = false - var zoomFactor: CGFloat = 1.0 /** Start the camera preview in a new UIView @@ -28,12 +27,12 @@ public class CameraPreview: CAPPlugin { // Initialize settings provided via API call initializePluginSettings(call: call) - guard self.cameraController.captureSession?.isRunning ?? true else { + if let captureSession = self.cameraController.captureSession, captureSession.isRunning { call.reject("camera already started") return } - self.cameraController.prepare(cameraPosition: self.cameraPosition, zoomFactor: self.zoomFactor) { error in + self.cameraController.prepare(cameraPosition: self.cameraPosition) { error in if let error = error { call.reject(error.localizedDescription) return @@ -56,7 +55,7 @@ public class CameraPreview: CAPPlugin { } DispatchQueue.main.async { - self.cameraController.captureSession?.stopRunning() + self.cameraController.stop() self.previewView.removeFromSuperview() self.webView?.isOpaque = true call.resolve() @@ -228,10 +227,6 @@ public class CameraPreview: CAPPlugin { self.paddingBottom = CGFloat(paddingBottom) } - if let zoomFactor = call.getFloat("zoomFactor") { - self.zoomFactor = CGFloat(zoomFactor) - } - self.rotateWhenOrientationChanged = call.getBool("rotateWhenOrientationChanged") ?? true self.toBack = call.getBool("toBack") ?? false diff --git a/src/definitions.ts b/src/definitions.ts index bb4b2643..afe4e2ca 100644 --- a/src/definitions.ts +++ b/src/definitions.ts @@ -24,24 +24,22 @@ export interface CameraPreviewOptions { storeToFile?: boolean; /** Defaults to false - Android Only - Disable automatic rotation of the image, and let the browser deal with it (keep reading on how to achieve it) */ disableExifHeaderStripping?: boolean; - /** Android Only - Locks device orientation when camera is showing. */ lockAndroidOrientation?: boolean; /** Defaults to false - Android and Web only. Set if camera preview can change opacity. */ enableOpacity?: boolean; /** Defaults to false - Android only. Set if camera preview will support pinch to zoom. */ enableZoom?: boolean; - /** Defaults to 1 - Zoom factor of the camera previe */ - zoomFactor?: number; } export interface CameraPreviewPictureOptions { /** The picture height, optional, default 0 (Device default) */ height?: number; /** The picture width, optional, default 0 (Device default) */ width?: number; - /** The picture quality, 0 - 100, default 85 on `iOS/Android`. - * - * If left undefined, the `web` implementation will export a PNG, otherwise a JPEG will be generated */ + /** + * The picture quality, 0 - 100, default 85 on `iOS/Android`. + * If left undefined, the `web` implementation will export a PNG, otherwise a JPEG will be generated + */ quality?: number; } From 52f3a6c301fc4864a9396a5e7374b88b5991b5fc Mon Sep 17 00:00:00 2001 From: Michael Wolz Date: Mon, 24 Jun 2024 09:56:05 +0200 Subject: [PATCH 07/28] chore: clean up and documentation --- ios/Plugin/CameraController.swift | 22 ++++++++++++---------- ios/Plugin/Plugin.m | 2 ++ ios/Plugin/Plugin.swift | 8 ++++++++ src/definitions.ts | 24 +++++++++++++++++++----- 4 files changed, 41 insertions(+), 15 deletions(-) diff --git a/ios/Plugin/CameraController.swift b/ios/Plugin/CameraController.swift index f9adb9fe..11008967 100644 --- a/ios/Plugin/CameraController.swift +++ b/ios/Plugin/CameraController.swift @@ -64,7 +64,7 @@ class CameraController: NSObject { // Initialize front and back camera do { - try intializeCameraDevices(forPosistion: cameraPosition, zoomFactor: zoomFactor) + try initializeCameraDevices(forPosition: cameraPosition) try initializeCameraInput() } catch { completionHandler(error) @@ -84,7 +84,7 @@ class CameraController: NSObject { try self.currentCamera?.lockForConfiguration() self.currentCamera?.videoZoomFactor = self.zoomFactor self.currentCamera?.exposureMode = .continuousAutoExposure - self.currentCamera?.focusMode = .continuousAutoFocus + self.currentCamera?.focusMode = .continuousAutoFocus self.currentCamera?.unlockForConfiguration() completionHandler(nil) } catch { @@ -97,14 +97,16 @@ class CameraController: NSObject { } /** - Initialize the available camera devices by choosing the best fit for the current iOS device. + Initializes the available camera devices by selecting the best fit for the current iOS device. - This method will set the current camera device to the one that was requested but also initializes the oposite camera for easy switching later on - This will also set up virtual devices supporting ultra wide angle and better auto focus. For this to work the zoom factor is set to 2. This is done in - order to get the best available focus mode even when beeing super close to the object that is trying to get focused. - This resolves several issues with newer iPhones having focus issues. + This method sets the current camera device to the requested one and also initializes the opposite camera for easy switching later. + It configures virtual devices supporting ultra-wide angle and better autofocus to address several focus issues observed with newer iPhones. + + - Parameters: + - cameraPosition: The position of the camera to initialize (front or rear). + - Throws: `CameraControllerError.noCamerasAvailable` if no suitable camera is available. */ - private func intializeCameraDevices(forPosistion cameraPosition: CameraPosition, zoomFactor: CGFloat) throws { + private func initializeCameraDevices(forPosition cameraPosition: CameraPosition) throws { if let rearCamera = AVCaptureDevice.default(.builtInTripleCamera, for: .video, position: .back) { self.zoomFactor = 2 self.rearCamera = rearCamera @@ -387,13 +389,13 @@ extension CameraController: UIGestureRecognizerDelegate { try device.lockForConfiguration() defer { device.unlockForConfiguration() } - let focusMode = AVCaptureDevice.FocusMode.autoFocus + let focusMode = AVCaptureDevice.FocusMode.continuousAutoFocus if device.isFocusPointOfInterestSupported && device.isFocusModeSupported(focusMode) { device.focusPointOfInterest = CGPoint(x: CGFloat(devicePoint.x), y: CGFloat(devicePoint.y)) device.focusMode = focusMode } - let exposureMode = AVCaptureDevice.ExposureMode.autoExpose + let exposureMode = AVCaptureDevice.ExposureMode.continuousAutoExposure if device.isExposurePointOfInterestSupported && device.isExposureModeSupported(exposureMode) { device.exposurePointOfInterest = CGPoint(x: CGFloat(devicePoint.x), y: CGFloat(devicePoint.y)) device.exposureMode = exposureMode diff --git a/ios/Plugin/Plugin.m b/ios/Plugin/Plugin.m index b504e03e..06fb55e1 100644 --- a/ios/Plugin/Plugin.m +++ b/ios/Plugin/Plugin.m @@ -11,4 +11,6 @@ CAP_PLUGIN_METHOD(flip, CAPPluginReturnPromise); CAP_PLUGIN_METHOD(getSupportedFlashModes, CAPPluginReturnPromise); CAP_PLUGIN_METHOD(setFlashMode, CAPPluginReturnPromise); + CAP_PLUGIN_METHOD(startRecordVideo, CAPPluginReturnPromise); + CAP_PLUGIN_METHOD(stopRecordVideo, CAPPluginReturnPromise); ) diff --git a/ios/Plugin/Plugin.swift b/ios/Plugin/Plugin.swift index 8c35d582..073b051f 100644 --- a/ios/Plugin/Plugin.swift +++ b/ios/Plugin/Plugin.swift @@ -199,6 +199,14 @@ public class CameraPreview: CAPPlugin { } } + @objc func startRecordVideo(_ call: CAPPluginCall) { + call.reject("Method not implemented on iOS platform") + } + + @objc func stopRecordVideo(_ call: CAPPluginCall) { + call.reject("Method not implemented on iOS platform") + } + /** Helper method for initializing the plugin settings based on the Capacitor call */ diff --git a/src/definitions.ts b/src/definitions.ts index afe4e2ca..b0d20b89 100644 --- a/src/definitions.ts +++ b/src/definitions.ts @@ -24,11 +24,15 @@ export interface CameraPreviewOptions { storeToFile?: boolean; /** Defaults to false - Android Only - Disable automatic rotation of the image, and let the browser deal with it (keep reading on how to achieve it) */ disableExifHeaderStripping?: boolean; + /** Defaults to false - iOS only - Activate high resolution image capture so that output images are from the highest resolution possible on the device **/ + enableHighResolution?: boolean; + /** Defaults to false - Web only - Disables audio stream to prevent permission requests and output switching */ + disableAudio?: boolean; /** Android Only - Locks device orientation when camera is showing. */ lockAndroidOrientation?: boolean; /** Defaults to false - Android and Web only. Set if camera preview can change opacity. */ enableOpacity?: boolean; - /** Defaults to false - Android only. Set if camera preview will support pinch to zoom. */ + /** Defaults to false - Android and iOS only. Set if camera preview will support pinch to zoom. */ enableZoom?: boolean; } export interface CameraPreviewPictureOptions { @@ -36,7 +40,7 @@ export interface CameraPreviewPictureOptions { height?: number; /** The picture width, optional, default 0 (Device default) */ width?: number; - /** + /** * The picture quality, 0 - 100, default 85 on `iOS/Android`. * If left undefined, the `web` implementation will export a PNG, otherwise a JPEG will be generated */ @@ -56,14 +60,24 @@ export interface CameraOpacityOptions { } export interface CameraPreviewPlugin { + /** Starts the camera preview instance */ start(options: CameraPreviewOptions): Promise<{}>; + /** Stops the camera preview instance */ stop(): Promise<{}>; + /** Captures a picture from the camera preview */ capture(options: CameraPreviewPictureOptions): Promise<{ value: string }>; + /** Captures a sample image from the video stream - Android / iOS only */ captureSample(options: CameraSampleOptions): Promise<{ value: string }>; - getSupportedFlashModes(): Promise<{ - result: CameraPreviewFlashMode[]; - }>; + /** Get the flash modes supported by the camera device currently started */ + getSupportedFlashModes(): Promise<{ result: CameraPreviewFlashMode[] }>; + /** Set the flash mode */ setFlashMode(options: { flashMode: CameraPreviewFlashMode | string }): Promise; + /** Switch between rear and front camera - Android / iOS only */ flip(): Promise; + /** Changes the opacity of the shown camera preview - Android / Web only */ setOpacity(options: CameraOpacityOptions): Promise<{}>; + /** Start recording a video from the current camera preview - Android only */ + startRecordVideo(options: CameraPreviewOptions): Promise<{}>; + /** Stop recording a video from the current camera preview - Android only */ + stopRecordVideo(): Promise<{}>; } From 55952568bf68b827333e64fc871c2f1e6c85c709 Mon Sep 17 00:00:00 2001 From: Michael Wolz Date: Mon, 24 Jun 2024 11:42:49 +0200 Subject: [PATCH 08/28] fix: re-enable high resolution output for iOS --- README.md | 44 ++++++++++----------- ios/Plugin/CameraController.swift | 8 ++-- ios/Plugin/Plugin.swift | 64 ++++++++++++++++++++++++------- 3 files changed, 76 insertions(+), 40 deletions(-) diff --git a/README.md b/README.md index cc71a228..0adce8f0 100644 --- a/README.md +++ b/README.md @@ -85,23 +85,23 @@ and `CameraPreview.start({ parent: "cameraPreview"});` will work. Starts the camera preview instance.
-| Option | values | descriptions | -|----------|---------------|------------------------------------------------------------------------| -| position | front \| rear | Show front or rear camera when start the preview. Defaults to front | -| width | number | (optional) The preview width in pixels, default window.screen.width (applicable to the android and ios platforms only) | -| height | number | (optional) The preview height in pixels, default window.screen.height (applicable to the android and ios platforms only) | -| x | number | (optional) The x origin, default 0 (applicable to the android and ios platforms only) | -| y | number | (optional) The y origin, default 0 (applicable to the android and ios platforms only) | -| toBack | boolean | (optional) Brings your html in front of your preview, default false (applicable to the android and ios platforms only) | -| paddingBottom | number | (optional) The preview bottom padding in pixes. Useful to keep the appropriate preview sizes when orientation changes (applicable to the android and ios platforms only) | -| rotateWhenOrientationChanged | boolean | (optional) Rotate preview when orientation changes (applicable to the ios platforms only; default value is true) | -| storeToFile | boolean | (optional) Capture images to a file and return back the file path instead of returning base64 encoded data, default false. | -| disableExifHeaderStripping | boolean | (optional) Disable automatic rotation of the image, and let the browser deal with it, default true (applicable to the android and ios platforms only) | -| enableHighResolution | boolean | (optional) Defaults to false - iOS only - Activate high resolution image capture so that output images are from the highest resolution possible on the device | -| disableAudio | boolean | (optional) Disables audio stream to prevent permission requests, default false. (applicable to web and iOS only) | -| lockAndroidOrientation | boolean | (optional) Locks device orientation when camera is showing, default false. (applicable to Android only) | -| enableOpacity | boolean | (optional) Make the camera preview see-through. Ideal for augmented reality uses. Default false (applicable to Android and web only) -| enableZoom | boolean | (optional) Set if you can pinch to zoom. Default false (applicable to the android and ios platforms only) +| Option | values | descriptions | +|------------------------------|--------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| position | front \ rear | Show front or rear camera when start the preview. Defaults to front | +| width | number | (optional) The preview width in pixels, default window.screen.width (applicable to the android and ios platforms only) | +| height | number | (optional) The preview height in pixels, default window.screen.height (applicable to the android and ios platforms only) | +| x | number | (optional) The x origin, default 0 (applicable to the android and ios platforms only) | +| y | number | (optional) The y origin, default 0 (applicable to the android and ios platforms only) | +| toBack | boolean | (optional) Brings your html in front of your preview, default false (applicable to the android and ios platforms only) | +| paddingBottom | number | (optional) The preview bottom padding in pixes. Useful to keep the appropriate preview sizes when orientation changes (applicable to the android and ios platforms only) | +| rotateWhenOrientationChanged | boolean | (optional) Rotate preview when orientation changes (applicable to the ios platforms only; default value is true) | +| storeToFile | boolean | (optional) Capture images to a file and return back the file path instead of returning base64 encoded data, default false. | +| disableExifHeaderStripping | boolean | (optional) Disable automatic rotation of the image, and let the browser deal with it, default true (applicable to the android and ios platforms only) | +| enableHighResolution | boolean | (optional) Defaults to false - iOS only - Activate high resolution image capture so that output images are from the highest resolution possible on the device | +| disableAudio | boolean | (optional) Disables audio stream to prevent permission requests, default false. (applicable to web and iOS only) | +| lockAndroidOrientation | boolean | (optional) Locks device orientation when camera is showing, default false. (applicable to Android only) | +| enableOpacity | boolean | (optional) Make the camera preview see-through. Ideal for augmented reality uses. Default false (applicable to Android and web only) | +| enableZoom | boolean | (optional) Set if you can pinch to zoom. Default false (applicable to the android and ios platforms only) | diff --git a/ios/Plugin/CameraController.swift b/ios/Plugin/CameraController.swift index 11008967..476c4b57 100644 --- a/ios/Plugin/CameraController.swift +++ b/ios/Plugin/CameraController.swift @@ -52,10 +52,9 @@ class CameraController: NSObject { var flashMode = AVCaptureDevice.FlashMode.off var zoomFactor: CGFloat = 1 - public func prepare(cameraPosition: CameraPosition, completionHandler: @escaping (Error?) -> Void) { + public func prepare(cameraPosition: CameraPosition?, enableHighResolution isHighResolutionPhotoEnabled: Bool, completionHandler: @escaping (Error?) -> Void) { // Set up capture session - let captureSession = AVCaptureSession() - captureSession.sessionPreset = AVCaptureSession.Preset.high + let captureSession = AVCaptureSession() self.captureSession = captureSession // Set up preview layer @@ -64,7 +63,7 @@ class CameraController: NSObject { // Initialize front and back camera do { - try initializeCameraDevices(forPosition: cameraPosition) + try initializeCameraDevices(forPosition: cameraPosition ?? .rear) try initializeCameraInput() } catch { completionHandler(error) @@ -73,6 +72,7 @@ class CameraController: NSObject { // Configure camera output self.photoOutput.setPreparedPhotoSettingsArray([AVCapturePhotoSettings(format: [AVVideoCodecKey: AVVideoCodecType.jpeg])], completionHandler: nil) + self.photoOutput.isHighResolutionCaptureEnabled = isHighResolutionPhotoEnabled if captureSession.canAddOutput(self.photoOutput) { captureSession.addOutput(self.photoOutput) } diff --git a/ios/Plugin/Plugin.swift b/ios/Plugin/Plugin.swift index 073b051f..5c290be2 100644 --- a/ios/Plugin/Plugin.swift +++ b/ios/Plugin/Plugin.swift @@ -19,28 +19,36 @@ public class CameraPreview: CAPPlugin { var toBack = false var storeToFile = false var enableZoom = false + var enableHighResolution = false /** Start the camera preview in a new UIView */ @objc public func start(_ call: CAPPluginCall) { - // Initialize settings provided via API call - initializePluginSettings(call: call) - - if let captureSession = self.cameraController.captureSession, captureSession.isRunning { - call.reject("camera already started") - return - } - - self.cameraController.prepare(cameraPosition: self.cameraPosition) { error in - if let error = error { - call.reject(error.localizedDescription) + AVCaptureDevice.requestAccess(for: AVMediaType.video) { [weak self] granted in + guard granted else { + call.reject("camera access not granted") return } - DispatchQueue.main.async { - self.displayCameraPreviewView() - call.resolve() + // Initialize settings provided via API call + self?.initializePluginSettings(call: call) + + if let captureSession = self?.cameraController.captureSession, captureSession.isRunning { + call.reject("camera already started") + return + } + + self?.cameraController.prepare(cameraPosition: self?.cameraPosition, enableHighResolution: self?.enableHighResolution ?? false) { error in + if let error = error { + call.reject(error.localizedDescription) + return + } + + DispatchQueue.main.async { + self?.displayCameraPreviewView() + call.resolve() + } } } } @@ -68,6 +76,8 @@ public class CameraPreview: CAPPlugin { @objc func capture(_ call: CAPPluginCall) { DispatchQueue.main.async { let quality: Int = call.getInt("quality", 85) + let width: Int? = call.getInt("width", 85) + let height: Int? = call.getInt("height", 85) self.cameraController.captureImage { (image, error) in guard let image = image else { @@ -76,6 +86,7 @@ public class CameraPreview: CAPPlugin { call.reject("Image capture error") return } + call.reject(error.localizedDescription) return } @@ -242,6 +253,31 @@ public class CameraPreview: CAPPlugin { self.storeToFile = call.getBool("storeToFile") ?? false self.enableZoom = call.getBool("enableZoom") ?? false + + self.enableHighResolution = call.getBool("enableHighResolution", false) + } + + @objc override public func checkPermissions(_ call: CAPPluginCall) { + let cameraState: String + + switch AVCaptureDevice.authorizationStatus(for: .video) { + case .notDetermined: + cameraState = "prompt" + case .restricted, .denied: + cameraState = "denied" + case .authorized: + cameraState = "granted" + @unknown default: + cameraState = "prompt" + } + + call.resolve(["camera": cameraState]) + } + + @objc public override func requestPermissions(_ call: CAPPluginCall) { + AVCaptureDevice.requestAccess(for: .video) { [weak self] _ in + self?.checkPermissions(call) + } } /** From 631bb38779700911bd4ba7addc8e344f574f6ca4 Mon Sep 17 00:00:00 2001 From: Michael Wolz Date: Mon, 24 Jun 2024 12:02:35 +0200 Subject: [PATCH 09/28] chore: documentation --- README.md | 12 ++++++------ ios/Plugin/Plugin.swift | 4 +--- src/definitions.ts | 4 ++-- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 0adce8f0..5394c98f 100644 --- a/README.md +++ b/README.md @@ -202,13 +202,13 @@ CameraPreview.hide(); ### capture(options) -| Option | values | descriptions | -|----------------------|---------------|----------------------------------------------------------------------| -| quality | number | (optional) The picture quality, 0 - 100, default 85 | -| width | number | (optional) The picture width, default 0 (Device default) | -| height | number | (optional) The picture height, default 0 (Device default) | +| Option | values | descriptions | +|----------------------|---------------|-------------------------------------------------------------------------------------------------| +| quality | number | (optional) The picture quality, 0 - 100, default 85 | +| width | number | (optional) The picture width, best fit respecting the aspect ratio of the device (Android only) | +| height | number | (optional) The picture height, best fit the aspect ratio of the device (Android only) | - + ```javascript import { CameraPreviewPictureOptions } from '@capacitor-community/camera-preview'; diff --git a/ios/Plugin/Plugin.swift b/ios/Plugin/Plugin.swift index 5c290be2..d7c84d5d 100644 --- a/ios/Plugin/Plugin.swift +++ b/ios/Plugin/Plugin.swift @@ -76,9 +76,7 @@ public class CameraPreview: CAPPlugin { @objc func capture(_ call: CAPPluginCall) { DispatchQueue.main.async { let quality: Int = call.getInt("quality", 85) - let width: Int? = call.getInt("width", 85) - let height: Int? = call.getInt("height", 85) - + self.cameraController.captureImage { (image, error) in guard let image = image else { print(error ?? "Image capture error") diff --git a/src/definitions.ts b/src/definitions.ts index b0d20b89..b9d6319b 100644 --- a/src/definitions.ts +++ b/src/definitions.ts @@ -36,9 +36,9 @@ export interface CameraPreviewOptions { enableZoom?: boolean; } export interface CameraPreviewPictureOptions { - /** The picture height, optional, default 0 (Device default) */ + /** The picture height, respecting the default aspect ratio of the device - Android only */ height?: number; - /** The picture width, optional, default 0 (Device default) */ + /** The picture width, respecting the default aspect ratio of the device - Android only */ width?: number; /** * The picture quality, 0 - 100, default 85 on `iOS/Android`. From 2a664f40490d61dfeddd9318727a8ba22a1f91d8 Mon Sep 17 00:00:00 2001 From: Michael Wolz Date: Mon, 24 Jun 2024 13:00:39 +0200 Subject: [PATCH 10/28] fix(ios): improve performance when opening camera --- ios/Plugin/CameraController.swift | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/ios/Plugin/CameraController.swift b/ios/Plugin/CameraController.swift index 476c4b57..3725f034 100644 --- a/ios/Plugin/CameraController.swift +++ b/ios/Plugin/CameraController.swift @@ -73,8 +73,11 @@ class CameraController: NSObject { // Configure camera output self.photoOutput.setPreparedPhotoSettingsArray([AVCapturePhotoSettings(format: [AVVideoCodecKey: AVVideoCodecType.jpeg])], completionHandler: nil) self.photoOutput.isHighResolutionCaptureEnabled = isHighResolutionPhotoEnabled - if captureSession.canAddOutput(self.photoOutput) { - captureSession.addOutput(self.photoOutput) + DispatchQueue.global().async { + // Adding the camera output might take quite some time so it's outsourced into a different queue + if captureSession.canAddOutput(self.photoOutput) { + captureSession.addOutput(self.photoOutput) + } } captureSession.startRunning() @@ -87,6 +90,7 @@ class CameraController: NSObject { self.currentCamera?.focusMode = .continuousAutoFocus self.currentCamera?.unlockForConfiguration() completionHandler(nil) + } catch { completionHandler(error) } From 5a858d44961353a982617cde6d4b683b1b2bfd7a Mon Sep 17 00:00:00 2001 From: Michael Wolz Date: Mon, 24 Jun 2024 13:49:28 +0200 Subject: [PATCH 11/28] fix: add permissions methods --- ios/Plugin/CameraController.swift | 6 +++--- ios/Plugin/Plugin.m | 2 ++ src/definitions.ts | 6 ++++++ 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/ios/Plugin/CameraController.swift b/ios/Plugin/CameraController.swift index 3725f034..ba7e82a9 100644 --- a/ios/Plugin/CameraController.swift +++ b/ios/Plugin/CameraController.swift @@ -70,11 +70,11 @@ class CameraController: NSObject { return } - // Configure camera output - self.photoOutput.setPreparedPhotoSettingsArray([AVCapturePhotoSettings(format: [AVVideoCodecKey: AVVideoCodecType.jpeg])], completionHandler: nil) - self.photoOutput.isHighResolutionCaptureEnabled = isHighResolutionPhotoEnabled DispatchQueue.global().async { // Adding the camera output might take quite some time so it's outsourced into a different queue + // Configure camera output + self.photoOutput.setPreparedPhotoSettingsArray([AVCapturePhotoSettings(format: [AVVideoCodecKey: AVVideoCodecType.jpeg])], completionHandler: nil) + self.photoOutput.isHighResolutionCaptureEnabled = isHighResolutionPhotoEnabled if captureSession.canAddOutput(self.photoOutput) { captureSession.addOutput(self.photoOutput) } diff --git a/ios/Plugin/Plugin.m b/ios/Plugin/Plugin.m index 06fb55e1..4dee0361 100644 --- a/ios/Plugin/Plugin.m +++ b/ios/Plugin/Plugin.m @@ -13,4 +13,6 @@ CAP_PLUGIN_METHOD(setFlashMode, CAPPluginReturnPromise); CAP_PLUGIN_METHOD(startRecordVideo, CAPPluginReturnPromise); CAP_PLUGIN_METHOD(stopRecordVideo, CAPPluginReturnPromise); + CAP_PLUGIN_METHOD(checkPermissions, CAPPluginReturnPromise); + CAP_PLUGIN_METHOD(requestPermissions, CAPPluginReturnPromise); ) diff --git a/src/definitions.ts b/src/definitions.ts index b9d6319b..020e966e 100644 --- a/src/definitions.ts +++ b/src/definitions.ts @@ -1,3 +1,5 @@ +import type { PermissionState } from '@capacitor/core'; + export type CameraPosition = 'rear' | 'front'; export interface CameraPreviewOptions { /** Parent element to attach the video preview element to (applicable to the web platform only) */ @@ -80,4 +82,8 @@ export interface CameraPreviewPlugin { startRecordVideo(options: CameraPreviewOptions): Promise<{}>; /** Stop recording a video from the current camera preview - Android only */ stopRecordVideo(): Promise<{}>; + /** Check camera permission */ + checkPermissions(): Promise; + /** Request camera permission */ + requestPermissions(): Promise; } From e941601e3c0381ce84fd5e0f7592b027ce408eaa Mon Sep 17 00:00:00 2001 From: Michael Wolz Date: Mon, 24 Jun 2024 14:06:57 +0200 Subject: [PATCH 12/28] fix: do not use virtual device on older iphones --- ios/Plugin/CameraController.swift | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/ios/Plugin/CameraController.swift b/ios/Plugin/CameraController.swift index ba7e82a9..a1128212 100644 --- a/ios/Plugin/CameraController.swift +++ b/ios/Plugin/CameraController.swift @@ -90,7 +90,7 @@ class CameraController: NSObject { self.currentCamera?.focusMode = .continuousAutoFocus self.currentCamera?.unlockForConfiguration() completionHandler(nil) - + } catch { completionHandler(error) } @@ -114,11 +114,6 @@ class CameraController: NSObject { if let rearCamera = AVCaptureDevice.default(.builtInTripleCamera, for: .video, position: .back) { self.zoomFactor = 2 self.rearCamera = rearCamera - } else if let rearCamera = AVCaptureDevice.default(.builtInDualCamera, for: .video, position: .back) { - self.rearCamera = rearCamera - } else if let rearCamera = AVCaptureDevice.default(.builtInDualWideCamera, for: .video, position: .back) { - self.zoomFactor = 2 - self.rearCamera = rearCamera } else { self.rearCamera = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: .back) } From 5f34b76ae4679db922b4073ad252522e911acb2a Mon Sep 17 00:00:00 2001 From: Michael Wolz Date: Mon, 24 Jun 2024 15:10:26 +0200 Subject: [PATCH 13/28] fix(web): add missing implementations for web platform --- src/web.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/web.ts b/src/web.ts index 5f9bf913..a7b58561 100644 --- a/src/web.ts +++ b/src/web.ts @@ -180,4 +180,12 @@ export class CameraPreviewWeb extends WebPlugin implements CameraPreviewPlugin { video.style.setProperty('opacity', _options['opacity'].toString()); } } + + async checkPermissions(): Promise { + throw new Error('checkPermissions not supported under the web platform'); + } + + async requestPermissions(): Promise { + throw new Error('requestPermissions not supported under the web platform'); + } } From f2d96d66c2436fca8c41b216549d7b62d302700d Mon Sep 17 00:00:00 2001 From: Michael Wolz Date: Tue, 25 Jun 2024 11:12:44 +0200 Subject: [PATCH 14/28] fix(ios): set photo preset for high resolution mode --- ios/Plugin/CameraController.swift | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ios/Plugin/CameraController.swift b/ios/Plugin/CameraController.swift index a1128212..30708881 100644 --- a/ios/Plugin/CameraController.swift +++ b/ios/Plugin/CameraController.swift @@ -57,6 +57,10 @@ class CameraController: NSObject { let captureSession = AVCaptureSession() self.captureSession = captureSession + if (isHighResolutionPhotoEnabled) { + captureSession.sessionPreset = .photo + } + // Set up preview layer previewLayer.session = captureSession previewLayer.videoGravity = AVLayerVideoGravity.resizeAspectFill From 9bd7af396c62f3862f6eb8ec615d665134737005 Mon Sep 17 00:00:00 2001 From: Michael Wolz Date: Wed, 26 Jun 2024 21:58:38 +0200 Subject: [PATCH 15/28] fix(ios): check focus / exposure mode support --- ios/Plugin/CameraController.swift | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/ios/Plugin/CameraController.swift b/ios/Plugin/CameraController.swift index 30708881..eef7874d 100644 --- a/ios/Plugin/CameraController.swift +++ b/ios/Plugin/CameraController.swift @@ -90,8 +90,15 @@ class CameraController: NSObject { do { try self.currentCamera?.lockForConfiguration() self.currentCamera?.videoZoomFactor = self.zoomFactor - self.currentCamera?.exposureMode = .continuousAutoExposure - self.currentCamera?.focusMode = .continuousAutoFocus + + if (self.currentCamera?.isFocusModeSupported(.continuousAutoFocus) ?? false) { + self.currentCamera?.focusMode = .continuousAutoFocus + } + + if (self.currentCamera?.isExposureModeSupported(.continuousAutoExposure) ?? false) { + self.currentCamera?.exposureMode = .continuousAutoExposure + } + self.currentCamera?.unlockForConfiguration() completionHandler(nil) @@ -116,6 +123,8 @@ class CameraController: NSObject { */ private func initializeCameraDevices(forPosition cameraPosition: CameraPosition) throws { if let rearCamera = AVCaptureDevice.default(.builtInTripleCamera, for: .video, position: .back) { + // Note that zoomFactor 2 "equals" the regular 1x zoom factor of the native iphone camera app + // 0.5x is videoZoomFactor 1. We do not want to use ultra wide angle by default so we set it to 2 self.zoomFactor = 2 self.rearCamera = rearCamera } else { From 5480293c30bea20119c5084f2b06b74aaaf1682e Mon Sep 17 00:00:00 2001 From: Michael Wolz Date: Sun, 30 Jun 2024 17:30:11 +0200 Subject: [PATCH 16/28] fix(ios): initialize photo output before applying zoom factor --- ios/Plugin/CameraController.swift | 44 +++++++++++++++++-------------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/ios/Plugin/CameraController.swift b/ios/Plugin/CameraController.swift index eef7874d..0b6ebe92 100644 --- a/ios/Plugin/CameraController.swift +++ b/ios/Plugin/CameraController.swift @@ -50,7 +50,7 @@ class CameraController: NSObject { var cameraInput: AVCaptureDeviceInput? var flashMode = AVCaptureDevice.FlashMode.off - var zoomFactor: CGFloat = 1 + var videoZoomFactor: CGFloat = 1 public func prepare(cameraPosition: CameraPosition?, enableHighResolution isHighResolutionPhotoEnabled: Bool, completionHandler: @escaping (Error?) -> Void) { // Set up capture session @@ -74,32 +74,36 @@ class CameraController: NSObject { return } - DispatchQueue.global().async { - // Adding the camera output might take quite some time so it's outsourced into a different queue - // Configure camera output - self.photoOutput.setPreparedPhotoSettingsArray([AVCapturePhotoSettings(format: [AVVideoCodecKey: AVVideoCodecType.jpeg])], completionHandler: nil) - self.photoOutput.isHighResolutionCaptureEnabled = isHighResolutionPhotoEnabled - if captureSession.canAddOutput(self.photoOutput) { - captureSession.addOutput(self.photoOutput) - } + // Adding the camera output might take quite some time so it's outsourced into a different queue + // Configure camera output + self.photoOutput.setPreparedPhotoSettingsArray([AVCapturePhotoSettings(format: [AVVideoCodecKey: AVVideoCodecType.jpeg])], completionHandler: nil) + self.photoOutput.isHighResolutionCaptureEnabled = isHighResolutionPhotoEnabled + if captureSession.canAddOutput(self.photoOutput) { + captureSession.addOutput(self.photoOutput) + } + + guard let cameraDevice = self.currentCamera else { + completionHandler(CameraControllerError.noCamerasAvailable); + return } captureSession.startRunning() // Lastly setting the video zoom factor do { - try self.currentCamera?.lockForConfiguration() - self.currentCamera?.videoZoomFactor = self.zoomFactor + try cameraDevice.lockForConfiguration() + defer { cameraDevice.unlockForConfiguration() } - if (self.currentCamera?.isFocusModeSupported(.continuousAutoFocus) ?? false) { - self.currentCamera?.focusMode = .continuousAutoFocus - } + cameraDevice.videoZoomFactor = self.videoZoomFactor - if (self.currentCamera?.isExposureModeSupported(.continuousAutoExposure) ?? false) { - self.currentCamera?.exposureMode = .continuousAutoExposure + if (cameraDevice.isFocusModeSupported(.continuousAutoFocus)) { + cameraDevice.focusMode = .continuousAutoFocus } - self.currentCamera?.unlockForConfiguration() + if (cameraDevice.isExposureModeSupported(.continuousAutoExposure)) { + cameraDevice.exposureMode = .continuousAutoExposure + } + completionHandler(nil) } catch { @@ -123,10 +127,10 @@ class CameraController: NSObject { */ private func initializeCameraDevices(forPosition cameraPosition: CameraPosition) throws { if let rearCamera = AVCaptureDevice.default(.builtInTripleCamera, for: .video, position: .back) { + self.rearCamera = rearCamera // Note that zoomFactor 2 "equals" the regular 1x zoom factor of the native iphone camera app // 0.5x is videoZoomFactor 1. We do not want to use ultra wide angle by default so we set it to 2 - self.zoomFactor = 2 - self.rearCamera = rearCamera + self.videoZoomFactor = 2 } else { self.rearCamera = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: .back) } @@ -441,7 +445,7 @@ extension CameraController: UIGestureRecognizerDelegate { let newScaleFactor = minMaxZoom(pinch.scale) update(scale: newScaleFactor) case .ended: - zoomFactor = device.videoZoomFactor + videoZoomFactor = device.videoZoomFactor default: break } } From a3fe1fc2c61b19e889dc2577c5bb6aee6b3fb259 Mon Sep 17 00:00:00 2001 From: Michael Wolz Date: Wed, 3 Jul 2024 14:49:06 +0200 Subject: [PATCH 17/28] fix(ios): repair switching camera behavior --- ios/Plugin/CameraController.swift | 59 +++++++++++++++++++------------ 1 file changed, 37 insertions(+), 22 deletions(-) diff --git a/ios/Plugin/CameraController.swift b/ios/Plugin/CameraController.swift index 0b6ebe92..aa2a6ff8 100644 --- a/ios/Plugin/CameraController.swift +++ b/ios/Plugin/CameraController.swift @@ -50,6 +50,8 @@ class CameraController: NSObject { var cameraInput: AVCaptureDeviceInput? var flashMode = AVCaptureDevice.FlashMode.off + + /** Video zoom factor that is used for manually zooming in and out via pinch gesture */ var videoZoomFactor: CGFloat = 1 public func prepare(cameraPosition: CameraPosition?, enableHighResolution isHighResolutionPhotoEnabled: Bool, completionHandler: @escaping (Error?) -> Void) { @@ -82,30 +84,12 @@ class CameraController: NSObject { captureSession.addOutput(self.photoOutput) } - guard let cameraDevice = self.currentCamera else { - completionHandler(CameraControllerError.noCamerasAvailable); - return - } - captureSession.startRunning() // Lastly setting the video zoom factor do { - try cameraDevice.lockForConfiguration() - defer { cameraDevice.unlockForConfiguration() } - - cameraDevice.videoZoomFactor = self.videoZoomFactor - - if (cameraDevice.isFocusModeSupported(.continuousAutoFocus)) { - cameraDevice.focusMode = .continuousAutoFocus - } - - if (cameraDevice.isExposureModeSupported(.continuousAutoExposure)) { - cameraDevice.exposureMode = .continuousAutoExposure - } - + try self.configureCameraSettings() completionHandler(nil) - } catch { completionHandler(error) } @@ -128,9 +112,6 @@ class CameraController: NSObject { private func initializeCameraDevices(forPosition cameraPosition: CameraPosition) throws { if let rearCamera = AVCaptureDevice.default(.builtInTripleCamera, for: .video, position: .back) { self.rearCamera = rearCamera - // Note that zoomFactor 2 "equals" the regular 1x zoom factor of the native iphone camera app - // 0.5x is videoZoomFactor 1. We do not want to use ultra wide angle by default so we set it to 2 - self.videoZoomFactor = 2 } else { self.rearCamera = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: .back) } @@ -146,6 +127,34 @@ class CameraController: NSObject { self.currentCamera = cameraPosition == .rear ? rearCamera : frontCamera } + /** + Configure several camera related properties based on the currently selected camera device. + This function also keeps care of the default zoom factor for the chosen camera device + */ + private func configureCameraSettings() throws { + guard let cameraDevice = self.currentCamera else { + throw CameraControllerError.noCamerasAvailable; + } + + try cameraDevice.lockForConfiguration() + defer { cameraDevice.unlockForConfiguration() } + + if (cameraDevice.isFocusModeSupported(.continuousAutoFocus)) { + cameraDevice.focusMode = .continuousAutoFocus + } + + if (cameraDevice.isExposureModeSupported(.continuousAutoExposure)) { + cameraDevice.exposureMode = .continuousAutoExposure + } + + if (cameraDevice.deviceType == .builtInTripleCamera) { + // Note that zoomFactor 2 "equals" the regular 1x zoom factor of the native iphone camera app + // 0.5x however equal a videoZoomFactor of 1. We do not want to use ultra wide angle by default + // the default videoZoomFactor to 2 in case the current camera device type is .builtInTripleCamera + cameraDevice.videoZoomFactor = 2.0 + } + } + /** Initialize the camera inputs */ @@ -218,6 +227,7 @@ class CameraController: NSObject { if captureSession.canAddInput(newCameraInput) { captureSession.addInput(newCameraInput) self.cameraInput = newCameraInput + self.currentCamera = frontCamera } else { throw CameraControllerError.invalidOperation } @@ -233,6 +243,8 @@ class CameraController: NSObject { if captureSession.canAddInput(newCameraInput) { captureSession.addInput(newCameraInput) + self.cameraInput = newCameraInput + self.currentCamera = rearCamera } else { throw CameraControllerError.invalidOperation } @@ -248,6 +260,9 @@ class CameraController: NSObject { @unknown default: return } + + // Reconfigure camera settings + try? self.configureCameraSettings() captureSession.commitConfiguration() } From db16c0feec58d4328c315cc415b45203686fb474 Mon Sep 17 00:00:00 2001 From: Michael Wolz Date: Wed, 3 Jul 2024 19:12:27 +0200 Subject: [PATCH 18/28] fix(android): front camera rotation --- .../camera/preview/CameraActivity.java | 20 +++++-------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/android/src/main/java/com/ahm/capacitor/camera/preview/CameraActivity.java b/android/src/main/java/com/ahm/capacitor/camera/preview/CameraActivity.java index b0554fe1..1a8b98b0 100644 --- a/android/src/main/java/com/ahm/capacitor/camera/preview/CameraActivity.java +++ b/android/src/main/java/com/ahm/capacitor/camera/preview/CameraActivity.java @@ -768,31 +768,21 @@ public void run() { if (cameraCurrentlyLocked == Camera.CameraInfo.CAMERA_FACING_FRONT && disableExifHeaderStripping) { Activity activity = getActivity(); int rotation = activity.getWindowManager().getDefaultDisplay().getRotation(); - int degrees = 0; + int orientation = 0; switch (rotation) { case Surface.ROTATION_0: - degrees = 0; + orientation = 270; break; case Surface.ROTATION_90: - degrees = 180; + orientation = 0; break; case Surface.ROTATION_180: - degrees = 270; + orientation = 0; break; case Surface.ROTATION_270: - degrees = 0; + orientation = 180; break; } - int orientation; - Camera.CameraInfo info = new Camera.CameraInfo(); - if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) { - orientation = (info.orientation + degrees) % 360; - if (degrees != 0) { - orientation = (360 - orientation) % 360; - } - } else { - orientation = (info.orientation - degrees + 360) % 360; - } params.setRotation(orientation); } else { params.setRotation(mPreview.getDisplayOrientation()); From 6dbccb621c4d2d464ffb229d659540a3eb551a7a Mon Sep 17 00:00:00 2001 From: Michael Wolz Date: Wed, 3 Jul 2024 21:23:06 +0200 Subject: [PATCH 19/28] fix(android): image rotation logic for front camera --- .../camera/preview/CameraActivity.java | 24 +++++++------------ 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/android/src/main/java/com/ahm/capacitor/camera/preview/CameraActivity.java b/android/src/main/java/com/ahm/capacitor/camera/preview/CameraActivity.java index 1a8b98b0..c76a16db 100644 --- a/android/src/main/java/com/ahm/capacitor/camera/preview/CameraActivity.java +++ b/android/src/main/java/com/ahm/capacitor/camera/preview/CameraActivity.java @@ -765,25 +765,19 @@ public void run() { params.setJpegQuality(quality); } - if (cameraCurrentlyLocked == Camera.CameraInfo.CAMERA_FACING_FRONT && disableExifHeaderStripping) { + Camera.CameraInfo info = new Camera.CameraInfo(); + Camera.getCameraInfo(cameraCurrentlyLocked, info); + if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT && disableExifHeaderStripping) { Activity activity = getActivity(); int rotation = activity.getWindowManager().getDefaultDisplay().getRotation(); - int orientation = 0; + int degrees = 0; switch (rotation) { - case Surface.ROTATION_0: - orientation = 270; - break; - case Surface.ROTATION_90: - orientation = 0; - break; - case Surface.ROTATION_180: - orientation = 0; - break; - case Surface.ROTATION_270: - orientation = 180; - break; + case Surface.ROTATION_0: degrees = 0; break; + case Surface.ROTATION_90: degrees = 90; break; + case Surface.ROTATION_180: degrees = 180; break; + case Surface.ROTATION_270: degrees = 270; break; } - params.setRotation(orientation); + params.setRotation((info.orientation + degrees) % 360); } else { params.setRotation(mPreview.getDisplayOrientation()); } From bc57883dad01db38f0c80b4d826478899f77ef0c Mon Sep 17 00:00:00 2001 From: Michael Wolz Date: Thu, 4 Jul 2024 17:01:25 +0200 Subject: [PATCH 20/28] fix(ios): camera initialization on ios --- ios/Plugin/Plugin.swift | 39 ++++++++++++++------------------------- 1 file changed, 14 insertions(+), 25 deletions(-) diff --git a/ios/Plugin/Plugin.swift b/ios/Plugin/Plugin.swift index d7c84d5d..789f3e1a 100644 --- a/ios/Plugin/Plugin.swift +++ b/ios/Plugin/Plugin.swift @@ -89,14 +89,8 @@ public class CameraPreview: CAPPlugin { return } - let imageData: Data? - if self.cameraController.currentCamera?.position == .front { - let flippedImage = image.withHorizontallyFlippedOrientation() - imageData = flippedImage.jpegData(compressionQuality: CGFloat(quality / 100)) - } else { - imageData = image.jpegData(compressionQuality: CGFloat(quality / 100)) - } - + let imageData = image.jpegData(compressionQuality: CGFloat(quality / 100)) + if self.storeToFile == false { let imageBase64 = imageData?.base64EncodedString() call.resolve(["value": imageBase64!]) @@ -220,29 +214,24 @@ public class CameraPreview: CAPPlugin { Helper method for initializing the plugin settings based on the Capacitor call */ private func initializePluginSettings(call: CAPPluginCall) { - if call.getString("position") == "front" { - self.cameraPosition = .front - } - - if let width = call.getInt("width") { - self.previewWidth = CGFloat(width) - } + self.cameraPosition = call.getString("position") == "front" ? .front : .rear - if let height = call.getInt("height") { - self.previewHeight = CGFloat(height) + if let previewWidth = call.getInt("width") { + self.previewWidth = CGFloat(previewWidth) + } else { + self.previewWidth = UIScreen.main.bounds.size.width } - if let x = call.getInt("x") { - self.x = CGFloat(x) / 2 + if let previewHeight = call.getInt("height") { + self.previewHeight = CGFloat(previewHeight) + } else { + self.previewHeight = UIScreen.main.bounds.size.height } - if let y = call.getInt("y") { - self.y = CGFloat(y) / 2 - } + self.x = CGFloat(call.getInt("x", 0)) / 2 + self.y = CGFloat(call.getInt("y", 0)) / 2 - if let paddingBottom = call.getInt("paddingBottom") { - self.paddingBottom = CGFloat(paddingBottom) - } + self.paddingBottom = CGFloat(call.getInt("paddingBottom", 0)) self.rotateWhenOrientationChanged = call.getBool("rotateWhenOrientationChanged") ?? true From 93b5b742d5122ab926a916dbacd8b62877887b0d Mon Sep 17 00:00:00 2001 From: Michael Wolz Date: Mon, 8 Jul 2024 17:24:25 +0200 Subject: [PATCH 21/28] docs: remove iOS support for video recording --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5394c98f..a2c99e68 100644 --- a/README.md +++ b/README.md @@ -266,7 +266,7 @@ const CameraPreviewFlashMode: CameraPreviewFlashMode = 'torch'; CameraPreview.setFlashMode(cameraPreviewFlashMode); ``` -### startRecordVideo(options) ---- ANDROID and iOS only +### startRecordVideo(options) ---- ANDROID only Start capturing video
@@ -280,7 +280,7 @@ const cameraPreviewOptions: CameraPreviewOptions = { CameraPreview.startRecordVideo(cameraPreviewOptions); ``` -### stopRecordVideo() ---- ANDROID and iOS only +### stopRecordVideo() ---- ANDROID only Finish capturing a video. The captured video will be returned as a file path and the video format is .mp4
From 0a846ed375a96f54ed2396f8b27cfa3f50d8fa89 Mon Sep 17 00:00:00 2001 From: Michael Wolz Date: Fri, 12 Jul 2024 17:16:02 +0200 Subject: [PATCH 22/28] feat(*): remove video recording functions --- .../camera/preview/CameraActivity.java | 153 ------------------ .../camera/preview/CameraPreview.java | 102 ------------ .../ahm/capacitor/camera/preview/Preview.java | 2 - ios/Plugin/Plugin.m | 2 - ios/Plugin/Plugin.swift | 8 - src/definitions.ts | 8 +- src/web.ts | 133 +++++++-------- 7 files changed, 56 insertions(+), 352 deletions(-) diff --git a/android/src/main/java/com/ahm/capacitor/camera/preview/CameraActivity.java b/android/src/main/java/com/ahm/capacitor/camera/preview/CameraActivity.java index c76a16db..5706d909 100644 --- a/android/src/main/java/com/ahm/capacitor/camera/preview/CameraActivity.java +++ b/android/src/main/java/com/ahm/capacitor/camera/preview/CameraActivity.java @@ -2,35 +2,25 @@ import android.app.Activity; import android.app.Fragment; -import android.content.Context; import android.content.pm.PackageManager; import android.content.res.Configuration; import android.graphics.Bitmap; import android.graphics.Bitmap.CompressFormat; import android.graphics.BitmapFactory; -import android.graphics.Canvas; -import android.graphics.ImageFormat; import android.graphics.Matrix; import android.graphics.Rect; import android.graphics.YuvImage; import android.hardware.Camera; import android.hardware.Camera.PictureCallback; import android.hardware.Camera.ShutterCallback; -import android.media.AudioManager; -import android.media.CamcorderProfile; -import android.media.MediaRecorder; import android.os.Bundle; import android.util.Base64; -import android.util.DisplayMetrics; import android.util.Log; import android.view.GestureDetector; import android.view.Gravity; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.Surface; -import android.view.Surface; -import android.view.SurfaceHolder; -import android.view.SurfaceView; import android.view.View; import android.view.ViewGroup; import android.view.ViewTreeObserver; @@ -53,14 +43,8 @@ public interface CameraPreviewListener { void onPictureTakenError(String message); void onSnapshotTaken(String originalPicture); void onSnapshotTakenError(String message); - void onFocusSet(int pointX, int pointY); - void onFocusSetError(String message); void onBackButton(); void onCameraStarted(); - void onStartRecordVideo(); - void onStartRecordVideoError(String message); - void onStopRecordVideo(String file); - void onStopRecordVideoError(String error); } private CameraPreviewListener eventListener; @@ -84,9 +68,6 @@ private enum RecordingState { STOPPED } - private RecordingState mRecordingState = RecordingState.INITIALIZING; - private MediaRecorder mRecorder = null; - private String recordFilePath; private float opacity; // The first rear facing camera @@ -792,140 +773,6 @@ public void run() { } } - public void startRecord( - final String filePath, - final String camera, - final int width, - final int height, - final int quality, - final boolean withFlash, - final int maxDuration - ) { - Log.d(TAG, "CameraPreview startRecord camera: " + camera + " width: " + width + ", height: " + height + ", quality: " + quality); - Activity activity = getActivity(); - muteStream(true, activity); - if (this.mRecordingState == RecordingState.STARTED) { - Log.d(TAG, "Already Recording"); - return; - } - - this.recordFilePath = filePath; - int mOrientationHint = calculateOrientationHint(); - int videoWidth = 0; //set whatever - int videoHeight = 0; //set whatever - - Camera.Parameters cameraParams = mCamera.getParameters(); - if (withFlash) { - cameraParams.setFlashMode(withFlash ? Camera.Parameters.FLASH_MODE_TORCH : Camera.Parameters.FLASH_MODE_OFF); - mCamera.setParameters(cameraParams); - mCamera.startPreview(); - } - - mCamera.unlock(); - mRecorder = new MediaRecorder(); - - try { - mRecorder.setCamera(mCamera); - - CamcorderProfile profile; - if (CamcorderProfile.hasProfile(defaultCameraId, CamcorderProfile.QUALITY_HIGH)) { - profile = CamcorderProfile.get(defaultCameraId, CamcorderProfile.QUALITY_HIGH); - } else { - if (CamcorderProfile.hasProfile(defaultCameraId, CamcorderProfile.QUALITY_480P)) { - profile = CamcorderProfile.get(defaultCameraId, CamcorderProfile.QUALITY_480P); - } else { - if (CamcorderProfile.hasProfile(defaultCameraId, CamcorderProfile.QUALITY_720P)) { - profile = CamcorderProfile.get(defaultCameraId, CamcorderProfile.QUALITY_720P); - } else { - if (CamcorderProfile.hasProfile(defaultCameraId, CamcorderProfile.QUALITY_1080P)) { - profile = CamcorderProfile.get(defaultCameraId, CamcorderProfile.QUALITY_1080P); - } else { - profile = CamcorderProfile.get(defaultCameraId, CamcorderProfile.QUALITY_LOW); - } - } - } - } - - mRecorder.setAudioSource(MediaRecorder.AudioSource.VOICE_RECOGNITION); - mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); - mRecorder.setProfile(profile); - mRecorder.setOutputFile(filePath); - mRecorder.setOrientationHint(mOrientationHint); - mRecorder.setMaxDuration(maxDuration); - - mRecorder.prepare(); - Log.d(TAG, "Starting recording"); - mRecorder.start(); - eventListener.onStartRecordVideo(); - } catch (IOException e) { - eventListener.onStartRecordVideoError(e.getMessage()); - } - } - - public int calculateOrientationHint() { - DisplayMetrics dm = new DisplayMetrics(); - Camera.CameraInfo info = new Camera.CameraInfo(); - Camera.getCameraInfo(defaultCameraId, info); - int cameraRotationOffset = info.orientation; - Activity activity = getActivity(); - - activity.getWindowManager().getDefaultDisplay().getMetrics(dm); - int currentScreenRotation = activity.getWindowManager().getDefaultDisplay().getRotation(); - - int degrees = 0; - switch (currentScreenRotation) { - case Surface.ROTATION_0: - degrees = 0; - break; - case Surface.ROTATION_90: - degrees = 90; - break; - case Surface.ROTATION_180: - degrees = 180; - break; - case Surface.ROTATION_270: - degrees = 270; - break; - } - - int orientation; - if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) { - orientation = (cameraRotationOffset + degrees) % 360; - if (degrees != 0) { - orientation = (360 - orientation) % 360; - } - } else { - orientation = (cameraRotationOffset - degrees + 360) % 360; - } - Log.w(TAG, "************orientationHint ***********= " + orientation); - - return orientation; - } - - public void stopRecord() { - Log.d(TAG, "stopRecord"); - - try { - mRecorder.stop(); - mRecorder.reset(); // clear recorder configuration - mRecorder.release(); // release the recorder object - mRecorder = null; - mCamera.lock(); - Camera.Parameters cameraParams = mCamera.getParameters(); - cameraParams.setFlashMode(Camera.Parameters.FLASH_MODE_OFF); - mCamera.setParameters(cameraParams); - mCamera.startPreview(); - eventListener.onStopRecordVideo(this.recordFilePath); - } catch (Exception e) { - eventListener.onStopRecordVideoError(e.getMessage()); - } - } - - public void muteStream(boolean mute, Activity activity) { - AudioManager audioManager = ((AudioManager) activity.getApplicationContext().getSystemService(Context.AUDIO_SERVICE)); - int direction = mute ? audioManager.ADJUST_MUTE : audioManager.ADJUST_UNMUTE; - } - public void setFocusArea(final int pointX, final int pointY, final Camera.AutoFocusCallback callback) { if (mCamera != null) { mCamera.cancelAutoFocus(); diff --git a/android/src/main/java/com/ahm/capacitor/camera/preview/CameraPreview.java b/android/src/main/java/com/ahm/capacitor/camera/preview/CameraPreview.java index 784a15b6..761255f3 100644 --- a/android/src/main/java/com/ahm/capacitor/camera/preview/CameraPreview.java +++ b/android/src/main/java/com/ahm/capacitor/camera/preview/CameraPreview.java @@ -24,7 +24,6 @@ import com.getcapacitor.annotation.CapacitorPlugin; import com.getcapacitor.annotation.Permission; import com.getcapacitor.annotation.PermissionCallback; -import java.io.File; import java.util.List; import org.json.JSONArray; @@ -33,12 +32,8 @@ public class CameraPreview extends Plugin implements CameraActivity.CameraPrevie static final String CAMERA_PERMISSION_ALIAS = "camera"; - private static String VIDEO_FILE_PATH = ""; - private static String VIDEO_FILE_EXTENSION = ".mp4"; - private String captureCallbackId = ""; private String snapshotCallbackId = ""; - private String recordCallbackId = ""; private String cameraStartCallbackId = ""; // keep track of previously specified orientation to support locking orientation: @@ -193,62 +188,6 @@ public void setFlashMode(PluginCall call) { call.resolve(); } - @PluginMethod - public void startRecordVideo(final PluginCall call) { - if (this.hasCamera(call) == false) { - call.reject("Camera is not running"); - return; - } - final String filename = "videoTmp"; - VIDEO_FILE_PATH = getActivity().getCacheDir().toString() + "/"; - - final String position = call.getString("position", "front"); - final Integer width = call.getInt("width", 0); - final Integer height = call.getInt("height", 0); - final Boolean withFlash = call.getBoolean("withFlash", false); - final Integer maxDuration = call.getInt("maxDuration", 0); - // final Integer quality = call.getInt("quality", 0); - bridge.saveCall(call); - recordCallbackId = call.getCallbackId(); - - bridge - .getActivity() - .runOnUiThread( - new Runnable() { - @Override - public void run() { - // fragment.startRecord(getFilePath(filename), position, width, height, quality, withFlash); - fragment.startRecord(getFilePath(filename), position, width, height, 70, withFlash, maxDuration); - } - } - ); - - call.resolve(); - } - - @PluginMethod - public void stopRecordVideo(PluginCall call) { - if (this.hasCamera(call) == false) { - call.reject("Camera is not running"); - return; - } - - System.out.println("stopRecordVideo - Callbackid=" + call.getCallbackId()); - - bridge.saveCall(call); - recordCallbackId = call.getCallbackId(); - - // bridge.getActivity().runOnUiThread(new Runnable() { - // @Override - // public void run() { - // fragment.stopRecord(); - // } - // }); - - fragment.stopRecord(); - // call.resolve(); - } - @PermissionCallback private void handleCameraPermissionResult(PluginCall call) { if (PermissionState.GRANTED.equals(getPermissionState(CAMERA_PERMISSION_ALIAS))) { @@ -406,12 +345,6 @@ public void onSnapshotTakenError(String message) { bridge.getSavedCall(snapshotCallbackId).reject(message); } - @Override - public void onFocusSet(int pointX, int pointY) {} - - @Override - public void onFocusSetError(String message) {} - @Override public void onBackButton() {} @@ -422,27 +355,6 @@ public void onCameraStarted() { bridge.releaseCall(pluginCall); } - @Override - public void onStartRecordVideo() {} - - @Override - public void onStartRecordVideoError(String message) { - bridge.getSavedCall(recordCallbackId).reject(message); - } - - @Override - public void onStopRecordVideo(String file) { - PluginCall pluginCall = bridge.getSavedCall(recordCallbackId); - JSObject jsObject = new JSObject(); - jsObject.put("videoFilePath", file); - pluginCall.resolve(jsObject); - } - - @Override - public void onStopRecordVideoError(String error) { - bridge.getSavedCall(recordCallbackId).reject(error); - } - private boolean hasView(PluginCall call) { if (fragment == null) { return false; @@ -463,20 +375,6 @@ private boolean hasCamera(PluginCall call) { return true; } - private String getFilePath(String filename) { - String fileName = filename; - - int i = 1; - - while (new File(VIDEO_FILE_PATH + fileName + VIDEO_FILE_EXTENSION).exists()) { - // Add number suffix if file exists - fileName = filename + '_' + i; - i++; - } - - return VIDEO_FILE_PATH + fileName + VIDEO_FILE_EXTENSION; - } - private void setupBroadcast() { /** When touch event is triggered, relay it to camera view if needed so it can support pinch zoom */ diff --git a/android/src/main/java/com/ahm/capacitor/camera/preview/Preview.java b/android/src/main/java/com/ahm/capacitor/camera/preview/Preview.java index 6daa426f..6ba05fda 100644 --- a/android/src/main/java/com/ahm/capacitor/camera/preview/Preview.java +++ b/android/src/main/java/com/ahm/capacitor/camera/preview/Preview.java @@ -73,8 +73,6 @@ public void setCamera(Camera camera, int cameraId) { Camera.Parameters params = mCamera.getParameters(); if (mFocusModes.contains("continuous-picture")) { params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE); - } else if (mFocusModes.contains("continuous-video")) { - params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO); } else if (mFocusModes.contains("auto")) { params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO); } diff --git a/ios/Plugin/Plugin.m b/ios/Plugin/Plugin.m index 4dee0361..75e1a5e6 100644 --- a/ios/Plugin/Plugin.m +++ b/ios/Plugin/Plugin.m @@ -11,8 +11,6 @@ CAP_PLUGIN_METHOD(flip, CAPPluginReturnPromise); CAP_PLUGIN_METHOD(getSupportedFlashModes, CAPPluginReturnPromise); CAP_PLUGIN_METHOD(setFlashMode, CAPPluginReturnPromise); - CAP_PLUGIN_METHOD(startRecordVideo, CAPPluginReturnPromise); - CAP_PLUGIN_METHOD(stopRecordVideo, CAPPluginReturnPromise); CAP_PLUGIN_METHOD(checkPermissions, CAPPluginReturnPromise); CAP_PLUGIN_METHOD(requestPermissions, CAPPluginReturnPromise); ) diff --git a/ios/Plugin/Plugin.swift b/ios/Plugin/Plugin.swift index 789f3e1a..b9a0e349 100644 --- a/ios/Plugin/Plugin.swift +++ b/ios/Plugin/Plugin.swift @@ -202,14 +202,6 @@ public class CameraPreview: CAPPlugin { } } - @objc func startRecordVideo(_ call: CAPPluginCall) { - call.reject("Method not implemented on iOS platform") - } - - @objc func stopRecordVideo(_ call: CAPPluginCall) { - call.reject("Method not implemented on iOS platform") - } - /** Helper method for initializing the plugin settings based on the Capacitor call */ diff --git a/src/definitions.ts b/src/definitions.ts index 020e966e..78434d89 100644 --- a/src/definitions.ts +++ b/src/definitions.ts @@ -24,12 +24,10 @@ export interface CameraPreviewOptions { position?: CameraPosition | string; /** Defaults to false - Capture images to a file and return the file path instead of returning base64 encoded data */ storeToFile?: boolean; - /** Defaults to false - Android Only - Disable automatic rotation of the image, and let the browser deal with it (keep reading on how to achieve it) */ + /** Defaults to false - Android Only - Disable automatic rotation of the image, and let the browser deal with it */ disableExifHeaderStripping?: boolean; /** Defaults to false - iOS only - Activate high resolution image capture so that output images are from the highest resolution possible on the device **/ enableHighResolution?: boolean; - /** Defaults to false - Web only - Disables audio stream to prevent permission requests and output switching */ - disableAudio?: boolean; /** Android Only - Locks device orientation when camera is showing. */ lockAndroidOrientation?: boolean; /** Defaults to false - Android and Web only. Set if camera preview can change opacity. */ @@ -78,10 +76,6 @@ export interface CameraPreviewPlugin { flip(): Promise; /** Changes the opacity of the shown camera preview - Android / Web only */ setOpacity(options: CameraOpacityOptions): Promise<{}>; - /** Start recording a video from the current camera preview - Android only */ - startRecordVideo(options: CameraPreviewOptions): Promise<{}>; - /** Stop recording a video from the current camera preview - Android only */ - stopRecordVideo(): Promise<{}>; /** Check camera permission */ checkPermissions(): Promise; /** Request camera permission */ diff --git a/src/web.ts b/src/web.ts index a7b58561..0b06aceb 100644 --- a/src/web.ts +++ b/src/web.ts @@ -24,86 +24,63 @@ export class CameraPreviewWeb extends WebPlugin implements CameraPreviewPlugin { } async start(options: CameraPreviewOptions): Promise<{}> { - return new Promise(async (resolve, reject) => { - await navigator.mediaDevices - .getUserMedia({ - audio: !options.disableAudio, - video: true, - }) - .then((stream: MediaStream) => { - // Stop any existing stream so we can request media with different constraints based on user input - stream.getTracks().forEach((track) => track.stop()); - }) - .catch((error) => { - reject(error); - }); - - const video = document.getElementById('video'); - const parent = document.getElementById(options.parent); - - if (!video) { - const videoElement = document.createElement('video'); - videoElement.id = 'video'; - videoElement.setAttribute('class', options.className || ''); - - // Don't flip video feed if camera is rear facing - if (options.position !== 'rear') { - videoElement.setAttribute('style', '-webkit-transform: scaleX(-1); transform: scaleX(-1);'); - } - - const userAgent = navigator.userAgent.toLowerCase(); - const isSafari = userAgent.includes('safari') && !userAgent.includes('chrome'); - - // Safari on iOS needs to have the autoplay, muted and playsinline attributes set for video.play() to be successful - // Without these attributes videoElement.play() will throw a NotAllowedError - // https://developer.apple.com/documentation/webkit/delivering_video_content_for_safari - if (isSafari) { - videoElement.setAttribute('autoplay', 'true'); - videoElement.setAttribute('muted', 'true'); - videoElement.setAttribute('playsinline', 'true'); - } - - parent.appendChild(videoElement); - - if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) { - const constraints: MediaStreamConstraints = { - video: { - width: { ideal: options.width }, - height: { ideal: options.height }, - }, - }; - - if (options.position === 'rear') { - (constraints.video as MediaTrackConstraints).facingMode = 'environment'; - this.isBackCamera = true; - } else { - this.isBackCamera = false; - } - - navigator.mediaDevices.getUserMedia(constraints).then( - function (stream) { - //video.src = window.URL.createObjectURL(stream); - videoElement.srcObject = stream; - videoElement.play(); - resolve({}); - }, - (err) => { - reject(err); - } - ); - } - } else { - reject({ message: 'camera already started' }); - } - }); - } + const stream = await navigator.mediaDevices.getUserMedia({ video: true }); - async startRecordVideo(): Promise<{}> { - throw this.unimplemented('Not implemented on web.'); - } + // Stop any existing stream so we can request media with different constraints based on user input + stream.getTracks().forEach((track) => track.stop()); + + const video = document.getElementById('video'); + const parent = document.getElementById(options.parent); + + if (video) { + throw new Error('camera already started'); + } + + const videoElement = document.createElement('video'); + videoElement.id = 'video'; + videoElement.setAttribute('class', options.className || ''); + + // Don't flip video feed if camera is rear facing + if (options.position !== 'rear') { + videoElement.setAttribute('style', '-webkit-transform: scaleX(-1); transform: scaleX(-1);'); + } + + const userAgent = navigator.userAgent.toLowerCase(); + const isSafari = userAgent.includes('safari') && !userAgent.includes('chrome'); + + // Safari on iOS needs to have the autoplay, muted and playsinline attributes set for video.play() to be successful + // Without these attributes videoElement.play() will throw a NotAllowedError + // https://developer.apple.com/documentation/webkit/delivering_video_content_for_safari + if (isSafari) { + videoElement.setAttribute('autoplay', 'true'); + videoElement.setAttribute('muted', 'true'); + videoElement.setAttribute('playsinline', 'true'); + } + + parent.appendChild(videoElement); + + if (!navigator.mediaDevices?.getUserMedia) { + throw new Error('No media devices available'); + } + + const constraints: MediaStreamConstraints = { + video: { + width: { ideal: options.width }, + height: { ideal: options.height }, + }, + }; + + if (options.position === 'rear') { + (constraints.video as MediaTrackConstraints).facingMode = 'environment'; + this.isBackCamera = true; + } else { + this.isBackCamera = false; + } + + videoElement.srcObject = await navigator.mediaDevices.getUserMedia(constraints); + videoElement.play(); - async stopRecordVideo(): Promise<{}> { - throw this.unimplemented('Not implemented on web.'); + return {}; } async stop(): Promise { From 8fba53025abc7160da053e4e6f29f1cc7b396d95 Mon Sep 17 00:00:00 2001 From: Michael Wolz Date: Fri, 12 Jul 2024 17:16:22 +0200 Subject: [PATCH 23/28] docs: update readme --- README.md | 265 ++++++------------------------------------------------ 1 file changed, 25 insertions(+), 240 deletions(-) diff --git a/README.md b/README.md index a2c99e68..f9fba9b6 100644 --- a/README.md +++ b/README.md @@ -2,40 +2,19 @@

Capacitor Camera Preview

@capacitor-community/camera-preview


-

CAPACITOR 5


+

CAPACITOR 6


- Capacitor plugin that allows camera interaction from Javascript and HTML
(based on cordova-plugin-camera-preview). + Capacitor plugin that allows camera interaction from Javascript and HTML
(based on @capacitor-community/camera-preview which itself was based on cordova-plugin-camera-preview).

-
-Version 6 of this plugin requires Capacitor 6. - -If you are using Capacitor 5, use [version 5](https://github.com/capacitor-community/camera-preview/releases/tag/v5.0.0) -If you are using Capacitor 4, use [version 4](https://github.com/capacitor-community/camera-preview/releases/tag/v4.0.0) - -If you are using Capacitor 3, use [version 3](https://github.com/capacitor-community/camera-preview/releases/tag/v3.1.2) +
-If you are using Capacitor 2, use [version 1](https://github.com/capacitor-community/camera-preview/releases/tag/v1.2.1) +Version 6 of this plugin requires Capacitor 6. **PR's are greatly appreciated.** --- [@arielhernandezmusa](https://github.com/arielhernandezmusa) and [@pbowyer](https://github.com/pbowyer), current maintainers - - +[@michaelwolz](https://github.com/michaelwolz) is the current maintainer of this version of the camera-preview plugin and will try to maintain it until the official capacitor-community plugin will gets updated again. # Installation @@ -46,6 +25,7 @@ or npm install @capacitor-community/camera-preview ``` + Then run ``` npx cap sync @@ -67,7 +47,8 @@ This plugin will use the following project variables (defined in your app's `var - `androidxExifInterfaceVersion`: version of `androidx.exifinterface:exifinterface` (default: `1.3.6`) ## Extra iOS installation steps -You will need to add two permissions to `Info.plist`. Follow the [Capacitor docs](https://capacitorjs.com/docs/ios/configuration#configuring-infoplist) and add permissions with the raw keys `NSCameraUsageDescription` and `NSMicrophoneUsageDescription`. `NSMicrophoneUsageDescription` is only required, if audio will be used. Otherwise set the `disableAudio` option to `true`, which also disables the microphone permission request. + +You will need to add two permissions to `Info.plist`. Follow the [Capacitor docs](https://capacitorjs.com/docs/ios/configuration#configuring-infoplist) and add permissions with the raw keys `NSCameraUsageDescription`. ## Extra Web installation steps @@ -85,38 +66,22 @@ and `CameraPreview.start({ parent: "cameraPreview"});` will work. Starts the camera preview instance.
-| Option | values | descriptions | -|------------------------------|--------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| position | front \ rear | Show front or rear camera when start the preview. Defaults to front | -| width | number | (optional) The preview width in pixels, default window.screen.width (applicable to the android and ios platforms only) | -| height | number | (optional) The preview height in pixels, default window.screen.height (applicable to the android and ios platforms only) | -| x | number | (optional) The x origin, default 0 (applicable to the android and ios platforms only) | -| y | number | (optional) The y origin, default 0 (applicable to the android and ios platforms only) | -| toBack | boolean | (optional) Brings your html in front of your preview, default false (applicable to the android and ios platforms only) | -| paddingBottom | number | (optional) The preview bottom padding in pixes. Useful to keep the appropriate preview sizes when orientation changes (applicable to the android and ios platforms only) | -| rotateWhenOrientationChanged | boolean | (optional) Rotate preview when orientation changes (applicable to the ios platforms only; default value is true) | -| storeToFile | boolean | (optional) Capture images to a file and return back the file path instead of returning base64 encoded data, default false. | -| disableExifHeaderStripping | boolean | (optional) Disable automatic rotation of the image, and let the browser deal with it, default true (applicable to the android and ios platforms only) | -| enableHighResolution | boolean | (optional) Defaults to false - iOS only - Activate high resolution image capture so that output images are from the highest resolution possible on the device | -| disableAudio | boolean | (optional) Disables audio stream to prevent permission requests, default false. (applicable to web and iOS only) | -| lockAndroidOrientation | boolean | (optional) Locks device orientation when camera is showing, default false. (applicable to Android only) | -| enableOpacity | boolean | (optional) Make the camera preview see-through. Ideal for augmented reality uses. Default false (applicable to Android and web only) | -| enableZoom | boolean | (optional) Set if you can pinch to zoom. Default false (applicable to the android and ios platforms only) | - - +| Option | values | descriptions | +|------------------------------|--------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------| +| position | front \ rear | Show front or rear camera when start the preview. Defaults to front | +| width | number | The preview width in pixels, default window.screen.width (applicable to the android and ios platforms only) | +| height | number | The preview height in pixels, default window.screen.height (applicable to the android and ios platforms only) | +| x | number | The x origin, default 0 (applicable to the android and ios platforms only) | +| y | number | The y origin, default 0 (applicable to the android and ios platforms only) | +| toBack | boolean | Brings your html in front of your preview, default false (applicable to the android and ios platforms only) | +| paddingBottom | number | The preview bottom padding in pixes. Useful to keep the appropriate preview sizes when orientation changes (applicable to the android and ios platforms only) | +| rotateWhenOrientationChanged | boolean | Rotate preview when orientation changes (applicable to the ios platforms only; default value is true) | +| storeToFile | boolean | Capture images to a file and return back the file path instead of returning base64 encoded data, default false. | +| disableExifHeaderStripping | boolean | Disable automatic rotation of the image, and let the browser deal with it, default true (applicable to the android and ios platforms only) | +| enableHighResolution | boolean | Defaults to false - iOS only - Activate high resolution image capture so that output images are from the highest resolution on the device (photo quality) | +| lockAndroidOrientation | boolean | Locks device orientation when camera is showing, default false. (applicable to Android only) | +| enableOpacity | boolean | Make the camera preview see-through. Ideal for augmented reality uses. Default false (applicable to Android and web only) | +| enableZoom | boolean | Set if you can pinch to zoom. Default false (applicable to the android and ios platforms only) | ```javascript import { CameraPreview, CameraPreviewOptions } from '@capacitor-community/camera-preview'; @@ -176,30 +141,6 @@ CameraPreview.stop(); CameraPreview.flip() ``` - - ### capture(options) | Option | values | descriptions | @@ -208,7 +149,7 @@ CameraPreview.hide(); | width | number | (optional) The picture width, best fit respecting the aspect ratio of the device (Android only) | | height | number | (optional) The picture height, best fit the aspect ratio of the device (Android only) | - +Take the picture. If width and height are not specified or are 0 it will use the defaults. If width and height are specified, it will choose a supported photo size that is closest to width and height specified and has closest aspect ratio to the preview (only on Android). The argument `quality` defaults to `85` and specifies the quality/compression value: `0=max compression`, `100=max quality`. ```javascript import { CameraPreviewPictureOptions } from '@capacitor-community/camera-preview'; @@ -219,9 +160,6 @@ const cameraPreviewPictureOptions: CameraPreviewPictureOptions = { const result = await CameraPreview.capture(cameraPreviewPictureOptions); const base64PictureData = result.value; - -// do sometime with base64PictureData - ``` ### captureSample(options) @@ -241,9 +179,6 @@ const cameraSampleOptions: CameraSampleOptions = { const result = await CameraPreview.captureSample(cameraSampleOptions); const base64PictureData = result.value; - -// do something with base64PictureData - ``` ### getSupportedFlashModes() @@ -266,28 +201,6 @@ const CameraPreviewFlashMode: CameraPreviewFlashMode = 'torch'; CameraPreview.setFlashMode(cameraPreviewFlashMode); ``` -### startRecordVideo(options) ---- ANDROID only - -Start capturing video
- -```javascript -const cameraPreviewOptions: CameraPreviewOptions = { - position: 'front', - width: window.screen.width, - height: window.screen.height, -}; - -CameraPreview.startRecordVideo(cameraPreviewOptions); -``` - -### stopRecordVideo() ---- ANDROID only - -Finish capturing a video. The captured video will be returned as a file path and the video format is .mp4
- -```javascript -const resultRecordVideo = await CameraPreview.stopRecordVideo(); -``` - ### setOpacity(options: CameraOpacityOptions): Promise<{}>; ---- ANDROID only Set the opacity for the camera preview
@@ -313,134 +226,6 @@ myCamera.setOpacity({opacity: 0.4}); | RED_EYE | string | red-eye | Android Only | | TORCH | string | torch | | - - # Demo A working example can be found at [Demo](https://github.com/capacitor-community/camera-preview/tree/master/demo) From ea00fb175b59fad9fbba63ecd54b06db324c5911 Mon Sep 17 00:00:00 2001 From: Michael Wolz Date: Fri, 9 Aug 2024 17:41:27 +0200 Subject: [PATCH 24/28] docs: update readme --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index f9fba9b6..556581e5 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,6 @@ Version 6 of this plugin requires Capacitor 6. **PR's are greatly appreciated.** -[@michaelwolz](https://github.com/michaelwolz) is the current maintainer of this version of the camera-preview plugin and will try to maintain it until the official capacitor-community plugin will gets updated again. # Installation From 5f8a96bcfa07a2d4f29d9b898ec8139ce1e242c8 Mon Sep 17 00:00:00 2001 From: Michael Wolz Date: Tue, 13 Aug 2024 08:58:51 +0200 Subject: [PATCH 25/28] fix(ios): improve type safety to prevent crashes --- ios/Plugin/Plugin.swift | 98 +++++++++++++++++++++-------------------- 1 file changed, 51 insertions(+), 47 deletions(-) diff --git a/ios/Plugin/Plugin.swift b/ios/Plugin/Plugin.swift index 789f3e1a..edeecf40 100644 --- a/ios/Plugin/Plugin.swift +++ b/ios/Plugin/Plugin.swift @@ -11,7 +11,7 @@ public class CameraPreview: CAPPlugin { var cameraPosition: CameraPosition = .rear var x: CGFloat = 0.0 var y: CGFloat = 0.0 - var previewView: UIView! + var previewView: UIView? var previewWidth: CGFloat = UIScreen.main.bounds.size.width var previewHeight: CGFloat = UIScreen.main.bounds.size.height var paddingBottom: CGFloat = 0 @@ -20,7 +20,7 @@ public class CameraPreview: CAPPlugin { var storeToFile = false var enableZoom = false var enableHighResolution = false - + /** Start the camera preview in a new UIView */ @@ -30,21 +30,21 @@ public class CameraPreview: CAPPlugin { call.reject("camera access not granted") return } - + // Initialize settings provided via API call self?.initializePluginSettings(call: call) - + if let captureSession = self?.cameraController.captureSession, captureSession.isRunning { call.reject("camera already started") return } - + self?.cameraController.prepare(cameraPosition: self?.cameraPosition, enableHighResolution: self?.enableHighResolution ?? false) { error in if let error = error { call.reject(error.localizedDescription) return } - + DispatchQueue.main.async { self?.displayCameraPreviewView() call.resolve() @@ -52,7 +52,7 @@ public class CameraPreview: CAPPlugin { } } } - + /** Stops any currently running capture session */ @@ -61,15 +61,15 @@ public class CameraPreview: CAPPlugin { call.reject("camera already stopped") return; } - + DispatchQueue.main.async { self.cameraController.stop() - self.previewView.removeFromSuperview() + self.previewView?.removeFromSuperview() self.webView?.isOpaque = true call.resolve() } } - + /** Capture a photo with the currently active capture device */ @@ -84,11 +84,11 @@ public class CameraPreview: CAPPlugin { call.reject("Image capture error") return } - + call.reject(error.localizedDescription) return } - + let imageData = image.jpegData(compressionQuality: CGFloat(quality / 100)) if self.storeToFile == false { @@ -106,7 +106,7 @@ public class CameraPreview: CAPPlugin { } } } - + @objc public func flip(_ call: CAPPluginCall) { do { try self.cameraController.switchCameras() @@ -115,21 +115,21 @@ public class CameraPreview: CAPPlugin { call.reject("failed to flip camera") } } - + /** Captures a sample image from the video stream. */ @objc func captureSample(_ call: CAPPluginCall) { DispatchQueue.main.async { let quality: Int = call.getInt("quality", 85) - + self.cameraController.captureSample { image, error in guard let image = image else { print("Image capture error: \(String(describing: error))") call.reject("Image capture error: \(String(describing: error))") return } - + let imageData: Data? if self.cameraPosition == .front { let flippedImage = image.withHorizontallyFlippedOrientation() @@ -137,7 +137,7 @@ public class CameraPreview: CAPPlugin { } else { imageData = image.jpegData(compressionQuality: CGFloat(quality / 100)) } - + if self.storeToFile == false { let imageBase64 = imageData?.base64EncodedString() call.resolve(["value": imageBase64!]) @@ -153,7 +153,7 @@ public class CameraPreview: CAPPlugin { } } } - + /** Return an array of supported flash modes of the currently active capture device */ @@ -165,7 +165,7 @@ public class CameraPreview: CAPPlugin { call.reject("failed to get supported flash modes") } } - + /** Set the flash mode for the currently active capture device */ @@ -174,7 +174,7 @@ public class CameraPreview: CAPPlugin { call.reject("failed to set flash mode. required parameter flashMode is missing") return } - + var flashModeAsEnum: AVCaptureDevice.FlashMode? switch flashMode { case "off": @@ -185,7 +185,7 @@ public class CameraPreview: CAPPlugin { flashModeAsEnum = AVCaptureDevice.FlashMode.auto default: break } - + do { if flashModeAsEnum != nil { try self.cameraController.setFlashMode(flashMode: flashModeAsEnum!) @@ -195,52 +195,52 @@ public class CameraPreview: CAPPlugin { call.reject("Flash Mode not supported") return } - + call.resolve() } catch { call.reject("failed to set flash mode") } } - + @objc func startRecordVideo(_ call: CAPPluginCall) { call.reject("Method not implemented on iOS platform") } - + @objc func stopRecordVideo(_ call: CAPPluginCall) { call.reject("Method not implemented on iOS platform") } - + /** Helper method for initializing the plugin settings based on the Capacitor call */ private func initializePluginSettings(call: CAPPluginCall) { self.cameraPosition = call.getString("position") == "front" ? .front : .rear - + if let previewWidth = call.getInt("width") { self.previewWidth = CGFloat(previewWidth) } else { self.previewWidth = UIScreen.main.bounds.size.width } - + if let previewHeight = call.getInt("height") { self.previewHeight = CGFloat(previewHeight) } else { self.previewHeight = UIScreen.main.bounds.size.height } - + self.x = CGFloat(call.getInt("x", 0)) / 2 self.y = CGFloat(call.getInt("y", 0)) / 2 - + self.paddingBottom = CGFloat(call.getInt("paddingBottom", 0)) - + self.rotateWhenOrientationChanged = call.getBool("rotateWhenOrientationChanged") ?? true - + self.toBack = call.getBool("toBack") ?? false self.storeToFile = call.getBool("storeToFile") ?? false self.enableZoom = call.getBool("enableZoom") ?? false - + self.enableHighResolution = call.getBool("enableHighResolution", false) } @@ -260,7 +260,7 @@ public class CameraPreview: CAPPlugin { call.resolve(["camera": cameraState]) } - + @objc public override func requestPermissions(_ call: CAPPluginCall) { AVCaptureDevice.requestAccess(for: .video) { [weak self] _ in self?.checkPermissions(call) @@ -275,33 +275,37 @@ public class CameraPreview: CAPPlugin { self.webView?.isOpaque = false self.webView?.backgroundColor = UIColor.clear self.webView?.scrollView.backgroundColor = UIColor.clear - self.webView?.superview?.addSubview(self.previewView) - + self.webView?.superview?.addSubview(self.previewView!) + if self.toBack { self.webView?.superview?.bringSubviewToFront(self.webView!) } - + if self.rotateWhenOrientationChanged { NotificationCenter.default.addObserver(self, selector: #selector(CameraPreview.rotated), name: UIDevice.orientationDidChangeNotification, object: nil) } - - self.cameraController.displayPreview(on: self.previewView) - - let frontView = self.toBack ? self.webView : self.previewView - self.cameraController.setupGestures(target: frontView ?? self.previewView, enableZoom: self.enableZoom) + + self.cameraController.displayPreview(on: self.previewView!) + + let frontView = self.toBack ? self.webView : self.previewView! + self.cameraController.setupGestures(target: frontView ?? self.previewView!, enableZoom: self.enableZoom) } - + /** Handler funciton for updating the previewLayer frame based on plugin settings and the current device orientation */ @objc private func rotated() { + guard let previewView = self.previewView else { + return + } + guard let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene else { return } - + let interfaceOrientation = windowScene.interfaceOrientation let height = self.previewHeight - self.paddingBottom - + if interfaceOrientation.isLandscape { previewView.frame = CGRect(x: self.y, y: self.x, width: max(height, self.previewWidth), height: min(height, self.previewWidth)) cameraController.previewLayer.frame = previewView.frame @@ -309,10 +313,10 @@ public class CameraPreview: CAPPlugin { previewView.frame = CGRect(x: self.x, y: self.y, width: min(height, self.previewWidth), height: max(height, self.previewWidth)) cameraController.previewLayer.frame = previewView.frame } - + cameraController.updateVideoOrientation() } - + /** Get user's cache directory path */ @@ -322,7 +326,7 @@ public class CameraPreview: CAPPlugin { let finalIdentifier = String(randomIdentifier.prefix(8)) let fileName="cpcp_capture_"+finalIdentifier+".jpg" let fileUrl=path.appendingPathComponent(fileName) - + return fileUrl } } From 9b05b8972d95a5c5a5419cf2585e557bf6ed81e4 Mon Sep 17 00:00:00 2001 From: Michael Wolz Date: Fri, 16 Aug 2024 10:27:20 +0200 Subject: [PATCH 26/28] fix: update dependencies --- ios/Podfile.lock | 8 +- package-lock.json | 2860 +++++++++++++++++++++++++++++++++------------ package.json | 43 +- 3 files changed, 2135 insertions(+), 776 deletions(-) diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 7842c214..47c0938b 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -1,7 +1,7 @@ PODS: - - Capacitor (6.0.0): + - Capacitor (6.1.2): - CapacitorCordova - - CapacitorCordova (6.0.0) + - CapacitorCordova (6.1.2) DEPENDENCIES: - "Capacitor (from `../node_modules/@capacitor/ios`)" @@ -14,8 +14,8 @@ EXTERNAL SOURCES: :path: "../node_modules/@capacitor/ios" SPEC CHECKSUMS: - Capacitor: 559d073c4ca6c27f8e7002c807eea94c3ba435a9 - CapacitorCordova: 8c4bfdf69368512e85b1d8b724dd7546abeb30af + Capacitor: 679f9673fdf30597493a6362a5d5bf233d46abc2 + CapacitorCordova: f48c89f96c319101cd2f0ce8a2b7449b5fb8b3dd PODFILE CHECKSUM: 14e8b2400457751b865e1c327e7cfa1c6fa67da6 diff --git a/package-lock.json b/package-lock.json index dc52f9b0..017aefb1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,30 +1,30 @@ { - "name": "@capacitor-community/camera-preview", + "name": "@michaelwolz/camera-preview-lite", "version": "6.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "@capacitor-community/camera-preview", + "name": "@michaelwolz/camera-preview-lite", "version": "6.0.0", "license": "MIT", "devDependencies": { - "@capacitor/android": "^6.0.0", - "@capacitor/core": "^6.0.0", - "@capacitor/ios": "^6.0.0", - "@ionic/eslint-config": "^0.3.0", - "@ionic/prettier-config": "^2.0.0", + "@capacitor/android": "^6.1.2", + "@capacitor/core": "^6.1.2", + "@capacitor/ios": "^6.1.2", + "@ionic/eslint-config": "^0.4.0", + "@ionic/prettier-config": "^4.0.0", "@ionic/swiftlint-config": "^1.1.2", - "concurrently": "^7.0.0", - "eslint": "^7.32.0", - "husky": "^7.0.4", - "prettier": "^2.5.1", - "prettier-plugin-java": "^1.6.1", - "pretty-quick": "^3.1.3", - "rimraf": "^3.0.2", - "rollup": "^2.79.1", - "swiftlint": "^1.0.1", - "typescript": "^4.3.2" + "concurrently": "^8.2.2", + "eslint": "^8.57.0", + "husky": "^9.1.4", + "prettier": "^3.3.3", + "prettier-plugin-java": "^2.6.4", + "pretty-quick": "^4.0.0", + "rimraf": "^6.0.1", + "rollup": "^4.20.0", + "swiftlint": "^1.0.2", + "typescript": "^5.5.4" }, "peerDependencies": { "@capacitor/core": "^6.0.0" @@ -135,97 +135,367 @@ } }, "node_modules/@capacitor/android": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@capacitor/android/-/android-6.0.0.tgz", - "integrity": "sha512-NwL87VO9F1WY/EgvJZN9pIhjejq688k2fRW6XWNLVe3cgGE6nUb9J34KI68fhx3139cf2LVGPUYs+mwZC8esiQ==", + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/@capacitor/android/-/android-6.1.2.tgz", + "integrity": "sha512-Yh0gQDY1bgRrL25J6ecIlvvs2kF8iNSwIPXjyw6Yz9mnwYxBazF5KZbjpKtGPnJgicJhFkYGsqOkEtxrve0EoQ==", "dev": true, + "license": "MIT", "peerDependencies": { - "@capacitor/core": "^6.0.0" + "@capacitor/core": "^6.1.0" } }, "node_modules/@capacitor/core": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@capacitor/core/-/core-6.0.0.tgz", - "integrity": "sha512-NvxIQsJcMiIV+Le1DilR2GGyQQbDInfXK1UywGROQ5mycdFlW5XoAPZ+MKnFGB123RoEgE3uhDGgwTXUmSlX9A==", + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/@capacitor/core/-/core-6.1.2.tgz", + "integrity": "sha512-xFy1/4qLFLp5WCIzIhtwUuVNNoz36+V7/BzHmLqgVJcvotc4MMjswW/TshnPQaLLujEOaLkA4h8ZJ0uoK3ImGg==", "dev": true, + "license": "MIT", "dependencies": { "tslib": "^2.1.0" } }, "node_modules/@capacitor/ios": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@capacitor/ios/-/ios-6.0.0.tgz", - "integrity": "sha512-7mAs3gjWiE5DPM4AGPduqFSDGXCPwwqQRMzbohVway7/cTWnHomHV8mIojMZE4GILeWO2fILbyu3C8q9pHg2vg==", + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/@capacitor/ios/-/ios-6.1.2.tgz", + "integrity": "sha512-HaeW68KisBd/7TmavzPDlL2bpoDK5AjR2ZYrqU4TlGwM88GtQfvduBCAlSCj20X0w/4+rWMkseD9dAAkacjiyQ==", "dev": true, + "license": "MIT", "peerDependencies": { - "@capacitor/core": "^6.0.0" + "@capacitor/core": "^6.1.0" + } + }, + "node_modules/@chevrotain/cst-dts-gen": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/@chevrotain/cst-dts-gen/-/cst-dts-gen-11.0.3.tgz", + "integrity": "sha512-BvIKpRLeS/8UbfxXxgC33xOumsacaeCKAjAeLyOn7Pcp95HiRbrpl14S+9vaZLolnbssPIUuiUd8IvgkRyt6NQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@chevrotain/gast": "11.0.3", + "@chevrotain/types": "11.0.3", + "lodash-es": "4.17.21" + } + }, + "node_modules/@chevrotain/gast": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/@chevrotain/gast/-/gast-11.0.3.tgz", + "integrity": "sha512-+qNfcoNk70PyS/uxmj3li5NiECO+2YKZZQMbmjTqRI3Qchu8Hig/Q9vgkHpI3alNjr7M+a2St5pw5w5F6NL5/Q==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@chevrotain/types": "11.0.3", + "lodash-es": "4.17.21" + } + }, + "node_modules/@chevrotain/regexp-to-ast": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/@chevrotain/regexp-to-ast/-/regexp-to-ast-11.0.3.tgz", + "integrity": "sha512-1fMHaBZxLFvWI067AVbGJav1eRY7N8DDvYCTwGBiE/ytKBgP8azTdgyrKyWZ9Mfh09eHWb5PgTSO8wi7U824RA==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/@chevrotain/types": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/@chevrotain/types/-/types-11.0.3.tgz", + "integrity": "sha512-gsiM3G8b58kZC2HaWR50gu6Y1440cHiJ+i3JUvcp/35JchYejb2+5MVeJK0iKThYpAa/P2PYFV4hoi44HD+aHQ==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/@chevrotain/utils": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/@chevrotain/utils/-/utils-11.0.3.tgz", + "integrity": "sha512-YslZMgtJUyuMbZ+aKvfF3x1f5liK4mWNxghFRv7jqRR9C3R3fAOGTTKvxXDa2Y1s9zSbcpuO0cAxDYsc9SrXoQ==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.0.tgz", + "integrity": "sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, "node_modules/@eslint/eslintrc": { - "version": "0.4.3", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", "dev": true, "license": "MIT", "dependencies": { "ajv": "^6.12.4", - "debug": "^4.1.1", - "espree": "^7.3.0", - "globals": "^13.9.0", - "ignore": "^4.0.6", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", "import-fresh": "^3.2.1", - "js-yaml": "^3.13.1", - "minimatch": "^3.0.4", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/@eslint/eslintrc/node_modules/ignore": { - "version": "4.0.6", + "node_modules/@eslint/js": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", + "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", "dev": true, "license": "MIT", "engines": { - "node": ">= 4" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, "node_modules/@humanwhocodes/config-array": { - "version": "0.5.0", + "version": "0.11.14", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", + "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", + "deprecated": "Use @eslint/config-array instead", "dev": true, "license": "Apache-2.0", "dependencies": { - "@humanwhocodes/object-schema": "^1.2.0", - "debug": "^4.1.1", - "minimatch": "^3.0.4" + "@humanwhocodes/object-schema": "^2.0.2", + "debug": "^4.3.1", + "minimatch": "^3.0.5" }, "engines": { "node": ">=10.10.0" } }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, "node_modules/@humanwhocodes/object-schema": { - "version": "1.2.1", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", + "deprecated": "Use @eslint/object-schema instead", "dev": true, "license": "BSD-3-Clause" }, "node_modules/@ionic/eslint-config": { - "version": "0.3.0", + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@ionic/eslint-config/-/eslint-config-0.4.0.tgz", + "integrity": "sha512-L8OXY29D3iGqNtteFj0iz3eoZIVgokBiVjCO8WMssNZa4GTHjYsase0rC9ASXGefMnLJu6rbNl3Gbx7NNxJRZQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "^4.1.0", - "@typescript-eslint/parser": "^4.1.0", - "eslint-config-prettier": "^6.11.0", - "eslint-plugin-import": "^2.22.0" + "@typescript-eslint/eslint-plugin": "^5.58.0", + "@typescript-eslint/parser": "^5.58.0", + "eslint-config-prettier": "^8.8.0", + "eslint-plugin-import": "^2.27.0" }, "peerDependencies": { "eslint": ">=7" } }, + "node_modules/@ionic/eslint-config/node_modules/@typescript-eslint/eslint-plugin": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz", + "integrity": "sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.4.0", + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/type-utils": "5.62.0", + "@typescript-eslint/utils": "5.62.0", + "debug": "^4.3.4", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "natural-compare-lite": "^1.4.0", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^5.0.0", + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@ionic/eslint-config/node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz", + "integrity": "sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@types/json-schema": "^7.0.9", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/typescript-estree": "5.62.0", + "eslint-scope": "^5.1.1", + "semver": "^7.3.7" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/@ionic/eslint-config/node_modules/@typescript-eslint/parser": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.62.0.tgz", + "integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/typescript-estree": "5.62.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@ionic/eslint-config/node_modules/eslint-plugin-import": { + "version": "2.29.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz", + "integrity": "sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-includes": "^3.1.7", + "array.prototype.findlastindex": "^1.2.3", + "array.prototype.flat": "^1.3.2", + "array.prototype.flatmap": "^1.3.2", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.9", + "eslint-module-utils": "^2.8.0", + "hasown": "^2.0.0", + "is-core-module": "^2.13.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.7", + "object.groupby": "^1.0.1", + "object.values": "^1.1.7", + "semver": "^6.3.1", + "tsconfig-paths": "^3.15.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" + } + }, + "node_modules/@ionic/eslint-config/node_modules/eslint-plugin-import/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/@ionic/eslint-config/node_modules/eslint-plugin-import/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@ionic/eslint-config/node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@ionic/eslint-config/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, "node_modules/@ionic/prettier-config": { - "version": "2.1.2", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@ionic/prettier-config/-/prettier-config-4.0.0.tgz", + "integrity": "sha512-0DqL6CggVdgeJAWOLPUT73rF1VD5p0tVlCpC5GXz5vTIUBxNwsJ5085Q7wXjKiE5Odx3aOHGTcuRWCawFsLFag==", "dev": true, "license": "MIT", "peerDependencies": { - "prettier": "^2.4.0" + "prettier": "^2.4.0 || ^3.0.0" } }, "node_modules/@ionic/swiftlint-config": { @@ -336,8 +606,113 @@ "node": ">=10.3.0" } }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", "dev": true, "license": "MIT", "dependencies": { @@ -350,6 +725,8 @@ }, "node_modules/@nodelib/fs.stat": { "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "dev": true, "license": "MIT", "engines": { @@ -358,6 +735,8 @@ }, "node_modules/@nodelib/fs.walk": { "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "dev": true, "license": "MIT", "dependencies": { @@ -368,6 +747,248 @@ "node": ">= 8" } }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.20.0.tgz", + "integrity": "sha512-TSpWzflCc4VGAUJZlPpgAJE1+V60MePDQnBd7PPkpuEmOy8i87aL6tinFGKBFKuEDikYpig72QzdT3QPYIi+oA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.20.0.tgz", + "integrity": "sha512-u00Ro/nok7oGzVuh/FMYfNoGqxU5CPWz1mxV85S2w9LxHR8OoMQBuSk+3BKVIDYgkpeOET5yXkx90OYFc+ytpQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.20.0.tgz", + "integrity": "sha512-uFVfvzvsdGtlSLuL0ZlvPJvl6ZmrH4CBwLGEFPe7hUmf7htGAN+aXo43R/V6LATyxlKVC/m6UsLb7jbG+LG39Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.20.0.tgz", + "integrity": "sha512-xbrMDdlev53vNXexEa6l0LffojxhqDTBeL+VUxuuIXys4x6xyvbKq5XqTXBCEUA8ty8iEJblHvFaWRJTk/icAQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.20.0.tgz", + "integrity": "sha512-jMYvxZwGmoHFBTbr12Xc6wOdc2xA5tF5F2q6t7Rcfab68TT0n+r7dgawD4qhPEvasDsVpQi+MgDzj2faOLsZjA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.20.0.tgz", + "integrity": "sha512-1asSTl4HKuIHIB1GcdFHNNZhxAYEdqML/MW4QmPS4G0ivbEcBr1JKlFLKsIRqjSwOBkdItn3/ZDlyvZ/N6KPlw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.20.0.tgz", + "integrity": "sha512-COBb8Bkx56KldOYJfMf6wKeYJrtJ9vEgBRAOkfw6Ens0tnmzPqvlpjZiLgkhg6cA3DGzCmLmmd319pmHvKWWlQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.20.0.tgz", + "integrity": "sha512-+it+mBSyMslVQa8wSPvBx53fYuZK/oLTu5RJoXogjk6x7Q7sz1GNRsXWjn6SwyJm8E/oMjNVwPhmNdIjwP135Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.20.0.tgz", + "integrity": "sha512-yAMvqhPfGKsAxHN8I4+jE0CpLWD8cv4z7CK7BMmhjDuz606Q2tFKkWRY8bHR9JQXYcoLfopo5TTqzxgPUjUMfw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.20.0.tgz", + "integrity": "sha512-qmuxFpfmi/2SUkAw95TtNq/w/I7Gpjurx609OOOV7U4vhvUhBcftcmXwl3rqAek+ADBwSjIC4IVNLiszoj3dPA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.20.0.tgz", + "integrity": "sha512-I0BtGXddHSHjV1mqTNkgUZLnS3WtsqebAXv11D5BZE/gfw5KoyXSAXVqyJximQXNvNzUo4GKlCK/dIwXlz+jlg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.20.0.tgz", + "integrity": "sha512-y+eoL2I3iphUg9tN9GB6ku1FA8kOfmF4oUEWhztDJ4KXJy1agk/9+pejOuZkNFhRwHAOxMsBPLbXPd6mJiCwew==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.20.0.tgz", + "integrity": "sha512-hM3nhW40kBNYUkZb/r9k2FKK+/MnKglX7UYd4ZUy5DJs8/sMsIbqWK2piZtVGE3kcXVNj3B2IrUYROJMMCikNg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.20.0.tgz", + "integrity": "sha512-psegMvP+Ik/Bg7QRJbv8w8PAytPA7Uo8fpFjXyCRHWm6Nt42L+JtoqH8eDQ5hRP7/XW2UiIriy1Z46jf0Oa1kA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.20.0.tgz", + "integrity": "sha512-GabekH3w4lgAJpVxkk7hUzUf2hICSQO0a/BLFA11/RMxQT92MabKAqyubzDZmMOC/hcJNlc+rrypzNzYl4Dx7A==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.20.0.tgz", + "integrity": "sha512-aJ1EJSuTdGnM6qbVC4B5DSmozPTqIag9fSzXRNNo+humQLG89XpPgdt16Ia56ORD7s+H8Pmyx44uczDQ0yDzpg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/fs-extra": { "version": "8.1.2", "dev": true, @@ -377,17 +998,16 @@ } }, "node_modules/@types/json-schema": { - "version": "7.0.11", + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "dev": true, "license": "MIT" }, "node_modules/@types/json5": { "version": "0.0.29", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/minimatch": { - "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", "dev": true, "license": "MIT" }, @@ -401,35 +1021,57 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/semver": { + "version": "7.5.8", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", + "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/slice-ansi": { "version": "4.0.0", "dev": true, "license": "MIT" }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "4.33.0", + "node_modules/@typescript-eslint/scope-manager": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz", + "integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/experimental-utils": "4.33.0", - "@typescript-eslint/scope-manager": "4.33.0", - "debug": "^4.3.1", - "functional-red-black-tree": "^1.0.1", - "ignore": "^5.1.8", - "regexpp": "^3.1.0", - "semver": "^7.3.5", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.62.0.tgz", + "integrity": "sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/typescript-estree": "5.62.0", + "@typescript-eslint/utils": "5.62.0", + "debug": "^4.3.4", "tsutils": "^3.21.0" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^4.0.0", - "eslint": "^5.0.0 || ^6.0.0 || ^7.0.0" + "eslint": "*" }, "peerDependenciesMeta": { "typescript": { @@ -437,77 +1079,65 @@ } } }, - "node_modules/@typescript-eslint/experimental-utils": { - "version": "4.33.0", + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/utils": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz", + "integrity": "sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==", "dev": true, "license": "MIT", "dependencies": { - "@types/json-schema": "^7.0.7", - "@typescript-eslint/scope-manager": "4.33.0", - "@typescript-eslint/types": "4.33.0", - "@typescript-eslint/typescript-estree": "4.33.0", + "@eslint-community/eslint-utils": "^4.2.0", + "@types/json-schema": "^7.0.9", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/typescript-estree": "5.62.0", "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0" + "semver": "^7.3.7" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "*" + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "node_modules/@typescript-eslint/parser": { - "version": "4.33.0", + "node_modules/@typescript-eslint/type-utils/node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", "dev": true, "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/scope-manager": "4.33.0", - "@typescript-eslint/types": "4.33.0", - "@typescript-eslint/typescript-estree": "4.33.0", - "debug": "^4.3.1" + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" }, "engines": { - "node": "^10.12.0 || >=12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^5.0.0 || ^6.0.0 || ^7.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "node": ">=8.0.0" } }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "4.33.0", + "node_modules/@typescript-eslint/type-utils/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "4.33.0", - "@typescript-eslint/visitor-keys": "4.33.0" - }, + "license": "BSD-2-Clause", "engines": { - "node": "^8.10.0 || ^10.13.0 || >=11.10.1" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "node": ">=4.0" } }, "node_modules/@typescript-eslint/types": { - "version": "4.33.0", + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz", + "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==", "dev": true, "license": "MIT", "engines": { - "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { "type": "opencollective", @@ -515,20 +1145,22 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "4.33.0", + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz", + "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==", "dev": true, "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/types": "4.33.0", - "@typescript-eslint/visitor-keys": "4.33.0", - "debug": "^4.3.1", - "globby": "^11.0.3", - "is-glob": "^4.0.1", - "semver": "^7.3.5", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", "tsutils": "^3.21.0" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { "type": "opencollective", @@ -541,23 +1173,34 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "4.33.0", + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz", + "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "4.33.0", - "eslint-visitor-keys": "^2.0.0" + "@typescript-eslint/types": "5.62.0", + "eslint-visitor-keys": "^3.3.0" }, "engines": { - "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "dev": true, + "license": "ISC" + }, "node_modules/acorn": { - "version": "7.4.1", + "version": "8.12.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", + "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", "dev": true, "license": "MIT", "bin": { @@ -569,6 +1212,8 @@ }, "node_modules/acorn-jsx": { "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true, "license": "MIT", "peerDependencies": { @@ -577,6 +1222,8 @@ }, "node_modules/ajv": { "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, "license": "MIT", "dependencies": { @@ -590,14 +1237,6 @@ "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/ansi-colors": { - "version": "4.1.3", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/ansi-regex": { "version": "5.0.1", "dev": true, @@ -621,42 +1260,41 @@ } }, "node_modules/argparse": { - "version": "1.0.10", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true, - "license": "MIT", - "dependencies": { - "sprintf-js": "~1.0.2" - } + "license": "Python-2.0" }, "node_modules/array-buffer-byte-length": { - "version": "1.0.0", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz", + "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "is-array-buffer": "^3.0.1" + "call-bind": "^1.0.5", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/array-differ": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/array-includes": { - "version": "3.1.6", + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz", + "integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "get-intrinsic": "^1.1.3", + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.4", "is-string": "^1.0.7" }, "engines": { @@ -668,20 +1306,45 @@ }, "node_modules/array-union": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", "dev": true, "license": "MIT", "engines": { "node": ">=8" } }, + "node_modules/array.prototype.findlastindex": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz", + "integrity": "sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/array.prototype.flat": { - "version": "1.3.1", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", + "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", "es-shim-unscopables": "^1.0.0" }, "engines": { @@ -692,13 +1355,15 @@ } }, "node_modules/array.prototype.flatmap": { - "version": "1.3.1", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", + "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", "es-shim-unscopables": "^1.0.0" }, "engines": { @@ -708,12 +1373,27 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/arrify": { - "version": "2.0.1", + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz", + "integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==", "dev": true, "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "es-abstract": "^1.22.3", + "es-errors": "^1.2.1", + "get-intrinsic": "^1.2.3", + "is-array-buffer": "^3.0.4", + "is-shared-array-buffer": "^1.0.2" + }, "engines": { - "node": ">=8" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/astral-regex": { @@ -733,9 +1413,14 @@ } }, "node_modules/available-typed-arrays": { - "version": "1.0.5", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", "dev": true, "license": "MIT", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, "engines": { "node": ">= 0.4" }, @@ -758,23 +1443,33 @@ } }, "node_modules/braces": { - "version": "3.0.2", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, "license": "MIT", "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" } }, "node_modules/call-bind": { - "version": "1.0.2", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", "dev": true, "license": "MIT", "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -815,11 +1510,31 @@ } }, "node_modules/chevrotain": { - "version": "6.5.0", + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-11.0.3.tgz", + "integrity": "sha512-ci2iJH6LeIkvP9eJW6gpueU8cnZhv85ELY8w8WiFtNjMHA5ad6pQLaJo9mEly/9qUyCpvqX8/POVUTf18/HFdw==", "dev": true, "license": "Apache-2.0", "dependencies": { - "regexp-to-ast": "0.4.0" + "@chevrotain/cst-dts-gen": "11.0.3", + "@chevrotain/gast": "11.0.3", + "@chevrotain/regexp-to-ast": "11.0.3", + "@chevrotain/types": "11.0.3", + "@chevrotain/utils": "11.0.3", + "lodash-es": "4.17.21" + } + }, + "node_modules/chevrotain-allstar": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/chevrotain-allstar/-/chevrotain-allstar-0.3.1.tgz", + "integrity": "sha512-b7g+y9A0v4mxCW1qUhf3BSVPg+/NvGErk/dOkrDaHA0nQIQGAtrOjlX//9OQtRlSCy+x9rfB5N8yC71lH1nvMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash-es": "^4.17.21" + }, + "peerDependencies": { + "chevrotain": "^11.0.0" } }, "node_modules/cliui": { @@ -857,26 +1572,28 @@ "license": "MIT" }, "node_modules/concurrently": { - "version": "7.6.0", + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-8.2.2.tgz", + "integrity": "sha512-1dP4gpXFhei8IOtlXRE/T/4H88ElHgTiUzh71YUmtjTEHMSRS2Z/fgOxHSxxusGHogsRfxNq1vyAwxSC+EVyDg==", "dev": true, "license": "MIT", "dependencies": { - "chalk": "^4.1.0", - "date-fns": "^2.29.1", + "chalk": "^4.1.2", + "date-fns": "^2.30.0", "lodash": "^4.17.21", - "rxjs": "^7.0.0", - "shell-quote": "^1.7.3", - "spawn-command": "^0.0.2-1", - "supports-color": "^8.1.0", + "rxjs": "^7.8.1", + "shell-quote": "^1.8.1", + "spawn-command": "0.0.2", + "supports-color": "^8.1.1", "tree-kill": "^1.2.2", - "yargs": "^17.3.1" + "yargs": "^17.7.2" }, "bin": { "conc": "dist/bin/concurrently.js", "concurrently": "dist/bin/concurrently.js" }, "engines": { - "node": "^12.20.0 || ^14.13.0 || >=16.0.0" + "node": "^14.13.0 || >=16.0.0" }, "funding": { "url": "https://github.com/open-cli-tools/concurrently?sponsor=1" @@ -910,6 +1627,60 @@ "node": ">= 8" } }, + "node_modules/data-view-buffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz", + "integrity": "sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz", + "integrity": "sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz", + "integrity": "sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/date-fns": { "version": "2.30.0", "dev": true, @@ -943,14 +1714,37 @@ }, "node_modules/deep-is": { "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true, "license": "MIT" }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/define-properties": { - "version": "1.2.0", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", "dev": true, "license": "MIT", "dependencies": { + "define-data-property": "^1.0.1", "has-property-descriptors": "^1.0.0", "object-keys": "^1.1.1" }, @@ -963,6 +1757,8 @@ }, "node_modules/dir-glob": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", "dev": true, "license": "MIT", "dependencies": { @@ -973,39 +1769,29 @@ } }, "node_modules/doctrine": { - "version": "3.0.0", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", "dev": true, "license": "Apache-2.0", "dependencies": { "esutils": "^2.0.2" }, "engines": { - "node": ">=6.0.0" + "node": ">=0.10.0" } }, - "node_modules/emoji-regex": { - "version": "8.0.0", + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", "dev": true, "license": "MIT" }, - "node_modules/end-of-stream": { - "version": "1.4.4", - "dev": true, - "license": "MIT", - "dependencies": { - "once": "^1.4.0" - } - }, - "node_modules/enquirer": { - "version": "2.3.6", + "node_modules/emoji-regex": { + "version": "8.0.0", "dev": true, - "license": "MIT", - "dependencies": { - "ansi-colors": "^4.1.1" - }, - "engines": { - "node": ">=8.6" - } + "license": "MIT" }, "node_modules/error-ex": { "version": "1.3.2", @@ -1016,44 +1802,58 @@ } }, "node_modules/es-abstract": { - "version": "1.21.2", - "dev": true, - "license": "MIT", - "dependencies": { - "array-buffer-byte-length": "^1.0.0", - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "es-set-tostringtag": "^2.0.1", + "version": "1.23.3", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz", + "integrity": "sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "arraybuffer.prototype.slice": "^1.0.3", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "data-view-buffer": "^1.0.1", + "data-view-byte-length": "^1.0.1", + "data-view-byte-offset": "^1.0.0", + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-set-tostringtag": "^2.0.3", "es-to-primitive": "^1.2.1", - "function.prototype.name": "^1.1.5", - "get-intrinsic": "^1.2.0", - "get-symbol-description": "^1.0.0", + "function.prototype.name": "^1.1.6", + "get-intrinsic": "^1.2.4", + "get-symbol-description": "^1.0.2", "globalthis": "^1.0.3", "gopd": "^1.0.1", - "has": "^1.0.3", - "has-property-descriptors": "^1.0.0", - "has-proto": "^1.0.1", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.0.3", "has-symbols": "^1.0.3", - "internal-slot": "^1.0.5", - "is-array-buffer": "^3.0.2", + "hasown": "^2.0.2", + "internal-slot": "^1.0.7", + "is-array-buffer": "^3.0.4", "is-callable": "^1.2.7", - "is-negative-zero": "^2.0.2", + "is-data-view": "^1.0.1", + "is-negative-zero": "^2.0.3", "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", + "is-shared-array-buffer": "^1.0.3", "is-string": "^1.0.7", - "is-typed-array": "^1.1.10", + "is-typed-array": "^1.1.13", "is-weakref": "^1.0.2", - "object-inspect": "^1.12.3", + "object-inspect": "^1.13.1", "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.4.3", - "safe-regex-test": "^1.0.0", - "string.prototype.trim": "^1.2.7", - "string.prototype.trimend": "^1.0.6", - "string.prototype.trimstart": "^1.0.6", - "typed-array-length": "^1.0.4", + "object.assign": "^4.1.5", + "regexp.prototype.flags": "^1.5.2", + "safe-array-concat": "^1.1.2", + "safe-regex-test": "^1.0.3", + "string.prototype.trim": "^1.2.9", + "string.prototype.trimend": "^1.0.8", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.2", + "typed-array-byte-length": "^1.0.1", + "typed-array-byte-offset": "^1.0.2", + "typed-array-length": "^1.0.6", "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.9" + "which-typed-array": "^1.1.15" }, "engines": { "node": ">= 0.4" @@ -1062,29 +1862,71 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", + "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/es-set-tostringtag": { - "version": "2.0.1", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz", + "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==", "dev": true, "license": "MIT", "dependencies": { - "get-intrinsic": "^1.1.3", - "has": "^1.0.3", - "has-tostringtag": "^1.0.0" + "get-intrinsic": "^1.2.4", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.1" }, "engines": { "node": ">= 0.4" } }, "node_modules/es-shim-unscopables": { - "version": "1.0.0", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", + "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", "dev": true, "license": "MIT", "dependencies": { - "has": "^1.0.3" + "hasown": "^2.0.0" } }, "node_modules/es-to-primitive": { "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", "dev": true, "license": "MIT", "dependencies": { @@ -1119,87 +1961,90 @@ } }, "node_modules/eslint": { - "version": "7.32.0", + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", + "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "7.12.11", - "@eslint/eslintrc": "^0.4.3", - "@humanwhocodes/config-array": "^0.5.0", - "ajv": "^6.10.0", + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.0", + "@humanwhocodes/config-array": "^0.11.14", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", - "debug": "^4.0.1", + "debug": "^4.3.2", "doctrine": "^3.0.0", - "enquirer": "^2.3.5", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^5.1.1", - "eslint-utils": "^2.1.0", - "eslint-visitor-keys": "^2.0.0", - "espree": "^7.3.1", - "esquery": "^1.4.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^6.0.1", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^5.1.2", - "globals": "^13.6.0", - "ignore": "^4.0.6", - "import-fresh": "^3.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", - "js-yaml": "^3.13.1", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", "lodash.merge": "^4.6.2", - "minimatch": "^3.0.4", + "minimatch": "^3.1.2", "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "progress": "^2.0.0", - "regexpp": "^3.1.0", - "semver": "^7.2.1", - "strip-ansi": "^6.0.0", - "strip-json-comments": "^3.1.0", - "table": "^6.0.9", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" }, "bin": { "eslint": "bin/eslint.js" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { "url": "https://opencollective.com/eslint" } }, "node_modules/eslint-config-prettier": { - "version": "6.15.0", + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.10.0.tgz", + "integrity": "sha512-SM8AMJdeQqRYT9O9zguiruQZaN7+z+E4eAP9oiLNGKMtomwaB1E9dcgUD6ZAn/eQAb52USbvezbiljfZUhbJcg==", "dev": true, "license": "MIT", - "dependencies": { - "get-stdin": "^6.0.0" - }, "bin": { - "eslint-config-prettier-check": "bin/cli.js" + "eslint-config-prettier": "bin/cli.js" }, "peerDependencies": { - "eslint": ">=3.14.1" + "eslint": ">=7.0.0" } }, "node_modules/eslint-import-resolver-node": { - "version": "0.3.7", + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", + "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", "dev": true, "license": "MIT", "dependencies": { "debug": "^3.2.7", - "is-core-module": "^2.11.0", - "resolve": "^1.22.1" + "is-core-module": "^2.13.0", + "resolve": "^1.22.4" } }, "node_modules/eslint-import-resolver-node/node_modules/debug": { "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, "license": "MIT", "dependencies": { @@ -1207,7 +2052,9 @@ } }, "node_modules/eslint-module-utils": { - "version": "2.8.0", + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.1.tgz", + "integrity": "sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==", "dev": true, "license": "MIT", "dependencies": { @@ -1224,165 +2071,73 @@ }, "node_modules/eslint-module-utils/node_modules/debug": { "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, "license": "MIT", "dependencies": { "ms": "^2.1.1" } }, - "node_modules/eslint-plugin-import": { - "version": "2.27.5", - "dev": true, - "license": "MIT", - "dependencies": { - "array-includes": "^3.1.6", - "array.prototype.flat": "^1.3.1", - "array.prototype.flatmap": "^1.3.1", - "debug": "^3.2.7", - "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.7", - "eslint-module-utils": "^2.7.4", - "has": "^1.0.3", - "is-core-module": "^2.11.0", - "is-glob": "^4.0.3", - "minimatch": "^3.1.2", - "object.values": "^1.1.6", - "resolve": "^1.22.1", - "semver": "^6.3.0", - "tsconfig-paths": "^3.14.1" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" - } - }, - "node_modules/eslint-plugin-import/node_modules/debug": { - "version": "3.2.7", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-plugin-import/node_modules/doctrine": { - "version": "2.1.0", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint-plugin-import/node_modules/semver": { - "version": "6.3.0", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, "node_modules/eslint-scope": { - "version": "5.1.1", + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", "dev": true, "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/eslint-utils": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "eslint-visitor-keys": "^2.0.0" + "estraverse": "^5.2.0" }, "engines": { - "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=5" + "url": "https://opencollective.com/eslint" } }, "node_modules/eslint-visitor-keys": { - "version": "2.1.0", + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, "license": "Apache-2.0", "engines": { - "node": ">=10" - } - }, - "node_modules/eslint/node_modules/eslint-utils": { - "version": "2.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "eslint-visitor-keys": "^1.1.0" - }, - "engines": { - "node": ">=6" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { - "url": "https://github.com/sponsors/mysticatea" + "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint/node_modules/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "1.3.0", + "node_modules/eslint/node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", "dev": true, "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, "engines": { - "node": ">=4" - } - }, - "node_modules/eslint/node_modules/ignore": { - "version": "4.0.6", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" + "node": ">=6.0.0" } }, "node_modules/espree": { - "version": "7.3.1", + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", "dev": true, "license": "BSD-2-Clause", "dependencies": { - "acorn": "^7.4.0", - "acorn-jsx": "^5.3.1", - "eslint-visitor-keys": "^1.3.0" + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" }, "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/espree/node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=4" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "dev": true, - "license": "BSD-2-Clause", - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, - "engines": { - "node": ">=4" + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/esquery": { @@ -1396,16 +2151,10 @@ "node": ">=0.10" } }, - "node_modules/esquery/node_modules/estraverse": { - "version": "5.3.0", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.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==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -1415,16 +2164,10 @@ "node": ">=4.0" } }, - "node_modules/esrecurse/node_modules/estraverse": { - "version": "5.3.0", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" - } - }, "node_modules/estraverse": { - "version": "4.3.0", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, "license": "BSD-2-Clause", "engines": { @@ -1440,18 +2183,20 @@ } }, "node_modules/execa": { - "version": "4.1.0", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", "dev": true, "license": "MIT", "dependencies": { - "cross-spawn": "^7.0.0", - "get-stream": "^5.0.0", - "human-signals": "^1.1.1", + "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.0", - "onetime": "^5.1.0", - "signal-exit": "^3.0.2", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", "strip-final-newline": "^2.0.0" }, "engines": { @@ -1463,11 +2208,15 @@ }, "node_modules/fast-deep-equal": { "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "dev": true, "license": "MIT" }, "node_modules/fast-glob": { - "version": "3.2.12", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", "dev": true, "license": "MIT", "dependencies": { @@ -1481,18 +2230,37 @@ "node": ">=8.6.0" } }, + "node_modules/fast-glob/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==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "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==", "dev": true, "license": "MIT" }, "node_modules/fast-levenshtein": { "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true, "license": "MIT" }, "node_modules/fastq": { - "version": "1.15.0", + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", "dev": true, "license": "ISC", "dependencies": { @@ -1501,6 +2269,8 @@ }, "node_modules/file-entry-cache": { "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", "dev": true, "license": "MIT", "dependencies": { @@ -1511,7 +2281,9 @@ } }, "node_modules/fill-range": { - "version": "7.0.1", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, "license": "MIT", "dependencies": { @@ -1522,42 +2294,123 @@ } }, "node_modules/find-up": { - "version": "4.1.0", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, "license": "MIT", "dependencies": { - "locate-path": "^5.0.0", + "locate-path": "^6.0.0", "path-exists": "^4.0.0" }, "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/flat-cache": { - "version": "3.0.4", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", "dev": true, "license": "MIT", "dependencies": { - "flatted": "^3.1.0", + "flatted": "^3.2.9", + "keyv": "^4.5.3", "rimraf": "^3.0.2" }, "engines": { "node": "^10.12.0 || >=12.0.0" } }, + "node_modules/flat-cache/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/flat-cache/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/flatted": { - "version": "3.2.7", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", "dev": true, "license": "ISC" }, "node_modules/for-each": { "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", "dev": true, "license": "MIT", "dependencies": { "is-callable": "^1.1.3" } }, + "node_modules/foreground-child": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", + "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/foreground-child/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/fs-extra": { "version": "9.1.0", "dev": true, @@ -1574,6 +2427,8 @@ }, "node_modules/fs.realpath": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", "dev": true, "license": "ISC" }, @@ -1590,19 +2445,26 @@ } }, "node_modules/function-bind": { - "version": "1.1.1", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", "dev": true, - "license": "MIT" + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/function.prototype.name": { - "version": "1.1.5", + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", + "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0", - "functions-have-names": "^1.2.2" + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "functions-have-names": "^1.2.3" }, "engines": { "node": ">= 0.4" @@ -1611,13 +2473,10 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/functional-red-black-tree": { - "version": "1.0.1", - "dev": true, - "license": "MIT" - }, "node_modules/functions-have-names": { "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", "dev": true, "license": "MIT", "funding": { @@ -1633,48 +2492,48 @@ } }, "node_modules/get-intrinsic": { - "version": "1.2.1", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", "dev": true, "license": "MIT", "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", "has-proto": "^1.0.1", - "has-symbols": "^1.0.3" + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/get-stdin": { - "version": "6.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, "node_modules/get-stream": { - "version": "5.2.0", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", "dev": true, "license": "MIT", - "dependencies": { - "pump": "^3.0.0" - }, "engines": { - "node": ">=8" + "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/get-symbol-description": { - "version": "1.0.0", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz", + "integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" + "call-bind": "^1.0.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4" }, "engines": { "node": ">= 0.4" @@ -1684,37 +2543,72 @@ } }, "node_modules/glob": { - "version": "7.2.3", + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-11.0.0.tgz", + "integrity": "sha512-9UiX/Bl6J2yaBbxKoEBRm4Cipxgok8kQYcOPEhScPwebu2I0HoQOuYdIO6S3hLuWoZgpDpwQZMzTFxgpkyT76g==", "dev": true, "license": "ISC", "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "foreground-child": "^3.1.0", + "jackspeak": "^4.0.1", + "minimatch": "^10.0.0", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^2.0.0" + }, + "bin": { + "glob": "dist/esm/bin.mjs" }, "engines": { - "node": "*" + "node": "20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, "node_modules/glob-parent": { - "version": "5.1.2", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, "license": "ISC", "dependencies": { - "is-glob": "^4.0.1" + "is-glob": "^4.0.3" }, "engines": { - "node": ">= 6" + "node": ">=10.13.0" + } + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.1.tgz", + "integrity": "sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/globals": { - "version": "13.20.0", + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", "dev": true, "license": "MIT", "dependencies": { @@ -1728,11 +2622,14 @@ } }, "node_modules/globalthis": { - "version": "1.0.3", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", "dev": true, "license": "MIT", "dependencies": { - "define-properties": "^1.1.3" + "define-properties": "^1.2.1", + "gopd": "^1.0.1" }, "engines": { "node": ">= 0.4" @@ -1743,6 +2640,8 @@ }, "node_modules/globby": { "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "dev": true, "license": "MIT", "dependencies": { @@ -1762,6 +2661,8 @@ }, "node_modules/gopd": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", "dev": true, "license": "MIT", "dependencies": { @@ -1776,19 +2677,17 @@ "dev": true, "license": "ISC" }, - "node_modules/has": { - "version": "1.0.3", + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", "dev": true, - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } + "license": "MIT" }, "node_modules/has-bigints": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", "dev": true, "license": "MIT", "funding": { @@ -1804,18 +2703,22 @@ } }, "node_modules/has-property-descriptors": { - "version": "1.0.0", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", "dev": true, "license": "MIT", "dependencies": { - "get-intrinsic": "^1.1.1" + "es-define-property": "^1.0.0" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/has-proto": { - "version": "1.0.1", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", "dev": true, "license": "MIT", "engines": { @@ -1827,6 +2730,8 @@ }, "node_modules/has-symbols": { "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", "dev": true, "license": "MIT", "engines": { @@ -1837,11 +2742,13 @@ } }, "node_modules/has-tostringtag": { - "version": "1.0.0", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", "dev": true, "license": "MIT", "dependencies": { - "has-symbols": "^1.0.2" + "has-symbols": "^1.0.3" }, "engines": { "node": ">= 0.4" @@ -1850,30 +2757,49 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/human-signals": { - "version": "1.1.1", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", "dev": true, "license": "Apache-2.0", "engines": { - "node": ">=8.12.0" + "node": ">=10.17.0" } }, "node_modules/husky": { - "version": "7.0.4", + "version": "9.1.4", + "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.4.tgz", + "integrity": "sha512-bho94YyReb4JV7LYWRWxZ/xr6TtOTt8cMfmQ39MQYJ7f/YE268s3GdghGwi+y4zAeqewE5zYLvuhV0M0ijsDEA==", "dev": true, "license": "MIT", "bin": { - "husky": "lib/bin.js" + "husky": "bin.js" }, "engines": { - "node": ">=12" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/typicode" } }, "node_modules/ignore": { - "version": "5.2.4", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "dev": true, "license": "MIT", "engines": { @@ -1905,6 +2831,9 @@ }, "node_modules/inflight": { "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", "dev": true, "license": "ISC", "dependencies": { @@ -1914,16 +2843,20 @@ }, "node_modules/inherits": { "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true, "license": "ISC" }, "node_modules/internal-slot": { - "version": "1.0.5", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", + "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==", "dev": true, "license": "MIT", "dependencies": { - "get-intrinsic": "^1.2.0", - "has": "^1.0.3", + "es-errors": "^1.3.0", + "hasown": "^2.0.0", "side-channel": "^1.0.4" }, "engines": { @@ -1931,13 +2864,17 @@ } }, "node_modules/is-array-buffer": { - "version": "3.0.2", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", + "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==", "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.0", - "is-typed-array": "^1.1.10" + "get-intrinsic": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -1950,6 +2887,8 @@ }, "node_modules/is-bigint": { "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", "dev": true, "license": "MIT", "dependencies": { @@ -1961,6 +2900,8 @@ }, "node_modules/is-boolean-object": { "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", "dev": true, "license": "MIT", "dependencies": { @@ -1976,6 +2917,8 @@ }, "node_modules/is-callable": { "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", "dev": true, "license": "MIT", "engines": { @@ -1986,11 +2929,32 @@ } }, "node_modules/is-core-module": { - "version": "2.12.1", + "version": "2.15.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.0.tgz", + "integrity": "sha512-Dd+Lb2/zvk9SKy1TGCt1wFJFo/MWBPMX5x7KcvLajWTGuomczdQX61PvY5yK6SVACwpoexWo81IfFyoKY2QnTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-view": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.1.tgz", + "integrity": "sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==", "dev": true, "license": "MIT", "dependencies": { - "has": "^1.0.3" + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -1998,6 +2962,8 @@ }, "node_modules/is-date-object": { "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", "dev": true, "license": "MIT", "dependencies": { @@ -2038,7 +3004,9 @@ } }, "node_modules/is-negative-zero": { - "version": "2.0.2", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", "dev": true, "license": "MIT", "engines": { @@ -2050,6 +3018,8 @@ }, "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==", "dev": true, "license": "MIT", "engines": { @@ -2058,6 +3028,8 @@ }, "node_modules/is-number-object": { "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", "dev": true, "license": "MIT", "dependencies": { @@ -2070,8 +3042,20 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/is-regex": { "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", "dev": true, "license": "MIT", "dependencies": { @@ -2086,11 +3070,16 @@ } }, "node_modules/is-shared-array-buffer": { - "version": "1.0.2", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz", + "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.2" + "call-bind": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -2098,6 +3087,8 @@ }, "node_modules/is-stream": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", "dev": true, "license": "MIT", "engines": { @@ -2109,6 +3100,8 @@ }, "node_modules/is-string": { "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", "dev": true, "license": "MIT", "dependencies": { @@ -2123,6 +3116,8 @@ }, "node_modules/is-symbol": { "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", "dev": true, "license": "MIT", "dependencies": { @@ -2136,15 +3131,13 @@ } }, "node_modules/is-typed-array": { - "version": "1.1.10", + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz", + "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", "dev": true, "license": "MIT", "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0" + "which-typed-array": "^1.1.14" }, "engines": { "node": ">= 0.4" @@ -2155,6 +3148,8 @@ }, "node_modules/is-weakref": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", "dev": true, "license": "MIT", "dependencies": { @@ -2164,17 +3159,46 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true, + "license": "MIT" + }, "node_modules/isexe": { "version": "2.0.0", "dev": true, "license": "ISC" }, + "node_modules/jackspeak": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.0.1.tgz", + "integrity": "sha512-cub8rahkh0Q/bw1+GxP7aeSe29hHHn2V4m29nnDlvCdlgU+3UGxkZp7Z53jLUdpX3jdTO0nJZUDl3xvbWc2Xog==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, "node_modules/java-parser": { - "version": "2.0.2", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/java-parser/-/java-parser-2.3.2.tgz", + "integrity": "sha512-/O42UbEHy3VVJw8W0ruHkQjW75oWvQx4QisoUDRIGir6q3/IZ4JslDMPMYEqp7LU56PYJkH5uXdQiBaCXt/Opw==", "dev": true, "license": "Apache-2.0", "dependencies": { - "chevrotain": "6.5.0", + "chevrotain": "11.0.3", + "chevrotain-allstar": "0.3.1", "lodash": "4.17.21" } }, @@ -2184,17 +3208,25 @@ "license": "MIT" }, "node_modules/js-yaml": { - "version": "3.14.1", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, "license": "MIT", "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, "node_modules/json-parse-even-better-errors": { "version": "2.3.1", "dev": true, @@ -2202,6 +3234,8 @@ }, "node_modules/json-schema-traverse": { "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true, "license": "MIT" }, @@ -2212,6 +3246,8 @@ }, "node_modules/json5": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", "dev": true, "license": "MIT", "dependencies": { @@ -2232,8 +3268,20 @@ "graceful-fs": "^4.1.6" } }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, "node_modules/levn": { "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dev": true, "license": "MIT", "dependencies": { @@ -2250,14 +3298,19 @@ "license": "MIT" }, "node_modules/locate-path": { - "version": "5.0.0", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, "license": "MIT", "dependencies": { - "p-locate": "^4.1.0" + "p-locate": "^5.0.0" }, "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/lodash": { @@ -2265,34 +3318,39 @@ "dev": true, "license": "MIT" }, - "node_modules/lodash.merge": { - "version": "4.6.2", + "node_modules/lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", "dev": true, "license": "MIT" }, - "node_modules/lodash.truncate": { - "version": "4.4.2", + "node_modules/lodash.merge": { + "version": "4.6.2", "dev": true, "license": "MIT" }, "node_modules/lru-cache": { - "version": "6.0.0", + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.0.0.tgz", + "integrity": "sha512-Qv32eSV1RSCfhY3fpPE2GNZ8jgM9X7rdAfemLWqTUxwiyIC4jJ6Sy0fZ8H+oLWevO6i4/bizg7c8d8i6bxrzbA==", "dev": true, "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, "engines": { - "node": ">=10" + "node": "20 || >=22" } }, "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==", "dev": true, "license": "MIT" }, "node_modules/merge2": { "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", "dev": true, "license": "MIT", "engines": { @@ -2300,19 +3358,36 @@ } }, "node_modules/micromatch": { - "version": "4.0.5", + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", + "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", "dev": true, "license": "MIT", "dependencies": { - "braces": "^3.0.2", + "braces": "^3.0.3", "picomatch": "^2.3.1" }, "engines": { "node": ">=8.6" } }, + "node_modules/micromatch/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "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==", "dev": true, "license": "MIT", "engines": { @@ -2332,12 +3407,24 @@ }, "node_modules/minimist": { "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, "node_modules/mri": { "version": "1.2.0", "dev": true, @@ -2351,28 +3438,22 @@ "dev": true, "license": "MIT" }, - "node_modules/multimatch": { - "version": "4.0.0", + "node_modules/natural-compare": { + "version": "1.4.0", "dev": true, - "license": "MIT", - "dependencies": { - "@types/minimatch": "^3.0.3", - "array-differ": "^3.0.0", - "array-union": "^2.1.0", - "arrify": "^2.0.1", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=8" - } + "license": "MIT" }, - "node_modules/natural-compare": { + "node_modules/natural-compare-lite": { "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", + "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", "dev": true, "license": "MIT" }, "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==", "dev": true, "license": "MIT", "dependencies": { @@ -2383,15 +3464,22 @@ } }, "node_modules/object-inspect": { - "version": "1.12.3", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", + "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", "dev": true, "license": "MIT", + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/object-keys": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", "dev": true, "license": "MIT", "engines": { @@ -2399,12 +3487,14 @@ } }, "node_modules/object.assign": { - "version": "4.1.4", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", + "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", "has-symbols": "^1.0.3", "object-keys": "^1.1.1" }, @@ -2415,14 +3505,50 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/object.fromentries": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", + "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.groupby": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", + "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/object.values": { - "version": "1.1.6", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.0.tgz", + "integrity": "sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" }, "engines": { "node": ">= 0.4" @@ -2433,6 +3559,8 @@ }, "node_modules/once": { "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "dev": true, "license": "ISC", "dependencies": { @@ -2441,6 +3569,8 @@ }, "node_modules/onetime": { "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", "dev": true, "license": "MIT", "dependencies": { @@ -2454,7 +3584,9 @@ } }, "node_modules/optionator": { - "version": "0.9.1", + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", "dev": true, "license": "MIT", "dependencies": { @@ -2463,44 +3595,50 @@ "levn": "^0.4.1", "prelude-ls": "^1.2.1", "type-check": "^0.4.0", - "word-wrap": "^1.2.3" + "word-wrap": "^1.2.5" }, "engines": { "node": ">= 0.8.0" } }, "node_modules/p-limit": { - "version": "2.3.0", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, "license": "MIT", "dependencies": { - "p-try": "^2.0.0" + "yocto-queue": "^0.1.0" }, "engines": { - "node": ">=6" + "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/p-locate": { - "version": "4.1.0", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, "license": "MIT", "dependencies": { - "p-limit": "^2.2.0" + "p-limit": "^3.0.2" }, "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/p-try": { - "version": "2.2.0", + "node_modules/package-json-from-dist": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz", + "integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } + "license": "BlueOak-1.0.0" }, "node_modules/parent-module": { "version": "1.0.1", @@ -2532,6 +3670,8 @@ }, "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==", "dev": true, "license": "MIT", "engines": { @@ -2540,6 +3680,8 @@ }, "node_modules/path-is-absolute": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", "dev": true, "license": "MIT", "engines": { @@ -2556,9 +3698,28 @@ }, "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==", "dev": true, "license": "MIT" }, + "node_modules/path-scurry": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.0.tgz", + "integrity": "sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/path-type": { "version": "4.0.0", "dev": true, @@ -2567,19 +3728,40 @@ "node": ">=8" } }, + "node_modules/picocolors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", + "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", + "dev": true, + "license": "ISC" + }, "node_modules/picomatch": { - "version": "2.3.1", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-3.0.1.tgz", + "integrity": "sha512-I3EurrIQMlRc9IaAZnqRR044Phh2DXY+55o7uJ0V+hYZAcQYSuFWsc9q5PvyDHUSCe1Qxn/iBz+78s86zWnGag==", "dev": true, "license": "MIT", "engines": { - "node": ">=8.6" + "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/possible-typed-array-names": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", + "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/prelude-ls": { "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true, "license": "MIT", "engines": { @@ -2587,104 +3769,78 @@ } }, "node_modules/prettier": { - "version": "2.8.8", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz", + "integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==", "dev": true, "license": "MIT", "bin": { - "prettier": "bin-prettier.js" + "prettier": "bin/prettier.cjs" }, "engines": { - "node": ">=10.13.0" + "node": ">=14" }, "funding": { "url": "https://github.com/prettier/prettier?sponsor=1" } }, "node_modules/prettier-plugin-java": { - "version": "1.6.2", + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/prettier-plugin-java/-/prettier-plugin-java-2.6.4.tgz", + "integrity": "sha512-57iGIFM4xSCqzHc4G6RLeC0DJk+i6Vd1JDj5xcIe7GsWZjRSl8WWkpL0f4BB0gZ+jDZ8R1uJaxtnMgnRtzjLDQ==", "dev": true, "license": "Apache-2.0", "dependencies": { - "java-parser": "2.0.2", + "java-parser": "2.3.2", "lodash": "4.17.21", - "prettier": "2.3.1" + "prettier": "3.2.5" } }, "node_modules/prettier-plugin-java/node_modules/prettier": { - "version": "2.3.1", + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz", + "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==", "dev": true, "license": "MIT", "bin": { - "prettier": "bin-prettier.js" + "prettier": "bin/prettier.cjs" }, "engines": { - "node": ">=10.13.0" + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" } }, "node_modules/pretty-quick": { - "version": "3.1.3", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pretty-quick/-/pretty-quick-4.0.0.tgz", + "integrity": "sha512-M+2MmeufXb/M7Xw3Afh1gxcYpj+sK0AxEfnfF958ktFeAyi5MsKY5brymVURQLgPLV1QaF5P4pb2oFJ54H3yzQ==", "dev": true, "license": "MIT", "dependencies": { - "chalk": "^3.0.0", - "execa": "^4.0.0", - "find-up": "^4.1.0", - "ignore": "^5.1.4", - "mri": "^1.1.5", - "multimatch": "^4.0.0" + "execa": "^5.1.1", + "find-up": "^5.0.0", + "ignore": "^5.3.0", + "mri": "^1.2.0", + "picocolors": "^1.0.0", + "picomatch": "^3.0.1", + "tslib": "^2.6.2" }, "bin": { - "pretty-quick": "bin/pretty-quick.js" + "pretty-quick": "lib/cli.mjs" }, "engines": { - "node": ">=10.13" + "node": ">=14" }, "peerDependencies": { - "prettier": ">=2.0.0" - } - }, - "node_modules/pretty-quick/node_modules/chalk": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pretty-quick/node_modules/supports-color": { - "version": "7.2.0", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/progress": { - "version": "2.0.3", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/pump": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" + "prettier": "^3.0.0" } }, "node_modules/punycode": { - "version": "2.3.0", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, "license": "MIT", "engines": { @@ -2693,6 +3849,8 @@ }, "node_modules/queue-microtask": { "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", "dev": true, "funding": [ { @@ -2715,19 +3873,17 @@ "dev": true, "license": "MIT" }, - "node_modules/regexp-to-ast": { - "version": "0.4.0", - "dev": true, - "license": "MIT" - }, "node_modules/regexp.prototype.flags": { - "version": "1.5.0", + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", + "integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "functions-have-names": "^1.2.3" + "call-bind": "^1.0.6", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "set-function-name": "^2.0.1" }, "engines": { "node": ">= 0.4" @@ -2736,17 +3892,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/regexpp": { - "version": "3.2.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - } - }, "node_modules/require-directory": { "version": "2.1.1", "dev": true, @@ -2755,20 +3900,14 @@ "node": ">=0.10.0" } }, - "node_modules/require-from-string": { - "version": "2.0.2", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/resolve": { - "version": "1.22.2", + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", "dev": true, "license": "MIT", "dependencies": { - "is-core-module": "^2.11.0", + "is-core-module": "^2.13.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, @@ -2789,6 +3928,8 @@ }, "node_modules/reusify": { "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", "dev": true, "license": "MIT", "engines": { @@ -2797,35 +3938,65 @@ } }, "node_modules/rimraf": { - "version": "3.0.2", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-6.0.1.tgz", + "integrity": "sha512-9dkvaxAsk/xNXSJzMgFqqMCuFgt2+KsOFek3TMLfo8NCPfWpBmqwyNn5Y+NX56QUYfCtsyhF3ayiboEoUmJk/A==", "dev": true, "license": "ISC", "dependencies": { - "glob": "^7.1.3" + "glob": "^11.0.0", + "package-json-from-dist": "^1.0.0" }, "bin": { - "rimraf": "bin.js" + "rimraf": "dist/esm/bin.mjs" + }, + "engines": { + "node": "20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, "node_modules/rollup": { - "version": "2.79.1", + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.20.0.tgz", + "integrity": "sha512-6rbWBChcnSGzIlXeIdNIZTopKYad8ZG8ajhl78lGRLsI2rX8IkaotQhVas2Ma+GPxJav19wrSzvRvuiv0YKzWw==", "dev": true, "license": "MIT", + "dependencies": { + "@types/estree": "1.0.5" + }, "bin": { "rollup": "dist/bin/rollup" }, "engines": { - "node": ">=10.0.0" + "node": ">=18.0.0", + "npm": ">=8.0.0" }, "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.20.0", + "@rollup/rollup-android-arm64": "4.20.0", + "@rollup/rollup-darwin-arm64": "4.20.0", + "@rollup/rollup-darwin-x64": "4.20.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.20.0", + "@rollup/rollup-linux-arm-musleabihf": "4.20.0", + "@rollup/rollup-linux-arm64-gnu": "4.20.0", + "@rollup/rollup-linux-arm64-musl": "4.20.0", + "@rollup/rollup-linux-powerpc64le-gnu": "4.20.0", + "@rollup/rollup-linux-riscv64-gnu": "4.20.0", + "@rollup/rollup-linux-s390x-gnu": "4.20.0", + "@rollup/rollup-linux-x64-gnu": "4.20.0", + "@rollup/rollup-linux-x64-musl": "4.20.0", + "@rollup/rollup-win32-arm64-msvc": "4.20.0", + "@rollup/rollup-win32-ia32-msvc": "4.20.0", + "@rollup/rollup-win32-x64-msvc": "4.20.0", "fsevents": "~2.3.2" } }, "node_modules/run-parallel": { "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", "dev": true, "funding": [ { @@ -2854,26 +4025,49 @@ "tslib": "^2.1.0" } }, + "node_modules/safe-array-concat": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz", + "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "get-intrinsic": "^1.2.4", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/safe-regex-test": { - "version": "1.0.0", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz", + "integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.3", + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", "is-regex": "^1.1.4" }, + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/semver": { - "version": "7.5.1", + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "dev": true, "license": "ISC", - "dependencies": { - "lru-cache": "^6.0.0" - }, "bin": { "semver": "bin/semver.js" }, @@ -2881,6 +4075,40 @@ "node": ">=10" } }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/shebang-command": { "version": "2.0.0", "dev": true, @@ -2909,13 +4137,19 @@ } }, "node_modules/side-channel": { - "version": "1.0.4", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -2928,6 +4162,8 @@ }, "node_modules/slash": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true, "license": "MIT", "engines": { @@ -2951,17 +4187,29 @@ } }, "node_modules/spawn-command": { - "version": "0.0.2-1", - "dev": true, - "license": "MIT" + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/spawn-command/-/spawn-command-0.0.2.tgz", + "integrity": "sha512-zC8zGoGkmc8J9ndvml8Xksr1Amk9qBujgbF0JAIWO7kXr43w0h/0GJNM/Vustixu+YE8N/MTrQ7N31FvHUACxQ==", + "dev": true }, - "node_modules/sprintf-js": { - "version": "1.0.3", + "node_modules/string-width": { + "version": "4.2.3", "dev": true, - "license": "BSD-3-Clause" + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } }, - "node_modules/string-width": { + "node_modules/string-width-cjs": { + "name": "string-width", "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "license": "MIT", "dependencies": { @@ -2974,13 +4222,16 @@ } }, "node_modules/string.prototype.trim": { - "version": "1.2.7", + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz", + "integrity": "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.0", + "es-object-atoms": "^1.0.0" }, "engines": { "node": ">= 0.4" @@ -2990,26 +4241,33 @@ } }, "node_modules/string.prototype.trimend": { - "version": "1.0.6", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz", + "integrity": "sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/string.prototype.trimstart": { - "version": "1.0.6", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -3026,8 +4284,24 @@ "node": ">=8" } }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/strip-bom": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", "dev": true, "license": "MIT", "engines": { @@ -3036,6 +4310,8 @@ }, "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==", "dev": true, "license": "MIT", "engines": { @@ -3044,6 +4320,8 @@ }, "node_modules/strip-json-comments": { "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true, "license": "MIT", "engines": { @@ -3069,6 +4347,8 @@ }, "node_modules/supports-preserve-symlinks-flag": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", "dev": true, "license": "MIT", "engines": { @@ -3092,41 +4372,6 @@ "node-swiftlint": "bin.js" } }, - "node_modules/table": { - "version": "6.8.1", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "ajv": "^8.0.1", - "lodash.truncate": "^4.4.2", - "slice-ansi": "^4.0.0", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/table/node_modules/ajv": { - "version": "8.12.0", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/table/node_modules/json-schema-traverse": { - "version": "1.0.0", - "dev": true, - "license": "MIT" - }, "node_modules/text-table": { "version": "0.2.0", "dev": true, @@ -3134,6 +4379,8 @@ }, "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==", "dev": true, "license": "MIT", "dependencies": { @@ -3152,7 +4399,9 @@ } }, "node_modules/tsconfig-paths": { - "version": "3.14.2", + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", + "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", "dev": true, "license": "MIT", "dependencies": { @@ -3163,12 +4412,16 @@ } }, "node_modules/tslib": { - "version": "2.5.2", + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", "dev": true, "license": "0BSD" }, "node_modules/tsutils": { "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", "dev": true, "license": "MIT", "dependencies": { @@ -3183,11 +4436,15 @@ }, "node_modules/tsutils/node_modules/tslib": { "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", "dev": true, "license": "0BSD" }, "node_modules/type-check": { "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", "dev": true, "license": "MIT", "dependencies": { @@ -3199,6 +4456,8 @@ }, "node_modules/type-fest": { "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true, "license": "(MIT OR CC0-1.0)", "engines": { @@ -3208,21 +4467,87 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/typed-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz", + "integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz", + "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz", + "integrity": "sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/typed-array-length": { - "version": "1.0.4", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.6.tgz", + "integrity": "sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", + "call-bind": "^1.0.7", "for-each": "^0.3.3", - "is-typed-array": "^1.1.9" + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/typescript": { - "version": "4.9.5", + "version": "5.5.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz", + "integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==", "dev": true, "license": "Apache-2.0", "bin": { @@ -3230,11 +4555,13 @@ "tsserver": "bin/tsserver" }, "engines": { - "node": ">=4.2.0" + "node": ">=14.17" } }, "node_modules/unbox-primitive": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", "dev": true, "license": "MIT", "dependencies": { @@ -3265,17 +4592,14 @@ }, "node_modules/uri-js": { "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "dev": true, "license": "BSD-2-Clause", "dependencies": { "punycode": "^2.1.0" } }, - "node_modules/v8-compile-cache": { - "version": "2.3.0", - "dev": true, - "license": "MIT" - }, "node_modules/which": { "version": "2.0.2", "dev": true, @@ -3292,6 +4616,8 @@ }, "node_modules/which-boxed-primitive": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", "dev": true, "license": "MIT", "dependencies": { @@ -3306,16 +4632,17 @@ } }, "node_modules/which-typed-array": { - "version": "1.1.9", + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", + "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", "dev": true, "license": "MIT", "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", "for-each": "^0.3.3", "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0", - "is-typed-array": "^1.1.10" + "has-tostringtag": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -3325,7 +4652,9 @@ } }, "node_modules/word-wrap": { - "version": "1.2.3", + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", "dev": true, "license": "MIT", "engines": { @@ -3348,8 +4677,29 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/wrappy": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "dev": true, "license": "ISC" }, @@ -3361,11 +4711,6 @@ "node": ">=10" } }, - "node_modules/yallist": { - "version": "4.0.0", - "dev": true, - "license": "ISC" - }, "node_modules/yaml": { "version": "1.10.2", "dev": true, @@ -3398,6 +4743,19 @@ "engines": { "node": ">=12" } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } } } } diff --git a/package.json b/package.json index ef3b5737..a2cacfc0 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,8 @@ { - "name": "@capacitor-community/camera-preview", + "name": "@michaelwolz/camera-preview-lite", "version": "6.0.0", - "description": "Camera preview", + "description": "Fork of the capacitor-community/camera-preview plugin focusing on high resolution photos without bloating up the code.", + "type": "module", "main": "dist/plugin.cjs.js", "module": "dist/esm/index.js", "types": "dist/esm/index.d.ts", @@ -20,27 +21,27 @@ "prettier": "prettier \"**/*.{css,html,ts,js,java}\"", "swiftlint": "node-swiftlint", "prepublishOnly": "npm run build", - "prepare": "husky install && npm run build" + "prepare": "husky && npm run build" }, - "author": "Ariel Hernandez Musa", + "author": "Michael Wolz", "license": "MIT", "devDependencies": { - "@capacitor/android": "^6.0.0", - "@capacitor/core": "^6.0.0", - "@capacitor/ios": "^6.0.0", - "@ionic/eslint-config": "^0.3.0", - "@ionic/prettier-config": "^2.0.0", + "@capacitor/android": "^6.1.2", + "@capacitor/core": "^6.1.2", + "@capacitor/ios": "^6.1.2", + "@ionic/eslint-config": "^0.4.0", + "@ionic/prettier-config": "^4.0.0", "@ionic/swiftlint-config": "^1.1.2", - "concurrently": "^7.0.0", - "eslint": "^7.32.0", - "husky": "^7.0.4", - "prettier": "^2.5.1", - "prettier-plugin-java": "^1.6.1", - "pretty-quick": "^3.1.3", - "rimraf": "^3.0.2", - "rollup": "^2.79.1", - "swiftlint": "^1.0.1", - "typescript": "^4.3.2" + "concurrently": "^8.2.2", + "eslint": "^8.57.0", + "husky": "^9.1.4", + "prettier": "^3.3.3", + "prettier-plugin-java": "^2.6.4", + "pretty-quick": "^4.0.0", + "rimraf": "^6.0.1", + "rollup": "^4.20.0", + "swiftlint": "^1.0.2", + "typescript": "^5.5.4" }, "peerDependencies": { "@capacitor/core": "^6.0.0" @@ -76,9 +77,9 @@ }, "repository": { "type": "git", - "url": "https://github.com/capacitor-community/camera-preview.git" + "url": "https://github.com/michaelwolz/camera-preview-lite" }, "bugs": { - "url": "https://github.com/capacitor-community/camera-preview/issues" + "url": "https://github.com/michaelwolz/camera-preview-lite/issues" } } From a4613472da8d5c942face37a19cc6de6dc78f61d Mon Sep 17 00:00:00 2001 From: Michael Wolz Date: Fri, 16 Aug 2024 10:28:24 +0200 Subject: [PATCH 27/28] chore: modify license --- LICENSE | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index 6af10061..659f4e74 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,7 @@ MIT License -Copyright (c) Ariel Hernandez Musa. +Copyright (c) Ariel Hernandez Musa +Copyright (c) 2024 Michael Wolz Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From 7dbfa49469705b2db8a7e1a07538828c6997714b Mon Sep 17 00:00:00 2001 From: Michael Wolz Date: Fri, 16 Aug 2024 11:27:25 +0200 Subject: [PATCH 28/28] build: add missing file references for iOS --- ios/Plugin.xcodeproj/project.pbxproj | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ios/Plugin.xcodeproj/project.pbxproj b/ios/Plugin.xcodeproj/project.pbxproj index dafdf157..344f74ec 100644 --- a/ios/Plugin.xcodeproj/project.pbxproj +++ b/ios/Plugin.xcodeproj/project.pbxproj @@ -24,6 +24,7 @@ 50ADFFA42020D75100D50D53 /* Capacitor.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 50ADFFA52020D75100D50D53 /* Capacitor.framework */; }; 50ADFFA82020EE4F00D50D53 /* Plugin.m in Sources */ = {isa = PBXBuildFile; fileRef = 50ADFFA72020EE4F00D50D53 /* Plugin.m */; }; 50E1A94820377CB70090CE1A /* Plugin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50E1A94720377CB70090CE1A /* Plugin.swift */; }; + F72078D82C6F52C600AD0DC7 /* UIImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = F72078D72C6F52C600AD0DC7 /* UIImage.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -63,6 +64,7 @@ 96ED1B6440D6672E406C8D19 /* Pods-PluginTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PluginTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-PluginTests/Pods-PluginTests.debug.xcconfig"; sourceTree = ""; }; F65BB2953ECE002E1EF3E424 /* Pods-PluginTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PluginTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-PluginTests/Pods-PluginTests.release.xcconfig"; sourceTree = ""; }; F6753A823D3815DB436415E3 /* Pods_PluginTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_PluginTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + F72078D72C6F52C600AD0DC7 /* UIImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = UIImage.swift; path = "/Users/michaelwolz/work/camera-preview-michaelwolz/ios/Plugin/UIImage.swift"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -118,6 +120,7 @@ 50ADFF8A201F53D600D50D53 /* Plugin */ = { isa = PBXGroup; children = ( + F72078D72C6F52C600AD0DC7 /* UIImage.swift */, 50E1A94720377CB70090CE1A /* Plugin.swift */, 50ADFF8B201F53D600D50D53 /* Plugin.h */, 50ADFFA72020EE4F00D50D53 /* Plugin.m */, @@ -341,6 +344,7 @@ buildActionMask = 2147483647; files = ( 4C2070F422DB860800D1AD33 /* CameraController.swift in Sources */, + F72078D82C6F52C600AD0DC7 /* UIImage.swift in Sources */, 50E1A94820377CB70090CE1A /* Plugin.swift in Sources */, 50ADFFA82020EE4F00D50D53 /* Plugin.m in Sources */, );