many changes
new feature to record both sides while call recording(upstream commit), fix armv7 failed to initialize error & fix a9 issues
This commit is contained in:
Binary file not shown.
@@ -3,15 +3,19 @@ package me.eternal.purrfectsnap.bridge
|
||||
import android.content.Intent
|
||||
import android.hardware.biometrics.BiometricManager
|
||||
import android.hardware.biometrics.BiometricPrompt
|
||||
import android.hardware.fingerprint.FingerprintManager
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.os.CancellationSignal
|
||||
import android.app.KeyguardManager
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
import me.eternal.purrfectsnap.SharedContextHolder
|
||||
import java.util.concurrent.Executors
|
||||
|
||||
class BiometricPromptActivity: ComponentActivity() {
|
||||
private val deviceCredentialRequestCode = 2201
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
@@ -21,16 +25,50 @@ class BiometricPromptActivity: ComponentActivity() {
|
||||
}
|
||||
|
||||
val remoteSideContext = SharedContextHolder.remote(this)
|
||||
val executor = Executors.newSingleThreadExecutor()
|
||||
val negativeText = remoteSideContext.translation.getOrNull("biometric_auth.cancel")
|
||||
?.takeIf { it.isNotBlank() }
|
||||
?: "Cancel"
|
||||
val titleText = remoteSideContext.translation.getOrNull("biometric_auth.title")
|
||||
?.takeIf { it.isNotBlank() }
|
||||
?: "Unlock"
|
||||
val subtitleText = remoteSideContext.translation.getOrNull("biometric_auth.subtitle")
|
||||
?.takeIf { it.isNotBlank() }
|
||||
?: "Confirm your screen lock"
|
||||
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
|
||||
val fingerprintManager = getSystemService(FingerprintManager::class.java)
|
||||
val hasFingerprintSupport = runCatching {
|
||||
fingerprintManager?.isHardwareDetected == true && fingerprintManager.hasEnrolledFingerprints()
|
||||
}.getOrDefault(false)
|
||||
if (!hasFingerprintSupport) {
|
||||
val keyguardManager = getSystemService(KeyguardManager::class.java)
|
||||
val canUseDeviceCredential = keyguardManager?.isKeyguardSecure == true
|
||||
if (canUseDeviceCredential) {
|
||||
val intent = keyguardManager.createConfirmDeviceCredentialIntent(titleText, subtitleText)
|
||||
if (intent != null) {
|
||||
startActivityForResult(intent, deviceCredentialRequestCode)
|
||||
setContent {}
|
||||
return
|
||||
}
|
||||
}
|
||||
cancel()
|
||||
setContent {}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
BiometricPrompt.Builder(this@BiometricPromptActivity)
|
||||
.setTitle(remoteSideContext.translation["biometric_auth.title"])
|
||||
.setSubtitle(remoteSideContext.translation["biometric_auth.subtitle"])
|
||||
.setTitle(titleText)
|
||||
.setSubtitle(subtitleText)
|
||||
.apply {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
setAllowedAuthenticators(BiometricManager.Authenticators.BIOMETRIC_WEAK or BiometricManager.Authenticators.DEVICE_CREDENTIAL)
|
||||
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
@Suppress("DEPRECATION")
|
||||
setDeviceCredentialAllowed(true)
|
||||
} else {
|
||||
setNegativeButton(negativeText, mainExecutor) { _, _ -> cancel() }
|
||||
}
|
||||
}
|
||||
.build().authenticate(
|
||||
@@ -39,7 +77,7 @@ class BiometricPromptActivity: ComponentActivity() {
|
||||
cancel()
|
||||
}
|
||||
},
|
||||
Executors.newSingleThreadExecutor(),
|
||||
executor,
|
||||
object: BiometricPrompt.AuthenticationCallback() {
|
||||
override fun onAuthenticationError(errorCode: Int, errString: CharSequence?) {
|
||||
cancel()
|
||||
@@ -54,4 +92,16 @@ class BiometricPromptActivity: ComponentActivity() {
|
||||
|
||||
setContent {}
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
if (requestCode != deviceCredentialRequestCode) return
|
||||
if (resultCode == RESULT_OK) {
|
||||
setResult(RESULT_OK, Intent())
|
||||
} else {
|
||||
setResult(RESULT_CANCELED, Intent())
|
||||
}
|
||||
finish()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import android.os.ParcelFileDescriptor
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import me.eternal.purrfectsnap.RemoteSideContext
|
||||
import me.eternal.purrfectsnap.SharedContextHolder
|
||||
import me.eternal.purrfectsnap.bridge.call.CallDownloadSession
|
||||
import me.eternal.purrfectsnap.bridge.snapclient.MessagingBridge
|
||||
import me.eternal.purrfectsnap.common.data.MessagingFriendInfo
|
||||
import me.eternal.purrfectsnap.common.data.MessagingGroupInfo
|
||||
@@ -16,6 +17,7 @@ import me.eternal.purrfectsnap.common.ui.OverlayType
|
||||
import me.eternal.purrfectsnap.common.util.toParcelable
|
||||
import me.eternal.purrfectsnap.download.DownloadProcessor
|
||||
import me.eternal.purrfectsnap.download.FFMpegProcessor
|
||||
import me.eternal.purrfectsnap.download.call.CallDownloadSessionImpl
|
||||
import me.eternal.purrfectsnap.storage.*
|
||||
import me.eternal.purrfectsnap.task.Task
|
||||
import me.eternal.purrfectsnap.task.TaskType
|
||||
@@ -248,5 +250,16 @@ class BridgeService : Service() {
|
||||
override fun getDebugProp(key: String, defaultValue: String?): String? {
|
||||
return remoteSideContext.sharedPreferences.all["debug_$key"]?.toString() ?: defaultValue
|
||||
}
|
||||
|
||||
override fun startCallDownload(
|
||||
startTimestamp: Long,
|
||||
author: String
|
||||
): CallDownloadSession {
|
||||
return CallDownloadSessionImpl(
|
||||
context = remoteSideContext,
|
||||
callStartTimestamp = startTimestamp,
|
||||
author = author
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,6 +59,12 @@ class FFMpegProcessor(
|
||||
pendingTask.updateProgress("Processing (frames=${it.videoFrameNumber}, fps=${it.videoFps}, time=${it.time}, bitrate=${it.bitrate}, speed=${it.speed})")
|
||||
}
|
||||
)
|
||||
|
||||
fun newFFMpegProcessor(context: RemoteSideContext, onStatistics: (Statistics) -> Unit = {}) = FFMpegProcessor(
|
||||
logManager = context.log,
|
||||
ffmpegOptions = context.config.root.downloader.ffmpegOptions,
|
||||
onStatistics = onStatistics
|
||||
)
|
||||
}
|
||||
enum class Action {
|
||||
DOWNLOAD_DASH,
|
||||
@@ -66,6 +72,7 @@ class FFMpegProcessor(
|
||||
CONVERSION,
|
||||
MERGE_MEDIA,
|
||||
DOWNLOAD_AUDIO_STREAM,
|
||||
MERGE_AUDIO_STREAMS,
|
||||
}
|
||||
|
||||
data class Request(
|
||||
@@ -76,6 +83,7 @@ class FFMpegProcessor(
|
||||
val startTime: Long? = null, //only for DOWNLOAD_DASH
|
||||
val duration: Long? = null, //only for DOWNLOAD_DASH
|
||||
val audioStreamFormat: AudioStreamFormat? = null, //only for DOWNLOAD_AUDIO_STREAM
|
||||
val inputDelayOffsets: Map<String, Long>? = null, // only for MERGE_AUDIO_STREAMS
|
||||
|
||||
var videoCodec: String? = null,
|
||||
var audioCodec: String? = null,
|
||||
@@ -225,6 +233,26 @@ class FFMpegProcessor(
|
||||
globalArguments += "-ar" to args.audioStreamFormat.sampleRate.toString()
|
||||
globalArguments += "-ac" to args.audioStreamFormat.channels.toString()
|
||||
}
|
||||
Action.MERGE_AUDIO_STREAMS -> {
|
||||
inputArguments.clear()
|
||||
outputArguments.clear()
|
||||
val filterParts = StringBuilder()
|
||||
args.inputs.forEachIndexed { index, input ->
|
||||
inputArguments += "-i" to input
|
||||
val offset = args.inputDelayOffsets?.get(input) ?: 0L
|
||||
if (offset > 0) {
|
||||
filterParts.append("[$index:a]adelay=$offset|$offset[a$index];")
|
||||
} else {
|
||||
filterParts.append("[$index:a]acopy[a$index];")
|
||||
}
|
||||
}
|
||||
args.inputs.indices.forEach { index ->
|
||||
filterParts.append("[a$index]")
|
||||
}
|
||||
filterParts.append("amix=inputs=${args.inputs.size}:duration=longest:normalize=0[aout]")
|
||||
outputArguments += "-filter_complex" to "\"$filterParts\""
|
||||
outputArguments += "-map" to "\"[aout]\""
|
||||
}
|
||||
}
|
||||
outputArguments += args.output.absolutePath
|
||||
try {
|
||||
|
||||
@@ -0,0 +1,175 @@
|
||||
package me.eternal.purrfectsnap.download.call
|
||||
|
||||
import android.os.ParcelFileDescriptor
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.launch
|
||||
import me.eternal.purrfectsnap.RemoteSideContext
|
||||
import me.eternal.purrfectsnap.bridge.DownloadCallback
|
||||
import me.eternal.purrfectsnap.bridge.call.CallDownloadSession
|
||||
import me.eternal.purrfectsnap.common.data.download.AudioStreamFormat
|
||||
import me.eternal.purrfectsnap.common.data.download.DownloadMetadata
|
||||
import me.eternal.purrfectsnap.common.data.download.MediaDownloadSource
|
||||
import me.eternal.purrfectsnap.common.data.download.createNewFilePath
|
||||
import me.eternal.purrfectsnap.download.DownloadProcessor
|
||||
import me.eternal.purrfectsnap.download.FFMpegProcessor
|
||||
import me.eternal.purrfectsnap.task.PendingTaskListener
|
||||
import me.eternal.purrfectsnap.task.Task
|
||||
import me.eternal.purrfectsnap.task.TaskType
|
||||
import java.util.UUID
|
||||
import java.util.concurrent.CopyOnWriteArrayList
|
||||
import kotlin.math.absoluteValue
|
||||
|
||||
class CallDownloadSessionImpl(
|
||||
private val context: RemoteSideContext,
|
||||
private val callStartTimestamp: Long,
|
||||
private val author: String,
|
||||
): CallDownloadSession.Stub() {
|
||||
private val coroutineScope = CoroutineScope(Dispatchers.IO)
|
||||
private var callEnded: Boolean = false
|
||||
|
||||
private val streams = CopyOnWriteArrayList<CallStream>()
|
||||
private var mergeJob: Job? = null
|
||||
|
||||
init {
|
||||
context.log.verbose("Starting call callStartTimestamp=$callStartTimestamp")
|
||||
}
|
||||
|
||||
inner class CallStream(
|
||||
val startTimestampMillis: Long,
|
||||
private val audioStreamFormat: AudioStreamFormat
|
||||
) {
|
||||
val job: Job
|
||||
val writePfd: ParcelFileDescriptor
|
||||
|
||||
val outputFile = context.androidContext.cacheDir.resolve("call_${UUID.randomUUID()}.mp3").apply {
|
||||
if (exists()) delete()
|
||||
}
|
||||
|
||||
init {
|
||||
val pipe = ParcelFileDescriptor.createPipe()
|
||||
writePfd = pipe[1]
|
||||
|
||||
job = coroutineScope.launch {
|
||||
runCatching {
|
||||
FFMpegProcessor.newFFMpegProcessor(context).execute(
|
||||
FFMpegProcessor.Request(
|
||||
action = FFMpegProcessor.Action.DOWNLOAD_AUDIO_STREAM,
|
||||
inputs = listOf("/proc/self/fd/${pipe[0].fd}"),
|
||||
output = outputFile,
|
||||
audioStreamFormat = audioStreamFormat
|
||||
)
|
||||
)
|
||||
}.onFailure {
|
||||
context.log.error("Error converting call audio stream", it)
|
||||
runCatching {
|
||||
outputFile.delete()
|
||||
}
|
||||
}
|
||||
|
||||
pipe.forEach { runCatching { it.close() } }
|
||||
|
||||
context.log.verbose("Call stream ended startTimestampMillis=$startTimestampMillis")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun createStream(
|
||||
startTimestampMillis: Long,
|
||||
channels: Int,
|
||||
sampleRate: Int,
|
||||
encoding: Int
|
||||
): ParcelFileDescriptor? {
|
||||
if (callEnded) return null
|
||||
|
||||
context.log.verbose("createFileDescriptor startTimestampMillis=$startTimestampMillis, channels=$channels, sampleRate=$sampleRate, encoding=$encoding")
|
||||
val callStream = CallStream(
|
||||
startTimestampMillis = startTimestampMillis,
|
||||
audioStreamFormat = AudioStreamFormat(
|
||||
channels = channels,
|
||||
sampleRate = sampleRate,
|
||||
encoding = encoding
|
||||
)
|
||||
)
|
||||
|
||||
synchronized(streams) {
|
||||
streams.add(callStream)
|
||||
}
|
||||
|
||||
return callStream.writePfd
|
||||
}
|
||||
|
||||
override fun end() {
|
||||
if (callEnded) return
|
||||
callEnded = true
|
||||
|
||||
if (streams.isEmpty()) {
|
||||
context.log.verbose("No call chunks to merge")
|
||||
return
|
||||
}
|
||||
|
||||
val outputFile = context.androidContext.cacheDir.resolve("call_${UUID.randomUUID()}_final.mp3")
|
||||
val pendingTask = context.taskManager.createPendingTask(
|
||||
Task(
|
||||
type = TaskType.DOWNLOAD,
|
||||
title = "Call Recording $author",
|
||||
author = author,
|
||||
hash = UUID.randomUUID().toString()
|
||||
)
|
||||
).apply {
|
||||
addListener(PendingTaskListener(
|
||||
onCancel = {
|
||||
mergeJob?.cancel()
|
||||
outputFile.delete()
|
||||
streams.forEach { stream ->
|
||||
stream.outputFile.delete()
|
||||
}
|
||||
}
|
||||
))
|
||||
}
|
||||
|
||||
mergeJob = coroutineScope.launch {
|
||||
try {
|
||||
streams.forEach { stream ->
|
||||
stream.job.join()
|
||||
}
|
||||
|
||||
val sortedStreams = streams.filter { it.outputFile.exists() }.sortedBy { it.startTimestampMillis }
|
||||
FFMpegProcessor.newFFMpegProcessor(context, pendingTask).execute(
|
||||
FFMpegProcessor.Request(
|
||||
action = FFMpegProcessor.Action.MERGE_AUDIO_STREAMS,
|
||||
inputs = sortedStreams.map { it.outputFile.absolutePath },
|
||||
output = outputFile,
|
||||
inputDelayOffsets = sortedStreams.associate { stream -> stream.outputFile.absolutePath to (stream.startTimestampMillis - callStartTimestamp) }
|
||||
)
|
||||
)
|
||||
|
||||
DownloadProcessor(context, object: DownloadCallback.Default() {
|
||||
override fun onSuccess(outputPath: String) {
|
||||
context.log.verbose("Downloaded call $outputPath")
|
||||
}
|
||||
}).saveMediaToGallery(pendingTask, outputFile, DownloadMetadata(
|
||||
mediaIdentifier = UUID.randomUUID().toString(),
|
||||
outputPath = createNewFilePath(
|
||||
context.config.root,
|
||||
UUID.randomUUID().toString().hashCode().absoluteValue.toString(16),
|
||||
downloadSource = MediaDownloadSource.VOICE_CALL,
|
||||
mediaAuthor = author,
|
||||
creationTimestamp = System.currentTimeMillis()
|
||||
),
|
||||
mediaAuthor = author,
|
||||
downloadSource = MediaDownloadSource.VOICE_CALL.translate(context.translation),
|
||||
iconUrl = null
|
||||
))
|
||||
} finally {
|
||||
streams.forEach { stream ->
|
||||
stream.outputFile.delete()
|
||||
}
|
||||
outputFile.delete()
|
||||
}
|
||||
|
||||
context.log.verbose("ending call")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
## v1.1.1
|
||||
## v1.1.2
|
||||
- Fix: Quick Tiles crash.
|
||||
|
||||
## v1.1.0
|
||||
|
||||
@@ -12,6 +12,7 @@ import me.eternal.purrfectsnap.bridge.snapclient.MessagingBridge;
|
||||
import me.eternal.purrfectsnap.bridge.AccountStorage;
|
||||
import me.eternal.purrfectsnap.bridge.storage.FileHandleManager;
|
||||
import me.eternal.purrfectsnap.bridge.location.LocationManager;
|
||||
import me.eternal.purrfectsnap.bridge.call.CallDownloadSession;
|
||||
import me.eternal.purrfectsnap.bridge.task.TaskInterface;
|
||||
|
||||
interface BridgeInterface {
|
||||
@@ -105,4 +106,6 @@ interface BridgeInterface {
|
||||
oneway void registerConfigStateListener(in ConfigStateListener listener);
|
||||
|
||||
@nullable String getDebugProp(String key, @nullable String defaultValue);
|
||||
|
||||
CallDownloadSession startCallDownload(long startTimestamp, String author);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
package me.eternal.purrfectsnap.bridge.call;
|
||||
|
||||
interface CallDownloadSession {
|
||||
ParcelFileDescriptor createStream(long startTimestampMillis, int channels, int sampleRate, int encoding);
|
||||
oneway void end();
|
||||
}
|
||||
@@ -765,6 +765,10 @@
|
||||
"name": "Auto Download Voice Notes",
|
||||
"description": "Automatically downloads voice notes when playing them"
|
||||
},
|
||||
"call_recorder": {
|
||||
"name": "Call Recorder",
|
||||
"description": "Automatically records audio calls"
|
||||
},
|
||||
"download_profile_pictures": {
|
||||
"name": "Download Profile Pictures",
|
||||
"description": "Allows you to download Profile Pictures from the profile page"
|
||||
@@ -1814,10 +1818,6 @@
|
||||
"name": "Story Logger",
|
||||
"description": "Provides a history of friends stories"
|
||||
},
|
||||
"call_recorder": {
|
||||
"name": "Call Recorder",
|
||||
"description": "Automatically records audio calls"
|
||||
},
|
||||
"account_switcher": {
|
||||
"name": "Account Switcher",
|
||||
"description": "Allows you to switch between accounts without logging out\nLong press on the search icon next to your Bitmoji profile to open the menu\nNote: This feature is experimental and will likely change in the future",
|
||||
@@ -2143,6 +2143,11 @@
|
||||
"back": "Back Camera",
|
||||
"null": "Remember last used"
|
||||
},
|
||||
"call_recorder": {
|
||||
"only_record_self": "Only Record Self",
|
||||
"only_record_others": "Only Record Others",
|
||||
"record_both": "Record Both Sides"
|
||||
},
|
||||
"front_custom_frame_rate": {
|
||||
"null": "Device default FPS"
|
||||
},
|
||||
|
||||
@@ -50,4 +50,5 @@ class DownloaderConfig : ConfigContainer() {
|
||||
set(mutableListOf("success", "progress", "failure"))
|
||||
}
|
||||
val customPathFormat = string("custom_path_format") { addNotices(FeatureNotice.UNSTABLE) }
|
||||
}
|
||||
val callRecorder = unique("call_recorder", "only_record_self", "only_record_others", "record_both") { requireRestart(); addNotices(FeatureNotice.UNSTABLE) }
|
||||
}
|
||||
|
||||
@@ -66,7 +66,6 @@ class Experimental : ConfigContainer() {
|
||||
val convertMessageLocally = boolean("convert_message_locally") { requireRestart() }
|
||||
val mediaFilePicker = boolean("media_file_picker") { requireRestart(); addNotices(FeatureNotice.UNSTABLE) }
|
||||
val storyLogger = boolean("story_logger") { requireRestart(); addNotices(FeatureNotice.UNSTABLE); }
|
||||
val callRecorder = boolean("call_recorder") { requireRestart(); addNotices(FeatureNotice.UNSTABLE); }
|
||||
val accountSwitcher = container("account_switcher", AccountSwitcherConfig()) { requireRestart(); addNotices(FeatureNotice.UNSTABLE) }
|
||||
val betterTranscript = container("better_transcript", BetterTranscriptConfig()) { requireRestart() }
|
||||
val voiceNoteAutoPlay = boolean("voice_note_auto_play") { requireRestart() }
|
||||
|
||||
@@ -4,6 +4,7 @@ import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.res.Resources
|
||||
import android.os.Build
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.os.Process
|
||||
@@ -161,7 +162,8 @@ class ModContext(
|
||||
NativeConfig(
|
||||
disableBitmoji = config.experimental.nativeHooks.disableBitmoji.get(),
|
||||
disableMetrics = config.global.disableMetrics.get(),
|
||||
valdiHooks = config.experimental.nativeHooks.valdiHooks.globalState == true,
|
||||
valdiHooks = config.experimental.nativeHooks.valdiHooks.globalState == true &&
|
||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q,
|
||||
customEmojiFontPath = getCustomEmojiFontPath(this)
|
||||
)
|
||||
)
|
||||
|
||||
@@ -7,6 +7,7 @@ import android.content.res.Resources
|
||||
import android.os.Build
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.outlined.Cancel
|
||||
import java.lang.reflect.Method
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
@@ -49,6 +50,8 @@ class PurrfectSnap {
|
||||
}
|
||||
private lateinit var appContext: ModContext
|
||||
private var isBridgeInitialized = false
|
||||
private var android9ValdiBindDisabled = false
|
||||
private var android9ValdiBindDisableLogged = false
|
||||
|
||||
private fun hookMainActivity(methodName: String, stage: HookStage = HookStage.AFTER, block: Activity.(param: HookAdapter) -> Unit) {
|
||||
Activity::class.java.hook(methodName, stage, { isBridgeInitialized }) { param ->
|
||||
@@ -156,6 +159,7 @@ class PurrfectSnap {
|
||||
}
|
||||
|
||||
reloadConfig()
|
||||
installAndroid9ValdiBindGuard()
|
||||
initNative()
|
||||
initWidgetListener()
|
||||
scope.launch(Dispatchers.IO) {
|
||||
@@ -244,6 +248,89 @@ class PurrfectSnap {
|
||||
}
|
||||
}
|
||||
|
||||
private fun installAndroid9ValdiBindGuard() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) return
|
||||
val valdiNativeBridge = runCatching {
|
||||
classLoader.loadClass("com.snapchat.client.valdi.NativeBridge")
|
||||
}.getOrNull()
|
||||
val targetClasses = listOf("AXj", "NZj", "MZj")
|
||||
.mapNotNull { className ->
|
||||
runCatching { classLoader.loadClass(className) }.getOrNull()
|
||||
}
|
||||
.distinct()
|
||||
if (targetClasses.isEmpty()) return
|
||||
fun defaultReturn(type: Class<*>): Any? = when (type) {
|
||||
Boolean::class.javaPrimitiveType -> false
|
||||
Byte::class.javaPrimitiveType -> 0.toByte()
|
||||
Short::class.javaPrimitiveType -> 0.toShort()
|
||||
Int::class.javaPrimitiveType -> 0
|
||||
Long::class.javaPrimitiveType -> 0L
|
||||
Float::class.javaPrimitiveType -> 0f
|
||||
Double::class.javaPrimitiveType -> 0.0
|
||||
Char::class.javaPrimitiveType -> 0.toChar()
|
||||
Void.TYPE -> null
|
||||
else -> null
|
||||
}
|
||||
|
||||
fun installGuard(targetClass: Class<*>, methodName: String) {
|
||||
targetClass.hook(methodName, HookStage.BEFORE) { param ->
|
||||
val method = param.method() as? Method ?: return@hook
|
||||
if (android9ValdiBindDisabled) {
|
||||
if (!android9ValdiBindDisableLogged) {
|
||||
android9ValdiBindDisableLogged = true
|
||||
appContext.log.warn("Skipping Valdi bind on Android 9 due to missing native impl")
|
||||
}
|
||||
param.setResult(defaultReturn(method.returnType))
|
||||
return@hook
|
||||
}
|
||||
runCatching {
|
||||
param.invokeOriginal()
|
||||
}.onSuccess { result ->
|
||||
param.setResult(result)
|
||||
}.onFailure { throwable ->
|
||||
val rootCause = throwable.cause ?: throwable
|
||||
val message = rootCause.message ?: throwable.message
|
||||
val isMissingNativeImpl = rootCause is UnsatisfiedLinkError &&
|
||||
message?.contains("NativeBridge.createContext") == true
|
||||
val isValdiContextNpe = rootCause is NullPointerException &&
|
||||
message?.contains("ValdiContext") == true
|
||||
if (isMissingNativeImpl || isValdiContextNpe) {
|
||||
android9ValdiBindDisabled = true
|
||||
if (!android9ValdiBindDisableLogged) {
|
||||
android9ValdiBindDisableLogged = true
|
||||
appContext.log.warn("Skipping Valdi bind on Android 9 due to missing native impl")
|
||||
if (isMissingNativeImpl) {
|
||||
appContext.log.error("Android 9 Valdi NativeBridge.createContext missing native impl", rootCause)
|
||||
}
|
||||
}
|
||||
param.setResult(defaultReturn(method.returnType))
|
||||
return@hook
|
||||
}
|
||||
appContext.log.error("Android 9 Valdi bind hook failed", throwable)
|
||||
param.setResult(defaultReturn(method.returnType))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
targetClasses.forEach { targetClass ->
|
||||
installGuard(targetClass, "f")
|
||||
installGuard(targetClass, "g2")
|
||||
installGuard(targetClass, "n2")
|
||||
installGuard(targetClass, "d")
|
||||
}
|
||||
|
||||
valdiNativeBridge?.hook("createContext", HookStage.AFTER) { param ->
|
||||
val throwable = param.throwable() as? UnsatisfiedLinkError ?: return@hook
|
||||
android9ValdiBindDisabled = true
|
||||
if (!android9ValdiBindDisableLogged) {
|
||||
android9ValdiBindDisableLogged = true
|
||||
appContext.log.warn("Skipping Valdi bind on Android 9 due to missing native impl")
|
||||
appContext.log.error("Android 9 Valdi NativeBridge.createContext missing native impl", throwable)
|
||||
}
|
||||
param.setResult(null)
|
||||
}
|
||||
}
|
||||
|
||||
private fun initNative() {
|
||||
val nativeSigCacheFileHandle = appContext.fileHandlerManager.getFileHandle(FileHandleScope.INTERNAL.key, InternalFileHandleType.NATIVE_SIG_CACHE.key).toWrapper()
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ import kotlinx.coroutines.sync.Semaphore
|
||||
import kotlinx.coroutines.sync.withPermit
|
||||
import kotlinx.coroutines.withTimeoutOrNull
|
||||
import me.eternal.purrfectsnap.bridge.*
|
||||
import me.eternal.purrfectsnap.bridge.call.CallDownloadSession
|
||||
import me.eternal.purrfectsnap.bridge.e2ee.E2eeInterface
|
||||
import me.eternal.purrfectsnap.bridge.location.LocationManager
|
||||
import me.eternal.purrfectsnap.bridge.logger.LoggerInterface
|
||||
@@ -284,5 +285,12 @@ class BridgeClient(
|
||||
fun registerConfigStateListener(listener: ConfigStateListener) = safeServiceCall { service.registerConfigStateListener(listener) }
|
||||
|
||||
fun getDebugProp(name: String, defaultValue: String? = null): String? = safeServiceCall { service.getDebugProp(name, defaultValue) }
|
||||
|
||||
fun startCallDownload(
|
||||
startTimestamp: Long,
|
||||
author: String,
|
||||
): CallDownloadSession {
|
||||
return safeServiceCall { service.startCallDownload(startTimestamp, author) }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import android.content.Intent
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.os.Build
|
||||
import me.eternal.purrfectsnap.common.util.snap.SnapWidgetBroadcastReceiverHelper
|
||||
import me.eternal.purrfectsnap.core.ModContext
|
||||
import me.eternal.purrfectsnap.core.event.events.impl.*
|
||||
@@ -27,6 +28,10 @@ class EventDispatcher(
|
||||
private val context: ModContext
|
||||
) {
|
||||
private fun hookViewBinder() {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
|
||||
context.log.warn("BindViewEvent hooks disabled on Android 9 and below")
|
||||
return
|
||||
}
|
||||
context.mappings.useMapper(ViewBinderMapper::class) {
|
||||
val cachedHooks = mutableListOf<String>()
|
||||
fun cacheHook(clazz: Class<*>, block: Class<*>.() -> Unit) {
|
||||
|
||||
@@ -6,6 +6,7 @@ import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import me.eternal.purrfectsnap.core.ModContext
|
||||
import me.eternal.purrfectsnap.core.features.impl.*
|
||||
import me.eternal.purrfectsnap.core.features.impl.downloader.CallRecorder
|
||||
import me.eternal.purrfectsnap.core.features.impl.downloader.MediaDownloader
|
||||
import me.eternal.purrfectsnap.core.features.impl.downloader.ProfilePictureDownloader
|
||||
import me.eternal.purrfectsnap.core.features.impl.experiments.*
|
||||
|
||||
@@ -0,0 +1,178 @@
|
||||
package me.eternal.purrfectsnap.core.features.impl.downloader
|
||||
|
||||
import android.media.AudioAttributes
|
||||
import android.media.AudioFormat
|
||||
import android.media.AudioRecord
|
||||
import android.media.AudioTrack
|
||||
import android.os.ParcelFileDescriptor
|
||||
import me.eternal.purrfectsnap.bridge.call.CallDownloadSession
|
||||
import me.eternal.purrfectsnap.core.features.Feature
|
||||
import me.eternal.purrfectsnap.core.util.hook.HookStage
|
||||
import me.eternal.purrfectsnap.core.util.hook.hook
|
||||
import me.eternal.purrfectsnap.core.util.hook.hookConstructor
|
||||
import me.eternal.purrfectsnap.core.util.ktx.getObjectField
|
||||
import me.eternal.purrfectsnap.core.util.ktx.getObjectFieldOrNull
|
||||
import me.eternal.purrfectsnap.core.wrapper.impl.SnapUUID
|
||||
import java.io.OutputStream
|
||||
import java.nio.ByteBuffer
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
class CallRecorder : Feature("Call Recorder") {
|
||||
private var wasInCall = false
|
||||
private var callDownloadSession: CallDownloadSession? = null
|
||||
|
||||
inner class LazyStream(
|
||||
private val audioFormat: AudioFormat,
|
||||
private val startTimestamp: Long = System.currentTimeMillis(),
|
||||
) {
|
||||
private var stream: ParcelFileDescriptor.AutoCloseOutputStream? = null
|
||||
|
||||
fun get(): OutputStream? {
|
||||
if (stream != null) return stream
|
||||
if (callDownloadSession == null) return null
|
||||
|
||||
stream = ParcelFileDescriptor.AutoCloseOutputStream(
|
||||
callDownloadSession?.createStream(
|
||||
startTimestamp,
|
||||
audioFormat.channelCount,
|
||||
audioFormat.sampleRate,
|
||||
audioFormat.encoding
|
||||
) ?: return null
|
||||
)
|
||||
|
||||
return stream
|
||||
}
|
||||
}
|
||||
|
||||
private fun initCallDownloadSession(conversationId: String) {
|
||||
val author = (if (context.database.getConversationType(conversationId) == 1) {
|
||||
context.database.getFeedEntryByConversationId(conversationId)?.feedDisplayName
|
||||
} else {
|
||||
context.database.getDMOtherParticipant(conversationId)?.let { context.database.getFriendInfo(it)?.mutableUsername }
|
||||
}) ?: "unknown"
|
||||
callDownloadSession = context.bridgeClient.startCallDownload(System.currentTimeMillis(), author)
|
||||
}
|
||||
|
||||
private fun onCallStarted(conversationId: String) {
|
||||
initCallDownloadSession(conversationId)
|
||||
}
|
||||
|
||||
private fun onCallEnded(conversationId: String) {
|
||||
callDownloadSession?.end()
|
||||
}
|
||||
|
||||
override fun init() {
|
||||
val callRecorderConfig = context.config.downloader.callRecorder.getNullable()
|
||||
if (callRecorderConfig == null) return
|
||||
|
||||
val streams = ConcurrentHashMap<Int, LazyStream>() // audioTrack -> stream
|
||||
|
||||
runCatching {
|
||||
findClass("com.snapchat.talkcorev3.CallingSessionState")
|
||||
}.getOrNull()?.hookConstructor(HookStage.AFTER) { param ->
|
||||
val instance = param.thisObject<Any>()
|
||||
val callingState = instance.getObjectFieldOrNull("mLocalUser")?.getObjectField("mCallingState")
|
||||
|
||||
if (callingState.toString() == "IN_CALL") {
|
||||
// TODO: implement for older Snapchat versions
|
||||
}
|
||||
} ?: findClass("com.snapchat.talkcorev3.TSCallingStateUpdateParams").hookConstructor(
|
||||
HookStage.AFTER) { param ->
|
||||
val instance = param.thisObject<Any>()
|
||||
val conversationId = SnapUUID(instance.getObjectField("mConversationId")).toString()
|
||||
|
||||
if (instance.getObjectFieldOrNull("mInCall") == true) {
|
||||
if (!wasInCall) {
|
||||
wasInCall = true
|
||||
onCallStarted(conversationId)
|
||||
}
|
||||
} else {
|
||||
if (wasInCall) {
|
||||
wasInCall = false
|
||||
onCallEnded(conversationId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
AudioRecord::class.java.apply {
|
||||
if (callRecorderConfig == "only_record_others") return@apply
|
||||
declaredConstructors.first { it.parameterCount > 5 }.hook(HookStage.AFTER) { param ->
|
||||
val audioAttributes = param.arg<AudioAttributes>(0)
|
||||
context.log.verbose(audioAttributes.usage)
|
||||
if (audioAttributes.usage != AudioAttributes.USAGE_UNKNOWN) return@hook
|
||||
val audioFormat = param.arg<AudioFormat>(1)
|
||||
val hashCode = param.thisObject<Any>().hashCode()
|
||||
|
||||
streams.put(hashCode, LazyStream(audioFormat))
|
||||
context.log.verbose("AudioRecord called usage=${audioAttributes.usage}, format=$audioFormat")
|
||||
}
|
||||
|
||||
getMethod("read", ByteBuffer::class.java, Int::class.javaPrimitiveType, Int::class.javaPrimitiveType).hook(
|
||||
HookStage.AFTER) { param ->
|
||||
val readBytes = param.getResult() as Int
|
||||
if (readBytes <= 0) return@hook
|
||||
|
||||
streams[param.thisObject<Any>().hashCode()]?.let { handlers ->
|
||||
val byteBuffer = param.arg<ByteBuffer>(0)
|
||||
val position = byteBuffer.position()
|
||||
val buffer = ByteArray(readBytes)
|
||||
byteBuffer.get(buffer)
|
||||
byteBuffer.position(position)
|
||||
|
||||
runCatching {
|
||||
handlers.get()?.write(buffer, 0, buffer.size)
|
||||
}.onFailure {
|
||||
context.log.error("Failed to record call audio data", it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hook("release", HookStage.BEFORE) {
|
||||
runCatching {
|
||||
streams.remove(it.thisObject<Any>().hashCode())?.get()?.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AudioTrack::class.java.apply {
|
||||
if (callRecorderConfig == "only_record_self") return@apply
|
||||
getConstructor(
|
||||
AudioAttributes::class.java,
|
||||
AudioFormat::class.java,
|
||||
Int::class.javaPrimitiveType,
|
||||
Int::class.javaPrimitiveType,
|
||||
Int::class.javaPrimitiveType,
|
||||
).hook(HookStage.AFTER) { param ->
|
||||
val audioAttributes = param.arg<AudioAttributes>(0)
|
||||
if (audioAttributes.usage != AudioAttributes.USAGE_VOICE_COMMUNICATION) return@hook
|
||||
val audioFormat = param.arg<AudioFormat>(1)
|
||||
val hashCode = param.thisObject<Any>().hashCode()
|
||||
|
||||
streams.put(hashCode, LazyStream(audioFormat))
|
||||
context.log.verbose("AudioTrack called usage=${audioAttributes.usage}, format=$audioFormat")
|
||||
}
|
||||
|
||||
getMethod("write", ByteBuffer::class.java, Int::class.javaPrimitiveType, Int::class.javaPrimitiveType).hook(
|
||||
HookStage.BEFORE) { param ->
|
||||
streams[param.thisObject<Any>().hashCode()]?.let { handlers ->
|
||||
val byteBuffer = param.arg<ByteBuffer>(0)
|
||||
val position = byteBuffer.position()
|
||||
val buffer = ByteArray(param.arg(1))
|
||||
byteBuffer.get(buffer)
|
||||
byteBuffer.position(position)
|
||||
|
||||
runCatching {
|
||||
handlers.get()?.write(buffer, 0, buffer.size)
|
||||
}.onFailure {
|
||||
context.log.error("Failed to record call audio data", it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hook("release", HookStage.BEFORE) {
|
||||
runCatching { streams.remove(it.thisObject<Any>().hashCode())?.get()?.close() }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import android.widget.RelativeLayout
|
||||
import me.eternal.purrfectsnap.common.util.protobuf.ProtoReader
|
||||
import me.eternal.purrfectsnap.core.event.events.impl.AddViewEvent
|
||||
import me.eternal.purrfectsnap.core.event.events.impl.NetworkApiRequestEvent
|
||||
import me.eternal.purrfectsnap.core.event.events.impl.UnaryCallEvent
|
||||
import me.eternal.purrfectsnap.core.features.Feature
|
||||
import me.eternal.purrfectsnap.core.ui.ViewAppearanceHelper
|
||||
|
||||
@@ -19,11 +20,23 @@ class ProfilePictureDownloader : Feature("ProfilePictureDownloader") {
|
||||
var avatarUrl: String? = null
|
||||
|
||||
onNextActivityCreate(defer = true) {
|
||||
val profileViewClasses = setOf(
|
||||
"com.snap.unifiedpublicprofile.UnifiedPublicProfileView",
|
||||
"com.snap.modules.profile3.UserProfileV2RootComponent",
|
||||
"com.snap.profile.ui.flatland.UnifiedProfileFlatlandProfileView"
|
||||
)
|
||||
|
||||
context.event.subscribe(AddViewEvent::class) { event ->
|
||||
if (event.view::class.java.name != "com.snap.unifiedpublicprofile.UnifiedPublicProfileView") return@subscribe
|
||||
if (event.view::class.java.name !in profileViewClasses) return@subscribe
|
||||
|
||||
val buttonText = this@ProfilePictureDownloader.context.translation["profile_picture_downloader.button"]
|
||||
if ((0 until event.parent.childCount).any {
|
||||
val child = event.parent.getChildAt(it)
|
||||
child is Button && (child as Button).text == buttonText
|
||||
}) return@subscribe
|
||||
|
||||
event.parent.addView(Button(event.parent.context).apply {
|
||||
text = this@ProfilePictureDownloader.context.translation["profile_picture_downloader.button"]
|
||||
text = buttonText
|
||||
layoutParams = RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT).apply {
|
||||
setMargins(0, 200, 0, 0)
|
||||
}
|
||||
@@ -36,16 +49,21 @@ class ProfilePictureDownloader : Feature("ProfilePictureDownloader") {
|
||||
backgroundUrl?.let { choices["background_option"] = it }
|
||||
avatarUrl?.let { choices["avatar_option"] = it }
|
||||
|
||||
setItems(choices.keys.map {
|
||||
this@ProfilePictureDownloader.context.translation["profile_picture_downloader.$it"]
|
||||
}.toTypedArray()) { _, which ->
|
||||
runCatching {
|
||||
this@ProfilePictureDownloader.context.feature(MediaDownloader::class).downloadProfilePicture(
|
||||
choices.values.elementAt(which),
|
||||
friendUsername!!
|
||||
)
|
||||
}.onFailure {
|
||||
this@ProfilePictureDownloader.context.log.error("Failed to download profile picture", it)
|
||||
if (choices.isEmpty()) {
|
||||
setMessage("No profile pictures available. Please wait for the profile to load.")
|
||||
setPositiveButton("OK") { dialog, _ -> dialog.dismiss() }
|
||||
} else {
|
||||
setItems(choices.keys.map {
|
||||
this@ProfilePictureDownloader.context.translation["profile_picture_downloader.$it"]
|
||||
}.toTypedArray()) { _, which ->
|
||||
runCatching {
|
||||
this@ProfilePictureDownloader.context.feature(MediaDownloader::class).downloadProfilePicture(
|
||||
choices.values.elementAt(which),
|
||||
friendUsername ?: "unknown"
|
||||
)
|
||||
}.onFailure {
|
||||
this@ProfilePictureDownloader.context.log.error("Failed to download profile picture", it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}.show()
|
||||
@@ -54,18 +72,31 @@ class ProfilePictureDownloader : Feature("ProfilePictureDownloader") {
|
||||
}
|
||||
|
||||
|
||||
context.event.subscribe(NetworkApiRequestEvent::class) { event ->
|
||||
if (!event.url.endsWith("/rpc/getPublicProfile")) return@subscribe
|
||||
event.onSuccess { buffer ->
|
||||
ProtoReader(buffer ?: return@onSuccess).followPath(1, 1, 2) {
|
||||
fun parseProfileData(buffer: ByteArray) {
|
||||
runCatching {
|
||||
ProtoReader(buffer).followPath(1, 1, 2) {
|
||||
friendUsername = getString(2) ?: return@followPath
|
||||
followPath(4) {
|
||||
backgroundUrl = getString(2)
|
||||
avatarUrl = getString(100)
|
||||
}
|
||||
}
|
||||
}.onFailure {
|
||||
context.log.error("Failed to parse profile picture data", it)
|
||||
}
|
||||
}
|
||||
|
||||
context.event.subscribe(NetworkApiRequestEvent::class) { event ->
|
||||
if (!event.url.contains("getPublicProfile")) return@subscribe
|
||||
event.onSuccess { buffer -> buffer?.let { parseProfileData(it) } }
|
||||
}
|
||||
|
||||
context.event.subscribe(UnaryCallEvent::class) { event ->
|
||||
if (!event.uri.contains("getPublicProfile")) return@subscribe
|
||||
event.addResponseCallback {
|
||||
parseProfileData(buffer)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,141 +0,0 @@
|
||||
package me.eternal.purrfectsnap.core.features.impl.experiments
|
||||
|
||||
import android.media.AudioAttributes
|
||||
import android.media.AudioFormat
|
||||
import android.media.AudioTrack
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.withTimeoutOrNull
|
||||
import me.eternal.purrfectsnap.common.data.download.AudioStreamFormat
|
||||
import me.eternal.purrfectsnap.common.data.download.MediaDownloadSource
|
||||
import me.eternal.purrfectsnap.core.features.Feature
|
||||
import me.eternal.purrfectsnap.core.features.impl.downloader.MediaDownloader
|
||||
import me.eternal.purrfectsnap.core.util.hook.HookStage
|
||||
import me.eternal.purrfectsnap.core.util.hook.hook
|
||||
import me.eternal.purrfectsnap.core.util.hook.hookConstructor
|
||||
import me.eternal.purrfectsnap.core.util.ktx.getObjectField
|
||||
import me.eternal.purrfectsnap.core.util.ktx.getObjectFieldOrNull
|
||||
import me.eternal.purrfectsnap.core.util.media.HttpServer
|
||||
import java.io.PipedInputStream
|
||||
import java.io.PipedOutputStream
|
||||
import java.nio.ByteBuffer
|
||||
import java.util.UUID
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import java.util.concurrent.CopyOnWriteArrayList
|
||||
|
||||
class CallRecorder : Feature("Call Recorder") {
|
||||
private val httpServer = HttpServer(
|
||||
timeout = Integer.MAX_VALUE
|
||||
)
|
||||
|
||||
override fun init() {
|
||||
if (!context.config.experimental.callRecorder.get()) return
|
||||
|
||||
val streamHandlers = ConcurrentHashMap<Int, MutableList<(data: ByteArray) -> Unit>>() // audioTrack -> handlers
|
||||
val participants = CopyOnWriteArrayList<String>()
|
||||
|
||||
runCatching {
|
||||
findClass("com.snapchat.talkcorev3.CallingSessionState")
|
||||
}.getOrNull()?.hookConstructor(HookStage.AFTER) { param ->
|
||||
val instance = param.thisObject<Any>()
|
||||
val callingState = instance.getObjectFieldOrNull("mLocalUser")?.getObjectField("mCallingState")
|
||||
|
||||
if (callingState.toString() == "IN_CALL") {
|
||||
participants.clear()
|
||||
participants.addAll((instance.getObjectField("mParticipants") as Map<*, *>).keys.map { it.toString() })
|
||||
}
|
||||
} ?: findClass("com.snapchat.talkcorev3.TSCallingStateUpdateParams").hookConstructor(HookStage.AFTER) { param ->
|
||||
val instance = param.thisObject<Any>()
|
||||
|
||||
if (instance.getObjectFieldOrNull("mInCall") == true) {
|
||||
participants.clear()
|
||||
participants.addAll((instance.getObjectField("mParticipants") as Set<*>).map { it.toString() })
|
||||
}
|
||||
}
|
||||
|
||||
AudioTrack::class.java.apply {
|
||||
getConstructor(
|
||||
AudioAttributes::class.java,
|
||||
AudioFormat::class.java,
|
||||
Int::class.javaPrimitiveType,
|
||||
Int::class.javaPrimitiveType,
|
||||
Int::class.javaPrimitiveType,
|
||||
).hook(HookStage.BEFORE) { param ->
|
||||
val audioAttributes = param.arg<AudioAttributes>(0)
|
||||
if (audioAttributes.usage != AudioAttributes.USAGE_VOICE_COMMUNICATION) return@hook
|
||||
val audioFormat = param.arg<AudioFormat>(1)
|
||||
val hashCode = param.thisObject<Any>().hashCode()
|
||||
|
||||
lateinit var streamUrl: String
|
||||
streamUrl = httpServer.ensureServerStarted()?.putContent(
|
||||
object: HttpServer.HttpContent() {
|
||||
override val contentType: String = "audio/wav"
|
||||
override val chunked: Boolean = true
|
||||
override val contentLength: Long? = null
|
||||
override val newBody: () -> HttpServer.HttpBody = {
|
||||
object: HttpServer.HttpBody() {
|
||||
val outputStream = PipedOutputStream()
|
||||
val inputStream = PipedInputStream(outputStream)
|
||||
|
||||
val handler: (byteArray: ByteArray) -> Unit = handler@{ byteArray ->
|
||||
if (byteArray.isEmpty()) {
|
||||
httpServer.removeUrl(streamUrl)
|
||||
return@handler
|
||||
}
|
||||
runCatching {
|
||||
outputStream.write(byteArray)
|
||||
outputStream.flush()
|
||||
}.onFailure {
|
||||
context.log.warn("Failed to write to streaming url ${it.localizedMessage}")
|
||||
}
|
||||
}
|
||||
|
||||
override val onOpen: () -> Unit = {
|
||||
streamHandlers.getOrPut(hashCode) { CopyOnWriteArrayList() }.add(handler)
|
||||
}
|
||||
|
||||
override val readBytes: (byteArray: ByteArray) -> Int = { byteArray ->
|
||||
runBlocking {
|
||||
withTimeoutOrNull(3000L) {
|
||||
inputStream.read(byteArray)
|
||||
} ?: -1
|
||||
}
|
||||
}
|
||||
|
||||
override val onClose: () -> Unit = {
|
||||
context.log.verbose("Streaming url closed")
|
||||
streamHandlers[hashCode]?.remove(handler)
|
||||
outputStream.close()
|
||||
inputStream.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
) ?: return@hook
|
||||
|
||||
context.log.verbose("streaming url = $streamUrl, sampleRate = ${audioFormat.sampleRate}, audioFormat = ${audioFormat.encoding}")
|
||||
|
||||
context.feature(MediaDownloader::class).provideDownloadManagerClient(
|
||||
UUID.randomUUID().toString(),
|
||||
participants.mapNotNull { context.database.getFriendInfo(it)?.mutableUsername }.joinToString("-"),
|
||||
System.currentTimeMillis(),
|
||||
MediaDownloadSource.VOICE_CALL
|
||||
).downloadStream(streamUrl, AudioStreamFormat(audioFormat.channelCount, audioFormat.sampleRate, audioFormat.encoding))
|
||||
}
|
||||
|
||||
getMethod("write", ByteBuffer::class.java, Int::class.javaPrimitiveType, Int::class.javaPrimitiveType).hook(HookStage.BEFORE) { param ->
|
||||
streamHandlers[param.thisObject<Any>().hashCode()]?.let { handlers ->
|
||||
val byteBuffer = param.arg<ByteBuffer>(0)
|
||||
val position = byteBuffer.position()
|
||||
val buffer = ByteArray(param.arg(1))
|
||||
byteBuffer.get(buffer)
|
||||
byteBuffer.position(position)
|
||||
handlers.forEach { it(buffer) }
|
||||
}
|
||||
}
|
||||
|
||||
hook("release", HookStage.BEFORE) {
|
||||
streamHandlers.remove(it.thisObject<Any>().hashCode())?.forEach { it(ByteArray(0)) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,7 @@ import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import kotlinx.coroutines.launch
|
||||
import android.os.Build
|
||||
import me.eternal.purrfectsnap.common.bridge.FileHandleScope
|
||||
import me.eternal.purrfectsnap.common.bridge.toWrapper
|
||||
import me.eternal.purrfectsnap.common.ui.createComposeAlertDialog
|
||||
@@ -113,6 +114,10 @@ class ValdiHooks: Feature("ValdiHooks") {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override fun init() {
|
||||
if (config.globalState != true) return
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
|
||||
context.log.warn("ValdiHooks disabled on Android 9 and below")
|
||||
return
|
||||
}
|
||||
|
||||
if (PurrfectSnap.classCache.valdiFunction == null) {
|
||||
context.log.warn("ComposerFunction/ValdiFunction class not found, ValdiHooks feature disabled")
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package me.eternal.purrfectsnap.core.features.impl.tweaks
|
||||
|
||||
import android.os.Build
|
||||
import android.view.ViewGroup
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
@@ -27,6 +28,7 @@ class VoiceNoteOverride: Feature("Voice Note Override") {
|
||||
|
||||
val playbackMap = sortedMapOf<Long, Any>()
|
||||
val classLoader = context.androidContext.classLoader
|
||||
var valdiCreateContextWarned = false
|
||||
|
||||
fun tryFallbackCreateContext(param: HookAdapter): Any? {
|
||||
val fallbackClass = runCatching {
|
||||
@@ -149,6 +151,17 @@ class VoiceNoteOverride: Feature("Voice Note Override") {
|
||||
|
||||
PurrfectSnap.classCache.nativeBridge.hook("createContext", HookStage.AFTER) { param ->
|
||||
val throwable = param.throwable() as? UnsatisfiedLinkError ?: return@hook
|
||||
val isAndroid9OrBelow = Build.VERSION.SDK_INT < Build.VERSION_CODES.Q
|
||||
val isValdiBridge = PurrfectSnap.classCache.nativeBridge.name == "com.snapchat.client.valdi.NativeBridge"
|
||||
if (isAndroid9OrBelow && isValdiBridge) {
|
||||
if (!valdiCreateContextWarned) {
|
||||
valdiCreateContextWarned = true
|
||||
context.log.warn("NativeBridge.createContext missing native impl on Android 9; skipping fallback")
|
||||
}
|
||||
param.clearThrowable()
|
||||
param.setResult(null)
|
||||
return@hook
|
||||
}
|
||||
context.log.error("NativeBridge.createContext missing native impl; attempting fallback", throwable)
|
||||
val fallback = tryFallbackCreateContext(param)
|
||||
param.setResult(fallback)
|
||||
|
||||
@@ -103,13 +103,24 @@ val nativeAbisProp = (findProperty("nativeAbis") as? String)
|
||||
?.takeIf { it.isNotBlank() }
|
||||
?: System.getenv("NATIVE_ABIS")
|
||||
?: "arm64-v8a,armeabi-v7a"
|
||||
val enabledNativeAbis = nativeAbisProp
|
||||
var enabledNativeAbis = nativeAbisProp
|
||||
.split(',', ';')
|
||||
.map { it.trim() }
|
||||
.filter { it.isNotEmpty() }
|
||||
.toSet()
|
||||
.ifEmpty { setOf("arm64-v8a", "armeabi-v7a") }
|
||||
|
||||
val requestedTasks = gradle.startParameter.taskNames.joinToString(" ")
|
||||
val wantsArmv7 = requestedTasks.contains("armv7", ignoreCase = true)
|
||||
val wantsArmv8 = requestedTasks.contains("armv8", ignoreCase = true)
|
||||
if (wantsArmv7 && !wantsArmv8) {
|
||||
enabledNativeAbis = setOf("armeabi-v7a")
|
||||
} else if (wantsArmv8 && !wantsArmv7) {
|
||||
enabledNativeAbis = setOf("arm64-v8a")
|
||||
} else if (wantsArmv7 && wantsArmv8) {
|
||||
enabledNativeAbis = enabledNativeAbis + setOf("armeabi-v7a", "arm64-v8a")
|
||||
}
|
||||
|
||||
val cargoTargets = listOf(
|
||||
CargoTarget(
|
||||
triple = "aarch64-linux-android",
|
||||
@@ -247,17 +258,16 @@ val syncTasks = cargoTargets.mapIndexed { index, target ->
|
||||
inputs.property("outputLibName", outputLibName)
|
||||
val wslCandidate = File(wslStagingDir, "native/rust/target/${target.triple}/release/libpurrfectsnap.so")
|
||||
val localCandidate = layout.projectDirectory.file("rust/target/${target.triple}/release/libpurrfectsnap.so").asFile
|
||||
val sourceLibProvider = providers.provider {
|
||||
if (wslCandidate.exists()) wslCandidate else localCandidate
|
||||
}
|
||||
from(sourceLibProvider) {
|
||||
val sourceLibs = files(wslCandidate, localCandidate)
|
||||
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
|
||||
from(sourceLibs) {
|
||||
rename { outputLibName }
|
||||
}
|
||||
from(sourceLibProvider) {
|
||||
from(sourceLibs) {
|
||||
rename { "libpurrfectsnap.so" }
|
||||
}
|
||||
into(layout.buildDirectory.dir("rustJniLibs/android/${target.abi}"))
|
||||
inputs.files(sourceLibProvider)
|
||||
inputs.files(sourceLibs)
|
||||
val checksumsDir = layout.buildDirectory.dir("checksums")
|
||||
doLast {
|
||||
val file = File(destinationDir, outputLibName)
|
||||
@@ -313,6 +323,7 @@ android {
|
||||
|
||||
defaultConfig {
|
||||
buildConfigField("String", "NATIVE_NAME", "\"$nativeBuildHash\".toString()")
|
||||
buildConfigField("String", "MODULE_PACKAGE_NAME", "\"${rootProject.ext["applicationId"]}\"")
|
||||
minSdk = 28
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package me.eternal.purrfectsnap.nativelib
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.util.Log
|
||||
import java.io.File
|
||||
import kotlin.math.absoluteValue
|
||||
@@ -15,40 +16,52 @@ class NativeLib {
|
||||
private set
|
||||
private var libraryLoaded = false
|
||||
|
||||
private fun findNativeLibraryDir(): File? {
|
||||
private fun findNativeLibraryDirs(): List<File> {
|
||||
val app = runCatching {
|
||||
val cls = Class.forName("android.app.ActivityThread")
|
||||
val method = cls.getMethod("currentApplication")
|
||||
method.invoke(null) as? android.app.Application
|
||||
}.getOrNull() ?: return null
|
||||
val dir = app.applicationInfo.nativeLibraryDir ?: return null
|
||||
return File(dir)
|
||||
}.getOrNull() ?: return emptyList()
|
||||
|
||||
val dirs = mutableListOf<File>()
|
||||
val moduleDir = runCatching {
|
||||
app.createPackageContext(BuildConfig.MODULE_PACKAGE_NAME, Context.CONTEXT_IGNORE_SECURITY)
|
||||
.applicationInfo.nativeLibraryDir
|
||||
}.getOrNull()
|
||||
moduleDir?.let { dirs.add(File(it)) }
|
||||
|
||||
app.applicationInfo.nativeLibraryDir?.let { dirs.add(File(it)) }
|
||||
|
||||
return dirs.distinctBy { it.absolutePath }
|
||||
}
|
||||
|
||||
private fun tryLoadFromNativeDir(): Boolean {
|
||||
val dir = findNativeLibraryDir() ?: return false
|
||||
if (!dir.isDirectory) return false
|
||||
val dirs = findNativeLibraryDirs().filter { it.isDirectory }
|
||||
if (dirs.isEmpty()) return false
|
||||
|
||||
val candidates = listOf(
|
||||
"lib${BuildConfig.NATIVE_NAME}.so",
|
||||
"libpurrfectsnap.so"
|
||||
).map { File(dir, it) }
|
||||
for (dir in dirs) {
|
||||
val candidates = listOf(
|
||||
"lib${BuildConfig.NATIVE_NAME}.so",
|
||||
"libpurrfectsnap.so"
|
||||
).map { File(dir, it) }
|
||||
|
||||
val fallback = dir.listFiles()?.firstOrNull { it.name.startsWith("lib") && it.name.endsWith(".so") && it.name.contains("purrfectsnap") }
|
||||
val fallback = dir.listFiles()
|
||||
?.firstOrNull { it.name.startsWith("lib") && it.name.endsWith(".so") && it.name.contains("purrfectsnap") }
|
||||
|
||||
val ordered = buildList<File> {
|
||||
addAll(candidates)
|
||||
fallback?.let { if (!contains(it)) add(it) }
|
||||
}
|
||||
val ordered = buildList<File> {
|
||||
addAll(candidates)
|
||||
fallback?.let { if (!contains(it)) add(it) }
|
||||
}
|
||||
|
||||
for (file in ordered) {
|
||||
if (!file.exists()) continue
|
||||
val ok = runCatching {
|
||||
System.load(file.absolutePath)
|
||||
libraryLoaded = true
|
||||
true
|
||||
}.getOrDefault(false)
|
||||
if (ok) return true
|
||||
for (file in ordered) {
|
||||
if (!file.exists()) continue
|
||||
val ok = runCatching {
|
||||
System.load(file.absolutePath)
|
||||
libraryLoaded = true
|
||||
true
|
||||
}.getOrDefault(false)
|
||||
if (ok) return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
96
valdi/node_modules/typescript/lib/_tsc.js
generated
vendored
96
valdi/node_modules/typescript/lib/_tsc.js
generated
vendored
@@ -3182,7 +3182,7 @@ var SyntaxKind = /* @__PURE__ */ ((SyntaxKind4) => {
|
||||
SyntaxKind4[SyntaxKind4["WhileStatement"] = 248] = "WhileStatement";
|
||||
SyntaxKind4[SyntaxKind4["ForStatement"] = 249] = "ForStatement";
|
||||
SyntaxKind4[SyntaxKind4["ForInStatement"] = 250] = "ForInStatement";
|
||||
SyntaxKind4[SyntaxKind4["ForOfStatement"] = 251] = "ForOfStatement";
|
||||
SyntaxKind4[SyntaxKind4["ForOfStatement"] = 252] = "ForOfStatement";
|
||||
SyntaxKind4[SyntaxKind4["ContinueStatement"] = 252] = "ContinueStatement";
|
||||
SyntaxKind4[SyntaxKind4["BreakStatement"] = 253] = "BreakStatement";
|
||||
SyntaxKind4[SyntaxKind4["ReturnStatement"] = 254] = "ReturnStatement";
|
||||
@@ -12315,7 +12315,7 @@ function isIterationStatement(node, lookInLabeledStatements) {
|
||||
switch (node.kind) {
|
||||
case 249 /* ForStatement */:
|
||||
case 250 /* ForInStatement */:
|
||||
case 251 /* ForOfStatement */:
|
||||
case 252 /* ForOfStatement */:
|
||||
case 247 /* DoStatement */:
|
||||
case 248 /* WhileStatement */:
|
||||
return true;
|
||||
@@ -12337,7 +12337,7 @@ function isExternalModuleIndicator(result) {
|
||||
return isAnyImportOrReExport(result) || isExportAssignment(result) || hasSyntacticModifier(result, 32 /* Export */);
|
||||
}
|
||||
function isForInOrOfStatement(node) {
|
||||
return node.kind === 250 /* ForInStatement */ || node.kind === 251 /* ForOfStatement */;
|
||||
return node.kind === 250 /* ForInStatement */ || node.kind === 252 /* ForOfStatement */;
|
||||
}
|
||||
function isConciseBody(node) {
|
||||
return isBlock(node) || isExpression(node);
|
||||
@@ -12441,7 +12441,7 @@ function canHaveLocals(node) {
|
||||
case 181 /* ConstructSignature */:
|
||||
case 249 /* ForStatement */:
|
||||
case 250 /* ForInStatement */:
|
||||
case 251 /* ForOfStatement */:
|
||||
case 252 /* ForOfStatement */:
|
||||
case 263 /* FunctionDeclaration */:
|
||||
case 219 /* FunctionExpression */:
|
||||
case 185 /* FunctionType */:
|
||||
@@ -12471,7 +12471,7 @@ function isDeclarationStatementKind(kind) {
|
||||
return kind === 263 /* FunctionDeclaration */ || kind === 283 /* MissingDeclaration */ || kind === 264 /* ClassDeclaration */ || kind === 265 /* InterfaceDeclaration */ || kind === 266 /* TypeAliasDeclaration */ || kind === 267 /* EnumDeclaration */ || kind === 268 /* ModuleDeclaration */ || kind === 273 /* ImportDeclaration */ || kind === 272 /* ImportEqualsDeclaration */ || kind === 279 /* ExportDeclaration */ || kind === 278 /* ExportAssignment */ || kind === 271 /* NamespaceExportDeclaration */;
|
||||
}
|
||||
function isStatementKindButNotDeclarationKind(kind) {
|
||||
return kind === 253 /* BreakStatement */ || kind === 252 /* ContinueStatement */ || kind === 260 /* DebuggerStatement */ || kind === 247 /* DoStatement */ || kind === 245 /* ExpressionStatement */ || kind === 243 /* EmptyStatement */ || kind === 250 /* ForInStatement */ || kind === 251 /* ForOfStatement */ || kind === 249 /* ForStatement */ || kind === 246 /* IfStatement */ || kind === 257 /* LabeledStatement */ || kind === 254 /* ReturnStatement */ || kind === 256 /* SwitchStatement */ || kind === 258 /* ThrowStatement */ || kind === 259 /* TryStatement */ || kind === 244 /* VariableStatement */ || kind === 248 /* WhileStatement */ || kind === 255 /* WithStatement */ || kind === 354 /* NotEmittedStatement */;
|
||||
return kind === 253 /* BreakStatement */ || kind === 252 /* ContinueStatement */ || kind === 260 /* DebuggerStatement */ || kind === 247 /* DoStatement */ || kind === 245 /* ExpressionStatement */ || kind === 243 /* EmptyStatement */ || kind === 250 /* ForInStatement */ || kind === 252 /* ForOfStatement */ || kind === 249 /* ForStatement */ || kind === 246 /* IfStatement */ || kind === 257 /* LabeledStatement */ || kind === 254 /* ReturnStatement */ || kind === 256 /* SwitchStatement */ || kind === 258 /* ThrowStatement */ || kind === 259 /* TryStatement */ || kind === 244 /* VariableStatement */ || kind === 248 /* WhileStatement */ || kind === 255 /* WithStatement */ || kind === 354 /* NotEmittedStatement */;
|
||||
}
|
||||
function isDeclaration(node) {
|
||||
if (node.kind === 169 /* TypeParameter */) {
|
||||
@@ -12897,7 +12897,7 @@ function isStatementWithLocals(node) {
|
||||
case 270 /* CaseBlock */:
|
||||
case 249 /* ForStatement */:
|
||||
case 250 /* ForInStatement */:
|
||||
case 251 /* ForOfStatement */:
|
||||
case 252 /* ForOfStatement */:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -13754,7 +13754,7 @@ function isBlockScope(node, parentNode) {
|
||||
case 268 /* ModuleDeclaration */:
|
||||
case 249 /* ForStatement */:
|
||||
case 250 /* ForInStatement */:
|
||||
case 251 /* ForOfStatement */:
|
||||
case 252 /* ForOfStatement */:
|
||||
case 177 /* Constructor */:
|
||||
case 175 /* MethodDeclaration */:
|
||||
case 178 /* GetAccessor */:
|
||||
@@ -14248,7 +14248,7 @@ function forEachReturnStatement(body, visitor) {
|
||||
case 248 /* WhileStatement */:
|
||||
case 249 /* ForStatement */:
|
||||
case 250 /* ForInStatement */:
|
||||
case 251 /* ForOfStatement */:
|
||||
case 252 /* ForOfStatement */:
|
||||
case 255 /* WithStatement */:
|
||||
case 256 /* SwitchStatement */:
|
||||
case 297 /* CaseClause */:
|
||||
@@ -14791,7 +14791,7 @@ function isInExpressionContext(node) {
|
||||
const forStatement = parent;
|
||||
return forStatement.initializer === node && forStatement.initializer.kind !== 262 /* VariableDeclarationList */ || forStatement.condition === node || forStatement.incrementor === node;
|
||||
case 250 /* ForInStatement */:
|
||||
case 251 /* ForOfStatement */:
|
||||
case 252 /* ForOfStatement */:
|
||||
const forInOrOfStatement = parent;
|
||||
return forInOrOfStatement.initializer === node && forInOrOfStatement.initializer.kind !== 262 /* VariableDeclarationList */ || forInOrOfStatement.expression === node;
|
||||
case 217 /* TypeAssertionExpression */:
|
||||
@@ -15325,7 +15325,7 @@ function canHaveJSDoc(node) {
|
||||
case 282 /* ExportSpecifier */:
|
||||
case 245 /* ExpressionStatement */:
|
||||
case 250 /* ForInStatement */:
|
||||
case 251 /* ForOfStatement */:
|
||||
case 252 /* ForOfStatement */:
|
||||
case 249 /* ForStatement */:
|
||||
case 263 /* FunctionDeclaration */:
|
||||
case 219 /* FunctionExpression */:
|
||||
@@ -15489,7 +15489,7 @@ function getAssignmentTarget(node) {
|
||||
const unaryOperator = unaryExpression.operator;
|
||||
return unaryOperator === 46 /* PlusPlusToken */ || unaryOperator === 47 /* MinusMinusToken */ ? unaryExpression : void 0;
|
||||
case 250 /* ForInStatement */:
|
||||
case 251 /* ForOfStatement */:
|
||||
case 252 /* ForOfStatement */:
|
||||
const forInOrOfStatement = parent;
|
||||
return forInOrOfStatement.initializer === node ? forInOrOfStatement : void 0;
|
||||
case 218 /* ParenthesizedExpression */:
|
||||
@@ -15532,7 +15532,7 @@ function getAssignmentTargetKind(node) {
|
||||
case 226 /* PostfixUnaryExpression */:
|
||||
return 2 /* Compound */;
|
||||
case 250 /* ForInStatement */:
|
||||
case 251 /* ForOfStatement */:
|
||||
case 252 /* ForOfStatement */:
|
||||
return 1 /* Definite */;
|
||||
}
|
||||
}
|
||||
@@ -15564,7 +15564,7 @@ function isNodeWithPossibleHoistedDeclaration(node) {
|
||||
case 257 /* LabeledStatement */:
|
||||
case 249 /* ForStatement */:
|
||||
case 250 /* ForInStatement */:
|
||||
case 251 /* ForOfStatement */:
|
||||
case 252 /* ForOfStatement */:
|
||||
case 247 /* DoStatement */:
|
||||
case 248 /* WhileStatement */:
|
||||
case 259 /* TryStatement */:
|
||||
@@ -17424,7 +17424,7 @@ function accessKind(node) {
|
||||
case 210 /* ArrayLiteralExpression */:
|
||||
return accessKind(parent);
|
||||
case 250 /* ForInStatement */:
|
||||
case 251 /* ForOfStatement */:
|
||||
case 252 /* ForOfStatement */:
|
||||
return node === parent.initializer ? 1 /* Write */ : 0 /* Read */;
|
||||
default:
|
||||
return 0 /* Read */;
|
||||
@@ -23083,7 +23083,7 @@ function createNodeFactory(flags, baseFactory2) {
|
||||
return node.initializer !== initializer || node.expression !== expression || node.statement !== statement ? update(createForInStatement(initializer, expression, statement), node) : node;
|
||||
}
|
||||
function createForOfStatement(awaitModifier, initializer, expression, statement) {
|
||||
const node = createBaseNode(251 /* ForOfStatement */);
|
||||
const node = createBaseNode(252 /* ForOfStatement */);
|
||||
node.awaitModifier = awaitModifier;
|
||||
node.initializer = initializer;
|
||||
node.expression = parenthesizerRules().parenthesizeExpressionForDisallowedComma(expression);
|
||||
@@ -26810,7 +26810,7 @@ function isForInStatement(node) {
|
||||
return node.kind === 250 /* ForInStatement */;
|
||||
}
|
||||
function isForOfStatement(node) {
|
||||
return node.kind === 251 /* ForOfStatement */;
|
||||
return node.kind === 252 /* ForOfStatement */;
|
||||
}
|
||||
function isReturnStatement(node) {
|
||||
return node.kind === 254 /* ReturnStatement */;
|
||||
@@ -28447,7 +28447,7 @@ var forEachChildTable = {
|
||||
[250 /* ForInStatement */]: function forEachChildInForInStatement(node, cbNode, _cbNodes) {
|
||||
return visitNode2(cbNode, node.initializer) || visitNode2(cbNode, node.expression) || visitNode2(cbNode, node.statement);
|
||||
},
|
||||
[251 /* ForOfStatement */]: function forEachChildInForOfStatement(node, cbNode, _cbNodes) {
|
||||
[252 /* ForOfStatement */]: function forEachChildInForOfStatement(node, cbNode, _cbNodes) {
|
||||
return visitNode2(cbNode, node.awaitModifier) || visitNode2(cbNode, node.initializer) || visitNode2(cbNode, node.expression) || visitNode2(cbNode, node.statement);
|
||||
},
|
||||
[252 /* ContinueStatement */]: forEachChildInContinueOrBreakStatement,
|
||||
@@ -30220,7 +30220,7 @@ var Parser;
|
||||
case 253 /* BreakStatement */:
|
||||
case 252 /* ContinueStatement */:
|
||||
case 250 /* ForInStatement */:
|
||||
case 251 /* ForOfStatement */:
|
||||
case 252 /* ForOfStatement */:
|
||||
case 249 /* ForStatement */:
|
||||
case 248 /* WhileStatement */:
|
||||
case 255 /* WithStatement */:
|
||||
@@ -42754,7 +42754,7 @@ function createBinder() {
|
||||
bindForStatement(node);
|
||||
break;
|
||||
case 250 /* ForInStatement */:
|
||||
case 251 /* ForOfStatement */:
|
||||
case 252 /* ForOfStatement */:
|
||||
bindForInOrForOfStatement(node);
|
||||
break;
|
||||
case 246 /* IfStatement */:
|
||||
@@ -43144,7 +43144,7 @@ function createBinder() {
|
||||
bind(node.expression);
|
||||
addAntecedent(preLoopLabel, currentFlow);
|
||||
currentFlow = preLoopLabel;
|
||||
if (node.kind === 251 /* ForOfStatement */) {
|
||||
if (node.kind === 252 /* ForOfStatement */) {
|
||||
bind(node.awaitModifier);
|
||||
}
|
||||
addAntecedent(postLoopLabel, currentFlow);
|
||||
@@ -45137,7 +45137,7 @@ function getContainerFlags(node) {
|
||||
case 300 /* CatchClause */:
|
||||
case 249 /* ForStatement */:
|
||||
case 250 /* ForInStatement */:
|
||||
case 251 /* ForOfStatement */:
|
||||
case 252 /* ForOfStatement */:
|
||||
case 270 /* CaseBlock */:
|
||||
return 2 /* IsBlockScopedContainer */ | 32 /* HasLocals */;
|
||||
case 242 /* Block */:
|
||||
@@ -47938,7 +47938,7 @@ function createTypeChecker(host) {
|
||||
switch (declaration2.parent.parent.kind) {
|
||||
case 244 /* VariableStatement */:
|
||||
case 249 /* ForStatement */:
|
||||
case 251 /* ForOfStatement */:
|
||||
case 252 /* ForOfStatement */:
|
||||
if (isSameScopeDescendentOf(usage2, declaration2, declContainer)) {
|
||||
return true;
|
||||
}
|
||||
@@ -55950,7 +55950,7 @@ function createTypeChecker(host) {
|
||||
)));
|
||||
return indexType.flags & (262144 /* TypeParameter */ | 4194304 /* Index */) ? getExtractStringType(indexType) : stringType;
|
||||
}
|
||||
if (isVariableDeclaration(declaration) && declaration.parent.parent.kind === 251 /* ForOfStatement */) {
|
||||
if (isVariableDeclaration(declaration) && declaration.parent.parent.kind === 252 /* ForOfStatement */) {
|
||||
const forOfStatement = declaration.parent.parent;
|
||||
return checkRightHandSideOfForOf(forOfStatement) || anyType;
|
||||
}
|
||||
@@ -69719,7 +69719,7 @@ function createTypeChecker(host) {
|
||||
return isDestructuringDefaultAssignment ? getTypeWithDefault(getAssignedType(node), node.right) : getTypeOfExpression(node.right);
|
||||
}
|
||||
function isDestructuringAssignmentTarget(parent) {
|
||||
return parent.parent.kind === 227 /* BinaryExpression */ && parent.parent.left === parent || parent.parent.kind === 251 /* ForOfStatement */ && parent.parent.initializer === parent;
|
||||
return parent.parent.kind === 227 /* BinaryExpression */ && parent.parent.left === parent || parent.parent.kind === 252 /* ForOfStatement */ && parent.parent.initializer === parent;
|
||||
}
|
||||
function getAssignedTypeOfArrayLiteralElement(node, element) {
|
||||
return getTypeOfDestructuredArrayElement(getAssignedType(node), node.elements.indexOf(element));
|
||||
@@ -69738,7 +69738,7 @@ function createTypeChecker(host) {
|
||||
switch (parent.kind) {
|
||||
case 250 /* ForInStatement */:
|
||||
return stringType;
|
||||
case 251 /* ForOfStatement */:
|
||||
case 252 /* ForOfStatement */:
|
||||
return checkRightHandSideOfForOf(parent) || errorType;
|
||||
case 227 /* BinaryExpression */:
|
||||
return getAssignedTypeOfBinaryExpression(parent);
|
||||
@@ -69772,7 +69772,7 @@ function createTypeChecker(host) {
|
||||
if (node.parent.parent.kind === 250 /* ForInStatement */) {
|
||||
return stringType;
|
||||
}
|
||||
if (node.parent.parent.kind === 251 /* ForOfStatement */) {
|
||||
if (node.parent.parent.kind === 252 /* ForOfStatement */) {
|
||||
return checkRightHandSideOfForOf(node.parent.parent) || errorType;
|
||||
}
|
||||
return errorType;
|
||||
@@ -70010,7 +70010,7 @@ function createTypeChecker(host) {
|
||||
if (isDeclarationWithExplicitTypeAnnotation(declaration)) {
|
||||
return getTypeOfSymbol(symbol);
|
||||
}
|
||||
if (isVariableDeclaration(declaration) && declaration.parent.parent.kind === 251 /* ForOfStatement */) {
|
||||
if (isVariableDeclaration(declaration) && declaration.parent.parent.kind === 252 /* ForOfStatement */) {
|
||||
const statement = declaration.parent.parent;
|
||||
const expressionType = getTypeOfDottedName(
|
||||
statement.expression,
|
||||
@@ -71449,7 +71449,7 @@ function createTypeChecker(host) {
|
||||
case 248 /* WhileStatement */:
|
||||
case 249 /* ForStatement */:
|
||||
case 250 /* ForInStatement */:
|
||||
case 251 /* ForOfStatement */:
|
||||
case 252 /* ForOfStatement */:
|
||||
case 255 /* WithStatement */:
|
||||
case 256 /* SwitchStatement */:
|
||||
case 259 /* TryStatement */:
|
||||
@@ -82766,7 +82766,7 @@ function createTypeChecker(host) {
|
||||
case 270 /* CaseBlock */:
|
||||
case 249 /* ForStatement */:
|
||||
case 250 /* ForInStatement */:
|
||||
case 251 /* ForOfStatement */:
|
||||
case 252 /* ForOfStatement */:
|
||||
checkUnusedLocalsAndParameters(node, addDiagnostic);
|
||||
break;
|
||||
case 177 /* Constructor */:
|
||||
@@ -86503,7 +86503,7 @@ function createTypeChecker(host) {
|
||||
return checkForStatement(node);
|
||||
case 250 /* ForInStatement */:
|
||||
return checkForInStatement(node);
|
||||
case 251 /* ForOfStatement */:
|
||||
case 252 /* ForOfStatement */:
|
||||
return checkForOfStatement(node);
|
||||
case 252 /* ContinueStatement */:
|
||||
case 253 /* BreakStatement */:
|
||||
@@ -87497,7 +87497,7 @@ function createTypeChecker(host) {
|
||||
}
|
||||
function getTypeOfAssignmentPattern(expr) {
|
||||
Debug.assert(expr.kind === 211 /* ObjectLiteralExpression */ || expr.kind === 210 /* ArrayLiteralExpression */);
|
||||
if (expr.parent.kind === 251 /* ForOfStatement */) {
|
||||
if (expr.parent.kind === 252 /* ForOfStatement */) {
|
||||
const iteratedType = checkRightHandSideOfForOf(expr.parent);
|
||||
return checkDestructuringAssignment(expr, iteratedType || errorType);
|
||||
}
|
||||
@@ -89489,7 +89489,7 @@ function createTypeChecker(host) {
|
||||
if (checkGrammarStatementInAmbientContext(forInOrOfStatement)) {
|
||||
return true;
|
||||
}
|
||||
if (forInOrOfStatement.kind === 251 /* ForOfStatement */ && forInOrOfStatement.awaitModifier) {
|
||||
if (forInOrOfStatement.kind === 252 /* ForOfStatement */ && forInOrOfStatement.awaitModifier) {
|
||||
if (!(forInOrOfStatement.flags & 65536 /* AwaitContext */)) {
|
||||
const sourceFile = getSourceFileOfNode(forInOrOfStatement);
|
||||
if (isInTopLevelContext(forInOrOfStatement)) {
|
||||
@@ -89798,7 +89798,7 @@ function createTypeChecker(host) {
|
||||
return grammarErrorOnNode(node, Diagnostics._0_declarations_may_not_have_binding_patterns, "using");
|
||||
}
|
||||
}
|
||||
if (node.parent.parent.kind !== 250 /* ForInStatement */ && node.parent.parent.kind !== 251 /* ForOfStatement */) {
|
||||
if (node.parent.parent.kind !== 250 /* ForInStatement */ && node.parent.parent.kind !== 252 /* ForOfStatement */) {
|
||||
if (nodeFlags & 33554432 /* Ambient */) {
|
||||
checkAmbientInitializer(node);
|
||||
} else if (!node.initializer) {
|
||||
@@ -89890,7 +89890,7 @@ function createTypeChecker(host) {
|
||||
case 255 /* WithStatement */:
|
||||
case 249 /* ForStatement */:
|
||||
case 250 /* ForInStatement */:
|
||||
case 251 /* ForOfStatement */:
|
||||
case 252 /* ForOfStatement */:
|
||||
return false;
|
||||
case 257 /* LabeledStatement */:
|
||||
return allowBlockDeclarations(parent.parent);
|
||||
@@ -91350,7 +91350,7 @@ var visitEachChildTable = {
|
||||
visitIterationBody(node.statement, visitor, context, nodeVisitor)
|
||||
);
|
||||
},
|
||||
[251 /* ForOfStatement */]: function visitEachChildOfForOfStatement(node, visitor, context, _nodesVisitor, nodeVisitor, tokenVisitor) {
|
||||
[252 /* ForOfStatement */]: function visitEachChildOfForOfStatement(node, visitor, context, _nodesVisitor, nodeVisitor, tokenVisitor) {
|
||||
return context.factory.updateForOfStatement(
|
||||
node,
|
||||
tokenVisitor ? nodeVisitor(node.awaitModifier, tokenVisitor, isAwaitKeyword) : node.awaitModifier,
|
||||
@@ -100339,7 +100339,7 @@ function transformES2017(context) {
|
||||
return visitForStatementInAsyncBody(node);
|
||||
case 250 /* ForInStatement */:
|
||||
return visitForInStatementInAsyncBody(node);
|
||||
case 251 /* ForOfStatement */:
|
||||
case 252 /* ForOfStatement */:
|
||||
return visitForOfStatementInAsyncBody(node);
|
||||
case 300 /* CatchClause */:
|
||||
return visitCatchClauseInAsyncBody(node);
|
||||
@@ -101193,7 +101193,7 @@ function transformES2018(context) {
|
||||
0 /* IterationStatementExcludes */,
|
||||
2 /* IterationStatementIncludes */
|
||||
);
|
||||
case 251 /* ForOfStatement */:
|
||||
case 252 /* ForOfStatement */:
|
||||
return visitForOfStatement(
|
||||
node,
|
||||
/*outermostLabeledStatement*/
|
||||
@@ -101364,7 +101364,7 @@ function transformES2018(context) {
|
||||
function visitLabeledStatement(node) {
|
||||
if (enclosingFunctionFlags & 2 /* Async */) {
|
||||
const statement = unwrapInnermostStatementOfLabel(node);
|
||||
if (statement.kind === 251 /* ForOfStatement */ && statement.awaitModifier) {
|
||||
if (statement.kind === 252 /* ForOfStatement */ && statement.awaitModifier) {
|
||||
return visitForOfStatement(statement, node);
|
||||
}
|
||||
return factory2.restoreEnclosingLabel(visitNode(statement, visitor, isStatement, factory2.liftToBlock), node);
|
||||
@@ -102705,7 +102705,7 @@ function transformESNext(context) {
|
||||
return visitBlock(node);
|
||||
case 249 /* ForStatement */:
|
||||
return visitForStatement(node);
|
||||
case 251 /* ForOfStatement */:
|
||||
case 252 /* ForOfStatement */:
|
||||
return visitForOfStatement(node);
|
||||
case 256 /* SwitchStatement */:
|
||||
return visitSwitchStatement(node);
|
||||
@@ -103943,7 +103943,7 @@ var entities = new Map(Object.entries({
|
||||
oslash: 248,
|
||||
ugrave: 249,
|
||||
uacute: 250,
|
||||
ucirc: 251,
|
||||
ucirc: 252,
|
||||
uuml: 252,
|
||||
yacute: 253,
|
||||
thorn: 254,
|
||||
@@ -104369,7 +104369,7 @@ function transformES2015(context) {
|
||||
/*outermostLabeledStatement*/
|
||||
void 0
|
||||
);
|
||||
case 251 /* ForOfStatement */:
|
||||
case 252 /* ForOfStatement */:
|
||||
return visitForOfStatement(
|
||||
node,
|
||||
/*outermostLabeledStatement*/
|
||||
@@ -105979,7 +105979,7 @@ function transformES2015(context) {
|
||||
return visitForStatement(node, outermostLabeledStatement);
|
||||
case 250 /* ForInStatement */:
|
||||
return visitForInStatement(node, outermostLabeledStatement);
|
||||
case 251 /* ForOfStatement */:
|
||||
case 252 /* ForOfStatement */:
|
||||
return visitForOfStatement(node, outermostLabeledStatement);
|
||||
}
|
||||
}
|
||||
@@ -106453,7 +106453,7 @@ function transformES2015(context) {
|
||||
return convertForStatement(node, initializerFunction, convertedLoopBody);
|
||||
case 250 /* ForInStatement */:
|
||||
return convertForInStatement(node, convertedLoopBody);
|
||||
case 251 /* ForOfStatement */:
|
||||
case 252 /* ForOfStatement */:
|
||||
return convertForOfStatement(node, convertedLoopBody);
|
||||
case 247 /* DoStatement */:
|
||||
return convertDoStatement(node, convertedLoopBody);
|
||||
@@ -106511,7 +106511,7 @@ function transformES2015(context) {
|
||||
switch (node.kind) {
|
||||
case 249 /* ForStatement */:
|
||||
case 250 /* ForInStatement */:
|
||||
case 251 /* ForOfStatement */:
|
||||
case 252 /* ForOfStatement */:
|
||||
const initializer = node.initializer;
|
||||
if (initializer && initializer.kind === 262 /* VariableDeclarationList */) {
|
||||
loopInitializer = initializer;
|
||||
@@ -110048,7 +110048,7 @@ function transformModule(context) {
|
||||
);
|
||||
case 250 /* ForInStatement */:
|
||||
return visitForInStatement(node);
|
||||
case 251 /* ForOfStatement */:
|
||||
case 252 /* ForOfStatement */:
|
||||
return visitForOfStatement(node);
|
||||
case 247 /* DoStatement */:
|
||||
return visitDoStatement(node);
|
||||
@@ -112320,7 +112320,7 @@ function transformSystemModule(context) {
|
||||
);
|
||||
case 250 /* ForInStatement */:
|
||||
return visitForInStatement(node);
|
||||
case 251 /* ForOfStatement */:
|
||||
case 252 /* ForOfStatement */:
|
||||
return visitForOfStatement(node);
|
||||
case 247 /* DoStatement */:
|
||||
return visitDoStatement(node);
|
||||
@@ -116842,7 +116842,7 @@ function createPrinter(printerOptions = {}, handlers = {}) {
|
||||
return emitForStatement(node);
|
||||
case 250 /* ForInStatement */:
|
||||
return emitForInStatement(node);
|
||||
case 251 /* ForOfStatement */:
|
||||
case 252 /* ForOfStatement */:
|
||||
return emitForOfStatement(node);
|
||||
case 252 /* ContinueStatement */:
|
||||
return emitContinueStatement(node);
|
||||
@@ -119983,7 +119983,7 @@ function createPrinter(printerOptions = {}, handlers = {}) {
|
||||
generateNames(node.elseStatement);
|
||||
break;
|
||||
case 249 /* ForStatement */:
|
||||
case 251 /* ForOfStatement */:
|
||||
case 252 /* ForOfStatement */:
|
||||
case 250 /* ForInStatement */:
|
||||
generateNames(node.initializer);
|
||||
generateNames(node.statement);
|
||||
|
||||
2
valdi/node_modules/typescript/lib/typescript.d.ts
generated
vendored
2
valdi/node_modules/typescript/lib/typescript.d.ts
generated
vendored
@@ -3927,7 +3927,7 @@ declare namespace ts {
|
||||
WhileStatement = 248,
|
||||
ForStatement = 249,
|
||||
ForInStatement = 250,
|
||||
ForOfStatement = 251,
|
||||
ForOfStatement = 252,
|
||||
ContinueStatement = 252,
|
||||
BreakStatement = 253,
|
||||
ReturnStatement = 254,
|
||||
|
||||
136
valdi/node_modules/typescript/lib/typescript.js
generated
vendored
136
valdi/node_modules/typescript/lib/typescript.js
generated
vendored
@@ -5771,7 +5771,7 @@ var SyntaxKind = /* @__PURE__ */ ((SyntaxKind5) => {
|
||||
SyntaxKind5[SyntaxKind5["WhileStatement"] = 248] = "WhileStatement";
|
||||
SyntaxKind5[SyntaxKind5["ForStatement"] = 249] = "ForStatement";
|
||||
SyntaxKind5[SyntaxKind5["ForInStatement"] = 250] = "ForInStatement";
|
||||
SyntaxKind5[SyntaxKind5["ForOfStatement"] = 251] = "ForOfStatement";
|
||||
SyntaxKind5[SyntaxKind5["ForOfStatement"] = 252] = "ForOfStatement";
|
||||
SyntaxKind5[SyntaxKind5["ContinueStatement"] = 252] = "ContinueStatement";
|
||||
SyntaxKind5[SyntaxKind5["BreakStatement"] = 253] = "BreakStatement";
|
||||
SyntaxKind5[SyntaxKind5["ReturnStatement"] = 254] = "ReturnStatement";
|
||||
@@ -15881,7 +15881,7 @@ function isIterationStatement(node, lookInLabeledStatements) {
|
||||
switch (node.kind) {
|
||||
case 249 /* ForStatement */:
|
||||
case 250 /* ForInStatement */:
|
||||
case 251 /* ForOfStatement */:
|
||||
case 252 /* ForOfStatement */:
|
||||
case 247 /* DoStatement */:
|
||||
case 248 /* WhileStatement */:
|
||||
return true;
|
||||
@@ -15903,7 +15903,7 @@ function isExternalModuleIndicator(result) {
|
||||
return isAnyImportOrReExport(result) || isExportAssignment(result) || hasSyntacticModifier(result, 32 /* Export */);
|
||||
}
|
||||
function isForInOrOfStatement(node) {
|
||||
return node.kind === 250 /* ForInStatement */ || node.kind === 251 /* ForOfStatement */;
|
||||
return node.kind === 250 /* ForInStatement */ || node.kind === 252 /* ForOfStatement */;
|
||||
}
|
||||
function isConciseBody(node) {
|
||||
return isBlock(node) || isExpression(node);
|
||||
@@ -16018,7 +16018,7 @@ function canHaveLocals(node) {
|
||||
case 181 /* ConstructSignature */:
|
||||
case 249 /* ForStatement */:
|
||||
case 250 /* ForInStatement */:
|
||||
case 251 /* ForOfStatement */:
|
||||
case 252 /* ForOfStatement */:
|
||||
case 263 /* FunctionDeclaration */:
|
||||
case 219 /* FunctionExpression */:
|
||||
case 185 /* FunctionType */:
|
||||
@@ -16048,7 +16048,7 @@ function isDeclarationStatementKind(kind) {
|
||||
return kind === 263 /* FunctionDeclaration */ || kind === 283 /* MissingDeclaration */ || kind === 264 /* ClassDeclaration */ || kind === 265 /* InterfaceDeclaration */ || kind === 266 /* TypeAliasDeclaration */ || kind === 267 /* EnumDeclaration */ || kind === 268 /* ModuleDeclaration */ || kind === 273 /* ImportDeclaration */ || kind === 272 /* ImportEqualsDeclaration */ || kind === 279 /* ExportDeclaration */ || kind === 278 /* ExportAssignment */ || kind === 271 /* NamespaceExportDeclaration */;
|
||||
}
|
||||
function isStatementKindButNotDeclarationKind(kind) {
|
||||
return kind === 253 /* BreakStatement */ || kind === 252 /* ContinueStatement */ || kind === 260 /* DebuggerStatement */ || kind === 247 /* DoStatement */ || kind === 245 /* ExpressionStatement */ || kind === 243 /* EmptyStatement */ || kind === 250 /* ForInStatement */ || kind === 251 /* ForOfStatement */ || kind === 249 /* ForStatement */ || kind === 246 /* IfStatement */ || kind === 257 /* LabeledStatement */ || kind === 254 /* ReturnStatement */ || kind === 256 /* SwitchStatement */ || kind === 258 /* ThrowStatement */ || kind === 259 /* TryStatement */ || kind === 244 /* VariableStatement */ || kind === 248 /* WhileStatement */ || kind === 255 /* WithStatement */ || kind === 354 /* NotEmittedStatement */;
|
||||
return kind === 253 /* BreakStatement */ || kind === 252 /* ContinueStatement */ || kind === 260 /* DebuggerStatement */ || kind === 247 /* DoStatement */ || kind === 245 /* ExpressionStatement */ || kind === 243 /* EmptyStatement */ || kind === 250 /* ForInStatement */ || kind === 252 /* ForOfStatement */ || kind === 249 /* ForStatement */ || kind === 246 /* IfStatement */ || kind === 257 /* LabeledStatement */ || kind === 254 /* ReturnStatement */ || kind === 256 /* SwitchStatement */ || kind === 258 /* ThrowStatement */ || kind === 259 /* TryStatement */ || kind === 244 /* VariableStatement */ || kind === 248 /* WhileStatement */ || kind === 255 /* WithStatement */ || kind === 354 /* NotEmittedStatement */;
|
||||
}
|
||||
function isDeclaration(node) {
|
||||
if (node.kind === 169 /* TypeParameter */) {
|
||||
@@ -16490,7 +16490,7 @@ function isStatementWithLocals(node) {
|
||||
case 270 /* CaseBlock */:
|
||||
case 249 /* ForStatement */:
|
||||
case 250 /* ForInStatement */:
|
||||
case 251 /* ForOfStatement */:
|
||||
case 252 /* ForOfStatement */:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -17395,7 +17395,7 @@ function isBlockScope(node, parentNode) {
|
||||
case 268 /* ModuleDeclaration */:
|
||||
case 249 /* ForStatement */:
|
||||
case 250 /* ForInStatement */:
|
||||
case 251 /* ForOfStatement */:
|
||||
case 252 /* ForOfStatement */:
|
||||
case 177 /* Constructor */:
|
||||
case 175 /* MethodDeclaration */:
|
||||
case 178 /* GetAccessor */:
|
||||
@@ -17935,7 +17935,7 @@ function forEachReturnStatement(body, visitor) {
|
||||
case 248 /* WhileStatement */:
|
||||
case 249 /* ForStatement */:
|
||||
case 250 /* ForInStatement */:
|
||||
case 251 /* ForOfStatement */:
|
||||
case 252 /* ForOfStatement */:
|
||||
case 255 /* WithStatement */:
|
||||
case 256 /* SwitchStatement */:
|
||||
case 297 /* CaseClause */:
|
||||
@@ -18481,7 +18481,7 @@ function isInExpressionContext(node) {
|
||||
const forStatement = parent2;
|
||||
return forStatement.initializer === node && forStatement.initializer.kind !== 262 /* VariableDeclarationList */ || forStatement.condition === node || forStatement.incrementor === node;
|
||||
case 250 /* ForInStatement */:
|
||||
case 251 /* ForOfStatement */:
|
||||
case 252 /* ForOfStatement */:
|
||||
const forInOrOfStatement = parent2;
|
||||
return forInOrOfStatement.initializer === node && forInOrOfStatement.initializer.kind !== 262 /* VariableDeclarationList */ || forInOrOfStatement.expression === node;
|
||||
case 217 /* TypeAssertionExpression */:
|
||||
@@ -19051,7 +19051,7 @@ function canHaveJSDoc(node) {
|
||||
case 282 /* ExportSpecifier */:
|
||||
case 245 /* ExpressionStatement */:
|
||||
case 250 /* ForInStatement */:
|
||||
case 251 /* ForOfStatement */:
|
||||
case 252 /* ForOfStatement */:
|
||||
case 249 /* ForStatement */:
|
||||
case 263 /* FunctionDeclaration */:
|
||||
case 219 /* FunctionExpression */:
|
||||
@@ -19224,7 +19224,7 @@ function getAssignmentTarget(node) {
|
||||
const unaryOperator = unaryExpression.operator;
|
||||
return unaryOperator === 46 /* PlusPlusToken */ || unaryOperator === 47 /* MinusMinusToken */ ? unaryExpression : void 0;
|
||||
case 250 /* ForInStatement */:
|
||||
case 251 /* ForOfStatement */:
|
||||
case 252 /* ForOfStatement */:
|
||||
const forInOrOfStatement = parent2;
|
||||
return forInOrOfStatement.initializer === node ? forInOrOfStatement : void 0;
|
||||
case 218 /* ParenthesizedExpression */:
|
||||
@@ -19267,7 +19267,7 @@ function getAssignmentTargetKind(node) {
|
||||
case 226 /* PostfixUnaryExpression */:
|
||||
return 2 /* Compound */;
|
||||
case 250 /* ForInStatement */:
|
||||
case 251 /* ForOfStatement */:
|
||||
case 252 /* ForOfStatement */:
|
||||
return 1 /* Definite */;
|
||||
}
|
||||
}
|
||||
@@ -19299,7 +19299,7 @@ function isNodeWithPossibleHoistedDeclaration(node) {
|
||||
case 257 /* LabeledStatement */:
|
||||
case 249 /* ForStatement */:
|
||||
case 250 /* ForInStatement */:
|
||||
case 251 /* ForOfStatement */:
|
||||
case 252 /* ForOfStatement */:
|
||||
case 247 /* DoStatement */:
|
||||
case 248 /* WhileStatement */:
|
||||
case 259 /* TryStatement */:
|
||||
@@ -21316,7 +21316,7 @@ function accessKind(node) {
|
||||
case 210 /* ArrayLiteralExpression */:
|
||||
return accessKind(parent2);
|
||||
case 250 /* ForInStatement */:
|
||||
case 251 /* ForOfStatement */:
|
||||
case 252 /* ForOfStatement */:
|
||||
return node === parent2.initializer ? 1 /* Write */ : 0 /* Read */;
|
||||
default:
|
||||
return 0 /* Read */;
|
||||
@@ -23389,7 +23389,7 @@ function isSourceElement(node) {
|
||||
case 248 /* WhileStatement */:
|
||||
case 249 /* ForStatement */:
|
||||
case 250 /* ForInStatement */:
|
||||
case 251 /* ForOfStatement */:
|
||||
case 252 /* ForOfStatement */:
|
||||
case 252 /* ContinueStatement */:
|
||||
case 253 /* BreakStatement */:
|
||||
case 254 /* ReturnStatement */:
|
||||
@@ -27191,7 +27191,7 @@ function createNodeFactory(flags, baseFactory2) {
|
||||
return node.initializer !== initializer || node.expression !== expression || node.statement !== statement ? update(createForInStatement(initializer, expression, statement), node) : node;
|
||||
}
|
||||
function createForOfStatement(awaitModifier, initializer, expression, statement) {
|
||||
const node = createBaseNode(251 /* ForOfStatement */);
|
||||
const node = createBaseNode(252 /* ForOfStatement */);
|
||||
node.awaitModifier = awaitModifier;
|
||||
node.initializer = initializer;
|
||||
node.expression = parenthesizerRules().parenthesizeExpressionForDisallowedComma(expression);
|
||||
@@ -30992,7 +30992,7 @@ function isForInStatement(node) {
|
||||
return node.kind === 250 /* ForInStatement */;
|
||||
}
|
||||
function isForOfStatement(node) {
|
||||
return node.kind === 251 /* ForOfStatement */;
|
||||
return node.kind === 252 /* ForOfStatement */;
|
||||
}
|
||||
function isContinueStatement(node) {
|
||||
return node.kind === 252 /* ContinueStatement */;
|
||||
@@ -32693,7 +32693,7 @@ var forEachChildTable = {
|
||||
[250 /* ForInStatement */]: function forEachChildInForInStatement(node, cbNode, _cbNodes) {
|
||||
return visitNode2(cbNode, node.initializer) || visitNode2(cbNode, node.expression) || visitNode2(cbNode, node.statement);
|
||||
},
|
||||
[251 /* ForOfStatement */]: function forEachChildInForOfStatement(node, cbNode, _cbNodes) {
|
||||
[252 /* ForOfStatement */]: function forEachChildInForOfStatement(node, cbNode, _cbNodes) {
|
||||
return visitNode2(cbNode, node.awaitModifier) || visitNode2(cbNode, node.initializer) || visitNode2(cbNode, node.expression) || visitNode2(cbNode, node.statement);
|
||||
},
|
||||
[252 /* ContinueStatement */]: forEachChildInContinueOrBreakStatement,
|
||||
@@ -34481,7 +34481,7 @@ var Parser;
|
||||
case 253 /* BreakStatement */:
|
||||
case 252 /* ContinueStatement */:
|
||||
case 250 /* ForInStatement */:
|
||||
case 251 /* ForOfStatement */:
|
||||
case 252 /* ForOfStatement */:
|
||||
case 249 /* ForStatement */:
|
||||
case 248 /* WhileStatement */:
|
||||
case 255 /* WithStatement */:
|
||||
@@ -47265,7 +47265,7 @@ function createBinder() {
|
||||
bindForStatement(node);
|
||||
break;
|
||||
case 250 /* ForInStatement */:
|
||||
case 251 /* ForOfStatement */:
|
||||
case 252 /* ForOfStatement */:
|
||||
bindForInOrForOfStatement(node);
|
||||
break;
|
||||
case 246 /* IfStatement */:
|
||||
@@ -47655,7 +47655,7 @@ function createBinder() {
|
||||
bind(node.expression);
|
||||
addAntecedent(preLoopLabel, currentFlow);
|
||||
currentFlow = preLoopLabel;
|
||||
if (node.kind === 251 /* ForOfStatement */) {
|
||||
if (node.kind === 252 /* ForOfStatement */) {
|
||||
bind(node.awaitModifier);
|
||||
}
|
||||
addAntecedent(postLoopLabel, currentFlow);
|
||||
@@ -49648,7 +49648,7 @@ function getContainerFlags(node) {
|
||||
case 300 /* CatchClause */:
|
||||
case 249 /* ForStatement */:
|
||||
case 250 /* ForInStatement */:
|
||||
case 251 /* ForOfStatement */:
|
||||
case 252 /* ForOfStatement */:
|
||||
case 270 /* CaseBlock */:
|
||||
return 2 /* IsBlockScopedContainer */ | 32 /* HasLocals */;
|
||||
case 242 /* Block */:
|
||||
@@ -52549,7 +52549,7 @@ function createTypeChecker(host) {
|
||||
switch (declaration2.parent.parent.kind) {
|
||||
case 244 /* VariableStatement */:
|
||||
case 249 /* ForStatement */:
|
||||
case 251 /* ForOfStatement */:
|
||||
case 252 /* ForOfStatement */:
|
||||
if (isSameScopeDescendentOf(usage2, declaration2, declContainer)) {
|
||||
return true;
|
||||
}
|
||||
@@ -60561,7 +60561,7 @@ function createTypeChecker(host) {
|
||||
)));
|
||||
return indexType.flags & (262144 /* TypeParameter */ | 4194304 /* Index */) ? getExtractStringType(indexType) : stringType;
|
||||
}
|
||||
if (isVariableDeclaration(declaration) && declaration.parent.parent.kind === 251 /* ForOfStatement */) {
|
||||
if (isVariableDeclaration(declaration) && declaration.parent.parent.kind === 252 /* ForOfStatement */) {
|
||||
const forOfStatement = declaration.parent.parent;
|
||||
return checkRightHandSideOfForOf(forOfStatement) || anyType;
|
||||
}
|
||||
@@ -74330,7 +74330,7 @@ function createTypeChecker(host) {
|
||||
return isDestructuringDefaultAssignment ? getTypeWithDefault(getAssignedType(node), node.right) : getTypeOfExpression(node.right);
|
||||
}
|
||||
function isDestructuringAssignmentTarget(parent2) {
|
||||
return parent2.parent.kind === 227 /* BinaryExpression */ && parent2.parent.left === parent2 || parent2.parent.kind === 251 /* ForOfStatement */ && parent2.parent.initializer === parent2;
|
||||
return parent2.parent.kind === 227 /* BinaryExpression */ && parent2.parent.left === parent2 || parent2.parent.kind === 252 /* ForOfStatement */ && parent2.parent.initializer === parent2;
|
||||
}
|
||||
function getAssignedTypeOfArrayLiteralElement(node, element) {
|
||||
return getTypeOfDestructuredArrayElement(getAssignedType(node), node.elements.indexOf(element));
|
||||
@@ -74349,7 +74349,7 @@ function createTypeChecker(host) {
|
||||
switch (parent2.kind) {
|
||||
case 250 /* ForInStatement */:
|
||||
return stringType;
|
||||
case 251 /* ForOfStatement */:
|
||||
case 252 /* ForOfStatement */:
|
||||
return checkRightHandSideOfForOf(parent2) || errorType;
|
||||
case 227 /* BinaryExpression */:
|
||||
return getAssignedTypeOfBinaryExpression(parent2);
|
||||
@@ -74383,7 +74383,7 @@ function createTypeChecker(host) {
|
||||
if (node.parent.parent.kind === 250 /* ForInStatement */) {
|
||||
return stringType;
|
||||
}
|
||||
if (node.parent.parent.kind === 251 /* ForOfStatement */) {
|
||||
if (node.parent.parent.kind === 252 /* ForOfStatement */) {
|
||||
return checkRightHandSideOfForOf(node.parent.parent) || errorType;
|
||||
}
|
||||
return errorType;
|
||||
@@ -74621,7 +74621,7 @@ function createTypeChecker(host) {
|
||||
if (isDeclarationWithExplicitTypeAnnotation(declaration)) {
|
||||
return getTypeOfSymbol(symbol);
|
||||
}
|
||||
if (isVariableDeclaration(declaration) && declaration.parent.parent.kind === 251 /* ForOfStatement */) {
|
||||
if (isVariableDeclaration(declaration) && declaration.parent.parent.kind === 252 /* ForOfStatement */) {
|
||||
const statement = declaration.parent.parent;
|
||||
const expressionType = getTypeOfDottedName(
|
||||
statement.expression,
|
||||
@@ -76060,7 +76060,7 @@ function createTypeChecker(host) {
|
||||
case 248 /* WhileStatement */:
|
||||
case 249 /* ForStatement */:
|
||||
case 250 /* ForInStatement */:
|
||||
case 251 /* ForOfStatement */:
|
||||
case 252 /* ForOfStatement */:
|
||||
case 255 /* WithStatement */:
|
||||
case 256 /* SwitchStatement */:
|
||||
case 259 /* TryStatement */:
|
||||
@@ -87377,7 +87377,7 @@ function createTypeChecker(host) {
|
||||
case 270 /* CaseBlock */:
|
||||
case 249 /* ForStatement */:
|
||||
case 250 /* ForInStatement */:
|
||||
case 251 /* ForOfStatement */:
|
||||
case 252 /* ForOfStatement */:
|
||||
checkUnusedLocalsAndParameters(node, addDiagnostic);
|
||||
break;
|
||||
case 177 /* Constructor */:
|
||||
@@ -91114,7 +91114,7 @@ function createTypeChecker(host) {
|
||||
return checkForStatement(node);
|
||||
case 250 /* ForInStatement */:
|
||||
return checkForInStatement(node);
|
||||
case 251 /* ForOfStatement */:
|
||||
case 252 /* ForOfStatement */:
|
||||
return checkForOfStatement(node);
|
||||
case 252 /* ContinueStatement */:
|
||||
case 253 /* BreakStatement */:
|
||||
@@ -92108,7 +92108,7 @@ function createTypeChecker(host) {
|
||||
}
|
||||
function getTypeOfAssignmentPattern(expr) {
|
||||
Debug.assert(expr.kind === 211 /* ObjectLiteralExpression */ || expr.kind === 210 /* ArrayLiteralExpression */);
|
||||
if (expr.parent.kind === 251 /* ForOfStatement */) {
|
||||
if (expr.parent.kind === 252 /* ForOfStatement */) {
|
||||
const iteratedType = checkRightHandSideOfForOf(expr.parent);
|
||||
return checkDestructuringAssignment(expr, iteratedType || errorType);
|
||||
}
|
||||
@@ -94100,7 +94100,7 @@ function createTypeChecker(host) {
|
||||
if (checkGrammarStatementInAmbientContext(forInOrOfStatement)) {
|
||||
return true;
|
||||
}
|
||||
if (forInOrOfStatement.kind === 251 /* ForOfStatement */ && forInOrOfStatement.awaitModifier) {
|
||||
if (forInOrOfStatement.kind === 252 /* ForOfStatement */ && forInOrOfStatement.awaitModifier) {
|
||||
if (!(forInOrOfStatement.flags & 65536 /* AwaitContext */)) {
|
||||
const sourceFile = getSourceFileOfNode(forInOrOfStatement);
|
||||
if (isInTopLevelContext(forInOrOfStatement)) {
|
||||
@@ -94409,7 +94409,7 @@ function createTypeChecker(host) {
|
||||
return grammarErrorOnNode(node, Diagnostics._0_declarations_may_not_have_binding_patterns, "using");
|
||||
}
|
||||
}
|
||||
if (node.parent.parent.kind !== 250 /* ForInStatement */ && node.parent.parent.kind !== 251 /* ForOfStatement */) {
|
||||
if (node.parent.parent.kind !== 250 /* ForInStatement */ && node.parent.parent.kind !== 252 /* ForOfStatement */) {
|
||||
if (nodeFlags & 33554432 /* Ambient */) {
|
||||
checkAmbientInitializer(node);
|
||||
} else if (!node.initializer) {
|
||||
@@ -94501,7 +94501,7 @@ function createTypeChecker(host) {
|
||||
case 255 /* WithStatement */:
|
||||
case 249 /* ForStatement */:
|
||||
case 250 /* ForInStatement */:
|
||||
case 251 /* ForOfStatement */:
|
||||
case 252 /* ForOfStatement */:
|
||||
return false;
|
||||
case 257 /* LabeledStatement */:
|
||||
return allowBlockDeclarations(parent2.parent);
|
||||
@@ -95961,7 +95961,7 @@ var visitEachChildTable = {
|
||||
visitIterationBody(node.statement, visitor, context, nodeVisitor)
|
||||
);
|
||||
},
|
||||
[251 /* ForOfStatement */]: function visitEachChildOfForOfStatement(node, visitor, context, _nodesVisitor, nodeVisitor, tokenVisitor) {
|
||||
[252 /* ForOfStatement */]: function visitEachChildOfForOfStatement(node, visitor, context, _nodesVisitor, nodeVisitor, tokenVisitor) {
|
||||
return context.factory.updateForOfStatement(
|
||||
node,
|
||||
tokenVisitor ? nodeVisitor(node.awaitModifier, tokenVisitor, isAwaitKeyword) : node.awaitModifier,
|
||||
@@ -105132,7 +105132,7 @@ function transformES2017(context) {
|
||||
return visitForStatementInAsyncBody(node);
|
||||
case 250 /* ForInStatement */:
|
||||
return visitForInStatementInAsyncBody(node);
|
||||
case 251 /* ForOfStatement */:
|
||||
case 252 /* ForOfStatement */:
|
||||
return visitForOfStatementInAsyncBody(node);
|
||||
case 300 /* CatchClause */:
|
||||
return visitCatchClauseInAsyncBody(node);
|
||||
@@ -105986,7 +105986,7 @@ function transformES2018(context) {
|
||||
0 /* IterationStatementExcludes */,
|
||||
2 /* IterationStatementIncludes */
|
||||
);
|
||||
case 251 /* ForOfStatement */:
|
||||
case 252 /* ForOfStatement */:
|
||||
return visitForOfStatement(
|
||||
node,
|
||||
/*outermostLabeledStatement*/
|
||||
@@ -106157,7 +106157,7 @@ function transformES2018(context) {
|
||||
function visitLabeledStatement(node) {
|
||||
if (enclosingFunctionFlags & 2 /* Async */) {
|
||||
const statement = unwrapInnermostStatementOfLabel(node);
|
||||
if (statement.kind === 251 /* ForOfStatement */ && statement.awaitModifier) {
|
||||
if (statement.kind === 252 /* ForOfStatement */ && statement.awaitModifier) {
|
||||
return visitForOfStatement(statement, node);
|
||||
}
|
||||
return factory2.restoreEnclosingLabel(visitNode(statement, visitor, isStatement, factory2.liftToBlock), node);
|
||||
@@ -107498,7 +107498,7 @@ function transformESNext(context) {
|
||||
return visitBlock(node);
|
||||
case 249 /* ForStatement */:
|
||||
return visitForStatement(node);
|
||||
case 251 /* ForOfStatement */:
|
||||
case 252 /* ForOfStatement */:
|
||||
return visitForOfStatement(node);
|
||||
case 256 /* SwitchStatement */:
|
||||
return visitSwitchStatement(node);
|
||||
@@ -108736,7 +108736,7 @@ var entities = new Map(Object.entries({
|
||||
oslash: 248,
|
||||
ugrave: 249,
|
||||
uacute: 250,
|
||||
ucirc: 251,
|
||||
ucirc: 252,
|
||||
uuml: 252,
|
||||
yacute: 253,
|
||||
thorn: 254,
|
||||
@@ -109162,7 +109162,7 @@ function transformES2015(context) {
|
||||
/*outermostLabeledStatement*/
|
||||
void 0
|
||||
);
|
||||
case 251 /* ForOfStatement */:
|
||||
case 252 /* ForOfStatement */:
|
||||
return visitForOfStatement(
|
||||
node,
|
||||
/*outermostLabeledStatement*/
|
||||
@@ -110772,7 +110772,7 @@ function transformES2015(context) {
|
||||
return visitForStatement(node, outermostLabeledStatement);
|
||||
case 250 /* ForInStatement */:
|
||||
return visitForInStatement(node, outermostLabeledStatement);
|
||||
case 251 /* ForOfStatement */:
|
||||
case 252 /* ForOfStatement */:
|
||||
return visitForOfStatement(node, outermostLabeledStatement);
|
||||
}
|
||||
}
|
||||
@@ -111246,7 +111246,7 @@ function transformES2015(context) {
|
||||
return convertForStatement(node, initializerFunction, convertedLoopBody);
|
||||
case 250 /* ForInStatement */:
|
||||
return convertForInStatement(node, convertedLoopBody);
|
||||
case 251 /* ForOfStatement */:
|
||||
case 252 /* ForOfStatement */:
|
||||
return convertForOfStatement(node, convertedLoopBody);
|
||||
case 247 /* DoStatement */:
|
||||
return convertDoStatement(node, convertedLoopBody);
|
||||
@@ -111304,7 +111304,7 @@ function transformES2015(context) {
|
||||
switch (node.kind) {
|
||||
case 249 /* ForStatement */:
|
||||
case 250 /* ForInStatement */:
|
||||
case 251 /* ForOfStatement */:
|
||||
case 252 /* ForOfStatement */:
|
||||
const initializer = node.initializer;
|
||||
if (initializer && initializer.kind === 262 /* VariableDeclarationList */) {
|
||||
loopInitializer = initializer;
|
||||
@@ -114841,7 +114841,7 @@ function transformModule(context) {
|
||||
);
|
||||
case 250 /* ForInStatement */:
|
||||
return visitForInStatement(node);
|
||||
case 251 /* ForOfStatement */:
|
||||
case 252 /* ForOfStatement */:
|
||||
return visitForOfStatement(node);
|
||||
case 247 /* DoStatement */:
|
||||
return visitDoStatement(node);
|
||||
@@ -117113,7 +117113,7 @@ function transformSystemModule(context) {
|
||||
);
|
||||
case 250 /* ForInStatement */:
|
||||
return visitForInStatement(node);
|
||||
case 251 /* ForOfStatement */:
|
||||
case 252 /* ForOfStatement */:
|
||||
return visitForOfStatement(node);
|
||||
case 247 /* DoStatement */:
|
||||
return visitDoStatement(node);
|
||||
@@ -121646,7 +121646,7 @@ function createPrinter(printerOptions = {}, handlers = {}) {
|
||||
return emitForStatement(node);
|
||||
case 250 /* ForInStatement */:
|
||||
return emitForInStatement(node);
|
||||
case 251 /* ForOfStatement */:
|
||||
case 252 /* ForOfStatement */:
|
||||
return emitForOfStatement(node);
|
||||
case 252 /* ContinueStatement */:
|
||||
return emitContinueStatement(node);
|
||||
@@ -124787,7 +124787,7 @@ function createPrinter(printerOptions = {}, handlers = {}) {
|
||||
generateNames(node.elseStatement);
|
||||
break;
|
||||
case 249 /* ForStatement */:
|
||||
case 251 /* ForOfStatement */:
|
||||
case 252 /* ForOfStatement */:
|
||||
case 250 /* ForInStatement */:
|
||||
generateNames(node.initializer);
|
||||
generateNames(node.statement);
|
||||
@@ -139884,7 +139884,7 @@ function isCompletedNode(n, sourceFile) {
|
||||
return false;
|
||||
case 249 /* ForStatement */:
|
||||
case 250 /* ForInStatement */:
|
||||
case 251 /* ForOfStatement */:
|
||||
case 252 /* ForOfStatement */:
|
||||
case 248 /* WhileStatement */:
|
||||
return isCompletedNode(n.statement, sourceFile);
|
||||
case 247 /* DoStatement */:
|
||||
@@ -140674,7 +140674,7 @@ function isArrayLiteralOrObjectLiteralDestructuringPattern(node) {
|
||||
if (node.parent.kind === 227 /* BinaryExpression */ && node.parent.left === node && node.parent.operatorToken.kind === 64 /* EqualsToken */) {
|
||||
return true;
|
||||
}
|
||||
if (node.parent.kind === 251 /* ForOfStatement */ && node.parent.initializer === node) {
|
||||
if (node.parent.kind === 252 /* ForOfStatement */ && node.parent.initializer === node) {
|
||||
return true;
|
||||
}
|
||||
if (isArrayLiteralOrObjectLiteralDestructuringPattern(node.parent.kind === 304 /* PropertyAssignment */ ? node.parent.parent : node.parent)) {
|
||||
@@ -143632,7 +143632,7 @@ var DocumentHighlights;
|
||||
// falls through
|
||||
case 249 /* ForStatement */:
|
||||
case 250 /* ForInStatement */:
|
||||
case 251 /* ForOfStatement */:
|
||||
case 252 /* ForOfStatement */:
|
||||
case 248 /* WhileStatement */:
|
||||
case 247 /* DoStatement */:
|
||||
return !statement.label || isLabeledBy(node, statement.label.escapedText);
|
||||
@@ -143712,7 +143712,7 @@ var DocumentHighlights;
|
||||
switch (owner.kind) {
|
||||
case 249 /* ForStatement */:
|
||||
case 250 /* ForInStatement */:
|
||||
case 251 /* ForOfStatement */:
|
||||
case 252 /* ForOfStatement */:
|
||||
case 247 /* DoStatement */:
|
||||
case 248 /* WhileStatement */:
|
||||
return getLoopBreakContinueOccurrences(owner);
|
||||
@@ -154280,7 +154280,7 @@ function spanInSourceFileAtLocation(sourceFile, position) {
|
||||
return spanInForStatement(node);
|
||||
case 250 /* ForInStatement */:
|
||||
return textSpanEndingAtNextToken(node, node.expression);
|
||||
case 251 /* ForOfStatement */:
|
||||
case 252 /* ForOfStatement */:
|
||||
return spanInInitializerOfForLike(node);
|
||||
case 256 /* SwitchStatement */:
|
||||
return textSpanEndingAtNextToken(node, node.expression);
|
||||
@@ -154378,7 +154378,7 @@ function spanInSourceFileAtLocation(sourceFile, position) {
|
||||
case 171 /* Decorator */:
|
||||
return spanInNode(node.parent);
|
||||
case 249 /* ForStatement */:
|
||||
case 251 /* ForOfStatement */:
|
||||
case 252 /* ForOfStatement */:
|
||||
return textSpan(node);
|
||||
case 227 /* BinaryExpression */:
|
||||
if (node.parent.operatorToken.kind === 28 /* CommaToken */) {
|
||||
@@ -154441,7 +154441,7 @@ function spanInSourceFileAtLocation(sourceFile, position) {
|
||||
if (isBindingPattern(variableDeclaration.name)) {
|
||||
return spanInBindingPattern(variableDeclaration.name);
|
||||
}
|
||||
if (hasOnlyExpressionInitializer(variableDeclaration) && variableDeclaration.initializer || hasSyntacticModifier(variableDeclaration, 32 /* Export */) || parent2.parent.kind === 251 /* ForOfStatement */) {
|
||||
if (hasOnlyExpressionInitializer(variableDeclaration) && variableDeclaration.initializer || hasSyntacticModifier(variableDeclaration, 32 /* Export */) || parent2.parent.kind === 252 /* ForOfStatement */) {
|
||||
return textSpanFromVariableDeclaration(variableDeclaration);
|
||||
}
|
||||
if (isVariableDeclarationList(variableDeclaration.parent) && variableDeclaration.parent.declarations[0] !== variableDeclaration) {
|
||||
@@ -154500,7 +154500,7 @@ function spanInSourceFileAtLocation(sourceFile, position) {
|
||||
return spanInNodeIfStartsOnSameLine(block.parent, block.statements[0]);
|
||||
// Set span on previous token if it starts on same line otherwise on the first statement of the block
|
||||
case 249 /* ForStatement */:
|
||||
case 251 /* ForOfStatement */:
|
||||
case 252 /* ForOfStatement */:
|
||||
return spanInNodeIfStartsOnSameLine(findPrecedingToken(block.pos, sourceFile, block.parent), block.statements[0]);
|
||||
}
|
||||
return spanInNode(block.statements[0]);
|
||||
@@ -154630,7 +154630,7 @@ function spanInSourceFileAtLocation(sourceFile, position) {
|
||||
case 248 /* WhileStatement */:
|
||||
case 247 /* DoStatement */:
|
||||
case 249 /* ForStatement */:
|
||||
case 251 /* ForOfStatement */:
|
||||
case 252 /* ForOfStatement */:
|
||||
case 214 /* CallExpression */:
|
||||
case 215 /* NewExpression */:
|
||||
case 218 /* ParenthesizedExpression */:
|
||||
@@ -154659,7 +154659,7 @@ function spanInSourceFileAtLocation(sourceFile, position) {
|
||||
return spanInNode(node2.parent);
|
||||
}
|
||||
function spanInOfKeyword(node2) {
|
||||
if (node2.parent.kind === 251 /* ForOfStatement */) {
|
||||
if (node2.parent.kind === 252 /* ForOfStatement */) {
|
||||
return spanInNextNode(node2);
|
||||
}
|
||||
return spanInNode(node2.parent);
|
||||
@@ -162485,7 +162485,7 @@ function canPrefix(token) {
|
||||
case 261 /* VariableDeclaration */: {
|
||||
const varDecl = token.parent;
|
||||
switch (varDecl.parent.parent.kind) {
|
||||
case 251 /* ForOfStatement */:
|
||||
case 252 /* ForOfStatement */:
|
||||
case 250 /* ForInStatement */:
|
||||
return true;
|
||||
}
|
||||
@@ -169764,7 +169764,7 @@ function getCompletionData(program, log, sourceFile, compilerOptions, position,
|
||||
isNewIdentifierLocation = false;
|
||||
const rootDeclaration = getRootDeclaration(objectLikeContainer.parent);
|
||||
if (!isVariableLike(rootDeclaration)) return Debug.fail("Root declaration is not variable-like.");
|
||||
let canGetType = hasInitializer(rootDeclaration) || !!getEffectiveTypeAnnotationNode(rootDeclaration) || rootDeclaration.parent.parent.kind === 251 /* ForOfStatement */;
|
||||
let canGetType = hasInitializer(rootDeclaration) || !!getEffectiveTypeAnnotationNode(rootDeclaration) || rootDeclaration.parent.parent.kind === 252 /* ForOfStatement */;
|
||||
if (!canGetType && rootDeclaration.kind === 170 /* Parameter */) {
|
||||
if (isExpression(rootDeclaration.parent)) {
|
||||
canGetType = !!typeChecker.getContextualType(rootDeclaration.parent);
|
||||
@@ -172505,7 +172505,7 @@ function getContextNode(node) {
|
||||
return node.parent;
|
||||
case 227 /* BinaryExpression */:
|
||||
return isExpressionStatement(node.parent) ? node.parent : node;
|
||||
case 251 /* ForOfStatement */:
|
||||
case 252 /* ForOfStatement */:
|
||||
case 250 /* ForInStatement */:
|
||||
return {
|
||||
start: node.initializer,
|
||||
@@ -177133,7 +177133,7 @@ function getOutliningSpanForNode(n, sourceFile) {
|
||||
switch (n.parent.kind) {
|
||||
case 247 /* DoStatement */:
|
||||
case 250 /* ForInStatement */:
|
||||
case 251 /* ForOfStatement */:
|
||||
case 252 /* ForOfStatement */:
|
||||
case 249 /* ForStatement */:
|
||||
case 246 /* IfStatement */:
|
||||
case 248 /* WhileStatement */:
|
||||
@@ -180339,7 +180339,7 @@ var deleteDeclaration;
|
||||
}
|
||||
const gp = parent2.parent;
|
||||
switch (gp.kind) {
|
||||
case 251 /* ForOfStatement */:
|
||||
case 252 /* ForOfStatement */:
|
||||
case 250 /* ForInStatement */:
|
||||
changes.replaceNode(sourceFile, node, factory.createObjectLiteralExpression());
|
||||
break;
|
||||
@@ -181131,7 +181131,7 @@ function isBinaryOpContext(context) {
|
||||
case 169 /* TypeParameter */:
|
||||
return context.currentTokenSpan.kind === 103 /* InKeyword */ || context.nextTokenSpan.kind === 103 /* InKeyword */ || context.currentTokenSpan.kind === 64 /* EqualsToken */ || context.nextTokenSpan.kind === 64 /* EqualsToken */;
|
||||
// Technically, "of" is not a binary operator, but format it the same way as "in"
|
||||
case 251 /* ForOfStatement */:
|
||||
case 252 /* ForOfStatement */:
|
||||
return context.currentTokenSpan.kind === 165 /* OfKeyword */ || context.nextTokenSpan.kind === 165 /* OfKeyword */;
|
||||
}
|
||||
return false;
|
||||
@@ -181262,7 +181262,7 @@ function isControlDeclContext(context) {
|
||||
case 256 /* SwitchStatement */:
|
||||
case 249 /* ForStatement */:
|
||||
case 250 /* ForInStatement */:
|
||||
case 251 /* ForOfStatement */:
|
||||
case 252 /* ForOfStatement */:
|
||||
case 248 /* WhileStatement */:
|
||||
case 259 /* TryStatement */:
|
||||
case 247 /* DoStatement */:
|
||||
@@ -181409,7 +181409,7 @@ function isStatementConditionContext(context) {
|
||||
case 246 /* IfStatement */:
|
||||
case 249 /* ForStatement */:
|
||||
case 250 /* ForInStatement */:
|
||||
case 251 /* ForOfStatement */:
|
||||
case 252 /* ForOfStatement */:
|
||||
case 247 /* DoStatement */:
|
||||
case 248 /* WhileStatement */:
|
||||
return true;
|
||||
@@ -183041,7 +183041,7 @@ var SmartIndenter;
|
||||
case 247 /* DoStatement */:
|
||||
case 248 /* WhileStatement */:
|
||||
case 250 /* ForInStatement */:
|
||||
case 251 /* ForOfStatement */:
|
||||
case 252 /* ForOfStatement */:
|
||||
case 249 /* ForStatement */:
|
||||
case 246 /* IfStatement */:
|
||||
case 263 /* FunctionDeclaration */:
|
||||
|
||||
4
valdi/node_modules/typescript/package.json
generated
vendored
4
valdi/node_modules/typescript/package.json
generated
vendored
@@ -43,7 +43,7 @@
|
||||
"@dprint/typescript": "0.93.4",
|
||||
"@esfx/canceltoken": "^1.0.0",
|
||||
"@eslint/js": "^9.20.0",
|
||||
"@octokit/rest": "^21.1.1",
|
||||
"@octokit/rest": "^21.1.2",
|
||||
"@types/chai": "^4.3.20",
|
||||
"@types/diff": "^7.0.1",
|
||||
"@types/minimist": "^1.2.5",
|
||||
@@ -76,7 +76,7 @@
|
||||
"mocha-fivemat-progress-reporter": "^0.1.0",
|
||||
"monocart-coverage-reports": "^2.12.1",
|
||||
"ms": "^2.1.3",
|
||||
"picocolors": "^1.1.1",
|
||||
"picocolors": "^1.1.2",
|
||||
"playwright": "^1.50.1",
|
||||
"source-map-support": "^0.5.21",
|
||||
"tslib": "^2.8.1",
|
||||
|
||||
Reference in New Issue
Block a user