8 Commits

Author SHA1 Message Date
zxq5 7e001d8769 idk 2026-06-03 19:12:23 +01:00
zxq5 2f34976f3e Merge remote-tracking branch 'origin/dev' into dev 2026-04-11 00:10:09 +01:00
zxq5 d1208f7e39 frontend v0.4.1-2
- added invite section to UI and some general bug fixes
2026-04-11 00:09:47 +01:00
zxq5 d6ba875297 addedd RELEASE_MODE=1 to run var to prevent crash in absence of .env
file
2026-04-08 00:05:54 +01:00
zxq5 529d09aabc frontend v0.4.1
- fixed most of the bugs with the rewrite. should be ready to deploy now
2026-04-08 00:00:28 +01:00
zxq5 5291e7dee6 rewritten docker compose files and updated giutignore 2026-04-06 15:42:20 +01:00
zxq5 3c52ade946 deleted some old files 2026-04-06 15:38:28 +01:00
zxq5 0f692e4372 updated docker compose and formatted backend. 2026-04-06 13:44:50 +01:00
737 changed files with 1208 additions and 93228 deletions
-2
View File
@@ -5,5 +5,3 @@
Cargo.lock
.cargo/
.sqlx/
docker-compose*
+1 -5
View File
@@ -1,12 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
xmlns:tools="http://tools.android.com/tools">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC"/>
<application
android:name=".ChatApplication"
@@ -22,7 +19,6 @@
<service
android:name=".core.service.MessageStreamService"
android:foregroundServiceType="dataSync"
android:exported="false"/>
<activity
@@ -1,9 +1,13 @@
package dev.zxq5.chatapp.android
import android.Manifest
import android.os.Build
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
@@ -62,14 +66,37 @@ class MainActivity : ComponentActivity() {
val currentScreen by chatViewModel.currentScreen.collectAsState()
val selectedChannelId by chatViewModel.channelId.collectAsState()
// Permission request launcher
val launcher = rememberLauncherForActivityResult(
contract = ActivityResultContracts.RequestPermission(),
onResult = { isGranted ->
if (isGranted && authState == AuthState.Authenticated) {
MessageStreamService.start(this@MainActivity)
}
}
)
LaunchedEffect(authState) {
when (authState) {
AuthState.Authenticated -> MessageStreamService.start(this@MainActivity)
AuthState.Authenticated -> {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
launcher.launch(Manifest.permission.POST_NOTIFICATIONS)
}
MessageStreamService.start(this@MainActivity)
chatViewModel.loadAccessibleChannels()
}
AuthState.Unauthenticated -> MessageStreamService.stop(this@MainActivity)
AuthState.AwaitingTotp -> {}
}
}
LaunchedEffect(Unit) {
chatViewModel.onUnauthorized = {
authViewModel.logout()
chatViewModel.clearChat()
}
}
LaunchedEffect(Unit) {
intent.getIntExtra("channel_id", -1).takeIf { it != -1 }?.let {
chatViewModel.switchChannel(it.toLong())
@@ -1,7 +1,9 @@
@file:OptIn(ExperimentalUuidApi::class)
package dev.zxq5.chatapp.android.api
import dev.zxq5.chatapp.android.BuildConfig.BASE_URL
import dev.zxq5.chatapp.android.api.model.Message
import dev.zxq5.chatapp.android.api.model.ChatEvent
import dev.zxq5.chatapp.android.api.model.SendMessage
import dev.zxq5.chatapp.android.api.model.SpaceDto
import io.ktor.client.HttpClient
@@ -25,6 +27,8 @@ import kotlinx.coroutines.flow.flow
import kotlinx.serialization.json.Json
import kotlin.time.Clock
import kotlin.time.ExperimentalTime
import kotlin.uuid.ExperimentalUuidApi
import kotlin.uuid.Uuid
class ChatClient(private val token: String) {
@@ -45,18 +49,18 @@ class ChatClient(private val token: String) {
suspend fun sendMessage(channelId: Long, userId: Int, text: String) {
http.post("${BASE_URL}/api/chat/$channelId") {
contentType(ContentType.Application.Json)
setBody(SendMessage(user_id = userId, text = text, timestamp = Clock.System.now()))
setBody(SendMessage(id = Uuid.random(), user_id = userId, text = text, timestamp = Clock.System.now()))
}
}
fun messageStream(channelId: Long): Flow<Message> = flow {
fun eventStream(channelId: Long): Flow<ChatEvent> = flow {
http.prepareGet("${BASE_URL}/api/events/$channelId").execute { response ->
val channel = response.bodyAsChannel()
while (!channel.isClosedForRead) {
val line = channel.readLine() ?: break
if (line.startsWith("data:")) {
val json = line.removePrefix("data:").trim()
runCatching { Json.decodeFromString<Message>(json) }
runCatching { Json.decodeFromString<ChatEvent>(json) }
.onSuccess { emit(it) }
}
}
@@ -4,6 +4,7 @@ import android.util.Log
import dev.zxq5.chatapp.android.BuildConfig.BASE_URL
import dev.zxq5.chatapp.android.api.model.AccountDeleteRequest
import dev.zxq5.chatapp.android.api.model.DisplayNameRequest
import dev.zxq5.chatapp.android.api.model.InviteRequest
import dev.zxq5.chatapp.android.api.model.PasswordChangeRequest
import dev.zxq5.chatapp.android.api.model.QrResponse
import dev.zxq5.chatapp.android.api.model.TOTPSixDigitCode
@@ -45,6 +46,22 @@ class SettingsClient(private val token: String) {
}
}
suspend fun createInvite(request: InviteRequest): ApiResult<String> {
return try {
val response = http.post("${BASE_URL}/api/invite") {
contentType(ContentType.Application.Json)
setBody(request)
}
if (response.status.isSuccess()) {
ApiResult.Success(response.body<String>())
} else {
ApiResult.HttpError(response.status.value, "Failed to create invite")
}
} catch (e: Exception) {
ApiResult.NetworkError(e.localizedMessage ?: "Network error")
}
}
suspend fun getTotpQr(password: String): ApiResult<QrResponse> {
return try {
val response = http.post("${BASE_URL}/api/totp.jpg") {
@@ -0,0 +1,60 @@
@file:OptIn(ExperimentalUuidApi::class, ExperimentalTime::class)
package dev.zxq5.chatapp.android.api.model
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.SerialName
import kotlinx.serialization.json.JsonClassDiscriminator
import kotlin.time.ExperimentalTime
import kotlin.time.Instant
import kotlinx.serialization.Serializable
import kotlin.uuid.ExperimentalUuidApi
import kotlin.uuid.Uuid
@OptIn(ExperimentalSerializationApi::class)
@Serializable
@JsonClassDiscriminator("type")
sealed class ChatEvent {
@Serializable
@SerialName("SendMessage")
data class SendMessage(
val data: Message
) : ChatEvent()
@Serializable
@SerialName("EditMessage")
data class EditMessage(
val data: EditMessageContent
) : ChatEvent()
@Serializable
@SerialName("MessageAppendContent")
data class MessageAppendContent(
val data: AppendContent
) : ChatEvent()
}
// tuple variants like (i64, ChatMsg) and (i64, String)
// need wrapper classes since kotlinx can't deserialise
// bare JSON arrays into data classes directly
@Serializable
data class EditMessageContent(
val id: Uuid,
val message: Message
)
@Serializable
data class AppendContent (
val id: Uuid,
val content: String
)
@Serializable
data class Message (
val id: Uuid,
val user_id: Int,
val display_name: String,
val text: String,
val timestamp: Instant
)
@@ -0,0 +1,13 @@
package dev.zxq5.chatapp.android.api.model
import kotlinx.serialization.Serializable
import kotlin.time.ExperimentalTime
import kotlin.time.Instant
@Serializable
data class InviteRequest @OptIn(ExperimentalTime::class) constructor(
val name: String,
val max_uses: Int,
val expiry_date: Instant,
val start_date: Instant
)
@@ -1,4 +1,4 @@
package dev.zxq5.chatapp.android.model
package dev.zxq5.chatapp.android.api.model
sealed class LoginState {
object Idle : LoginState()
@@ -1,13 +0,0 @@
package dev.zxq5.chatapp.android.api.model
import kotlinx.serialization.Serializable
import kotlin.time.ExperimentalTime
import kotlin.time.Instant
@Serializable
data class Message @OptIn(ExperimentalTime::class) constructor(
val user_id: Int,
val display_name: String,
val text: String,
val timestamp: Instant
)
@@ -3,9 +3,12 @@ package dev.zxq5.chatapp.android.api.model
import kotlinx.serialization.Serializable
import kotlin.time.ExperimentalTime
import kotlin.time.Instant
import kotlin.uuid.ExperimentalUuidApi
import kotlin.uuid.Uuid
@Serializable
data class SendMessage @OptIn(ExperimentalTime::class) constructor(
data class SendMessage @OptIn(ExperimentalTime::class, ExperimentalUuidApi::class) constructor(
val id: Uuid,
val user_id: Int,
val text: String,
val timestamp: Instant
@@ -3,10 +3,12 @@ package dev.zxq5.chatapp.android.core.data
import android.content.Context
import android.content.SharedPreferences
import android.util.Base64
import android.util.Log
import androidx.core.content.edit
import androidx.security.crypto.EncryptedSharedPreferences
import androidx.security.crypto.MasterKey
import org.json.JSONObject
import java.time.Instant
private const val KEY = "auth_token"
private const val TWOFA_KEY = "twofa_enabled"
@@ -27,11 +29,37 @@ class TokenStore(appContext: Context) {
)
}
fun save(token: String) =
prefs().edit { putString(KEY, token) }
fun save(token: String) {
Log.d("TokenStore", "Saving token: $token")
prefs().edit { putString(KEY, token) }
}
fun get(): String? {
val ret = prefs().getString(KEY, null)
Log.d("TokenStore", "Retrieved token: $ret")
return ret
}
fun isExpired(): Boolean {
val token = get() ?: return true
return try {
val payload = token.split(".")[1]
val padded = payload + "==".take((4 - payload.length % 4) % 4)
val jsonString = String(Base64.decode(padded, Base64.URL_SAFE))
val json = JSONObject(jsonString)
if (json.has("exp")) {
val exp = json.getLong("exp")
val now = Instant.now().epochSecond
now >= exp
} else {
false // If no exp claim, assume not expired or handle differently
}
} catch (e: Exception) {
true // If we can't parse it, treat it as expired
}
}
fun get(): String? =
prefs().getString(KEY, null)
fun save2faEnabled( enabled: Boolean) =
prefs().edit { putBoolean(TWOFA_KEY, enabled) }
@@ -3,10 +3,10 @@ package dev.zxq5.chatapp.android.core.service
import android.app.Service
import android.content.Context
import android.content.Intent
import android.os.Build
import android.os.IBinder
import android.util.Log
import dev.zxq5.chatapp.android.ChatApplication
import dev.zxq5.chatapp.android.api.model.ChatEvent
import dev.zxq5.chatapp.android.data.repository.ChatRepository
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
@@ -15,21 +15,17 @@ import kotlinx.coroutines.cancel
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.launch
// core/service/MessageStreamService.kt
class MessageStreamService : Service() {
private val serviceScope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
private lateinit var notificationService: NotificationService
private lateinit var chatRepository: ChatRepository
// which channel the user is currently looking at
// set by the ViewModel when the user opens/closes a channel
var activeChannelId: Long? = null
set(value) {
field = value
Log.d("Service", "activeChannelId set to $value")
if (value != null) {
// restart stream with new channel
currentStreamJob?.cancel()
observeMessages()
}
@@ -42,12 +38,8 @@ class MessageStreamService : Service() {
fun start(context: Context) {
val intent = Intent(context, MessageStreamService::class.java)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService(intent)
} else {
context.startService(intent)
}
}
fun stop(context: Context) {
context.stopService(Intent(context, MessageStreamService::class.java))
@@ -62,33 +54,29 @@ class MessageStreamService : Service() {
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
startForeground(
NotificationService.FOREGROUND_NOTIFICATION_ID,
notificationService.buildForegroundNotification()
)
observeMessages()
return START_STICKY // restart if killed
return START_STICKY
}
private fun observeMessages() {
val channelId = activeChannelId ?: chatRepository.getLastActiveChannel()
Log.d("Service", "observeMessages called, channelId=$channelId")
if (channelId == null) {
Log.d("Service", "No channel to observe, waiting for switchChannel")
return
}
if (channelId == null) return
Log.d("Service", "Starting stream for channel $channelId")
currentStreamJob = serviceScope.launch {
chatRepository.messageStream(channelId)
chatRepository.eventStream(channelId)
.catch { e -> Log.e("Service", "Stream error", e) }
.collect { message ->
if (!ChatApplication.AppState.isInForeground) { // no channel focused, always notify
notificationService.showMessageNotification(
conversationId = activeChannelId.toString(),
senderName = message.display_name,
messagePreview = message.text.take(80)
.collect { event ->
// Only show notification when an event (new message) is received
// and the app is not in the foreground on this channel.
if (!ChatApplication.AppState.isInForeground || activeChannelId != channelId) {
when (event) {
is ChatEvent.SendMessage -> notificationService.showMessageNotification(
conversationId = channelId.toString(),
senderName = event.data.display_name,
messagePreview = event.data.text
)
else -> {}
}
}
}
}
@@ -15,51 +15,41 @@ class NotificationService(private val context: Context) {
companion object {
const val CHANNEL_ID = "messages"
const val FOREGROUND_NOTIFICATION_ID = 1 // ← this needs to exist
const val SERVICE_CHANNEL_ID = "service"
const val FOREGROUND_NOTIFICATION_ID = 1
}
private val manager = context.getSystemService(NotificationManager::class.java)
fun createChannels() {
// channel for new message notifications
val messageChannel = NotificationChannel(
CHANNEL_ID,
"Messages",
NotificationManager.IMPORTANCE_HIGH
).apply {
enableVibration(true)
fun createForegroundNotification(): Notification {
val intent = Intent(context, MainActivity::class.java).apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
}
// channel for the persistent foreground service notification
// low importance so it doesn't make noise
val serviceChannel = NotificationChannel(
"service",
"Background connection",
NotificationManager.IMPORTANCE_LOW
val pendingIntent = PendingIntent.getActivity(
context,
0,
intent,
PendingIntent.FLAG_IMMUTABLE
)
val mgr = context.getSystemService(NotificationManager::class.java)
mgr.createNotificationChannel(messageChannel)
mgr.createNotificationChannel(serviceChannel)
}
fun buildForegroundNotification(): Notification {
return NotificationCompat.Builder(context, "service")
return NotificationCompat.Builder(context, SERVICE_CHANNEL_ID)
.setSmallIcon(R.drawable.ic_notification)
.setContentTitle("chatapp")
.setContentText("Connected")
.setContentTitle("Chat App")
.setContentText("Connecting to message stream...")
.setPriority(NotificationCompat.PRIORITY_LOW)
.setCategory(NotificationCompat.CATEGORY_SERVICE)
.setContentIntent(pendingIntent)
.setOngoing(true)
.setSilent(true)
.build()
}
fun showMessageNotification(
conversationId: String,
senderName: String,
messagePreview: String, // for E2E this would be "New message" — no plaintext
messagePreview: String,
notificationId: Int = conversationId.hashCode()
) {
// intent that opens the app to the right conversation when tapped
val intent = Intent(context, MainActivity::class.java).apply {
flags = Intent.FLAG_ACTIVITY_SINGLE_TOP
putExtra("conversation_id", conversationId)
@@ -72,13 +62,13 @@ class NotificationService(private val context: Context) {
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
)
val notification = NotificationCompat.Builder(context, "messages")
val notification = NotificationCompat.Builder(context, CHANNEL_ID)
.setSmallIcon(R.drawable.ic_notification)
.setContentTitle(senderName)
.setContentText(messagePreview)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setContentIntent(pendingIntent)
.setAutoCancel(true) // dismiss on tap
.setAutoCancel(true)
.build()
manager.notify(notificationId, notification)
@@ -56,6 +56,10 @@ class AuthRepository(
fun getAuthState(): AuthState {
val token = tokenStore.get() ?: return AuthState.Unauthenticated
if (tokenStore.isExpired()) {
tokenStore.clear()
return AuthState.Unauthenticated
}
return when (getScopeFromToken(token)) {
TokenScope.FULL -> AuthState.Authenticated
TokenScope.TOTP_PENDING -> AuthState.AwaitingTotp
@@ -1,6 +1,7 @@
package dev.zxq5.chatapp.android.data.repository
import dev.zxq5.chatapp.android.api.ChatClient
import dev.zxq5.chatapp.android.api.model.ChatEvent
import dev.zxq5.chatapp.android.core.data.TokenStore
import dev.zxq5.chatapp.android.api.model.Message
import dev.zxq5.chatapp.android.api.model.SpaceDto
@@ -43,8 +44,8 @@ class ChatRepository(private val tokenStore: TokenStore) {
getChatClient()?.sendMessage(channelId, userId, text)
}
fun messageStream(channelId: Long): Flow<Message> {
fun eventStream(channelId: Long): Flow<ChatEvent> {
_lastActiveChannel = channelId
return getChatClient()?.messageStream(channelId) ?: emptyFlow()
return getChatClient()?.eventStream(channelId) ?: emptyFlow()
}
}
@@ -2,6 +2,7 @@ package dev.zxq5.chatapp.android.data.repository
import dev.zxq5.chatapp.android.api.model.QrResponse
import dev.zxq5.chatapp.android.api.SettingsClient
import dev.zxq5.chatapp.android.api.model.InviteRequest
import dev.zxq5.chatapp.android.api.model.TotpStatus
import dev.zxq5.chatapp.android.core.data.TokenStore
import dev.zxq5.chatapp.android.core.error.ApiResult
@@ -25,6 +26,10 @@ class SettingsRepository(private val tokenStore: TokenStore) {
_lastToken = null
}
suspend fun createInvite(request: InviteRequest): ApiResult<String> {
return getSettingsClient()?.createInvite(request) ?: ApiResult.NetworkError("Not authenticated")
}
suspend fun getTotpQr(password: String): ApiResult<QrResponse?> {
val settingsClient = getSettingsClient() ?: return ApiResult.NetworkError("Not authenticated")
return settingsClient.getTotpQr(password)
@@ -3,7 +3,7 @@ package dev.zxq5.chatapp.android.feature.auth
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import dev.zxq5.chatapp.android.model.LoginState
import dev.zxq5.chatapp.android.api.model.LoginState
@Composable
fun AuthScreen(viewModel: AuthViewModel) {
@@ -7,7 +7,7 @@ import dev.zxq5.chatapp.android.data.repository.AuthRepository
import dev.zxq5.chatapp.android.data.repository.LoginResult
import dev.zxq5.chatapp.android.data.repository.SignupResult
import dev.zxq5.chatapp.android.data.repository.AuthState
import dev.zxq5.chatapp.android.model.LoginState
import dev.zxq5.chatapp.android.api.model.LoginState
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch
@@ -28,7 +28,7 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import dev.zxq5.chatapp.android.model.LoginState
import dev.zxq5.chatapp.android.api.model.LoginState
import dev.zxq5.chatapp.android.ui.components.TextField
@Composable
@@ -28,7 +28,7 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import dev.zxq5.chatapp.android.model.LoginState
import dev.zxq5.chatapp.android.api.model.LoginState
import dev.zxq5.chatapp.android.ui.components.TextField
@Composable
@@ -1,20 +1,25 @@
@file:OptIn(ExperimentalUuidApi::class)
package dev.zxq5.chatapp.android.feature.chat
import android.util.Log
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import dev.zxq5.chatapp.android.api.model.Channel
import dev.zxq5.chatapp.android.api.model.ChatEvent
import dev.zxq5.chatapp.android.data.repository.ChatRepository
import dev.zxq5.chatapp.android.api.model.Message
import dev.zxq5.chatapp.android.api.model.Space
import dev.zxq5.chatapp.android.api.model.SpaceDto
import dev.zxq5.chatapp.android.core.service.MessageStreamService
import io.ktor.client.plugins.ResponseException
import io.ktor.http.HttpStatusCode
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import kotlin.time.ExperimentalTime
import kotlin.uuid.ExperimentalUuidApi
class ChatViewModel(private val chatRepository: ChatRepository) : ViewModel() {
@@ -41,6 +46,8 @@ class ChatViewModel(private val chatRepository: ChatRepository) : ViewModel() {
private var streamJob: Job? = null
var onUnauthorized: (() -> Unit)? = null
init {
_currentUserId.value = chatRepository.getUserId()
observeChannel()
@@ -49,6 +56,7 @@ class ChatViewModel(private val chatRepository: ChatRepository) : ViewModel() {
fun loadAccessibleChannels() {
_error.value = null
_currentUserId.value = chatRepository.getUserId()
viewModelScope.launch {
runCatching {
chatRepository.getAccessibleChannels()
@@ -56,11 +64,16 @@ class ChatViewModel(private val chatRepository: ChatRepository) : ViewModel() {
_spaces.value = data
}.onFailure { e ->
Log.e("Chat", "Failed to load spaces", e)
if (e is ResponseException && e.response.status == HttpStatusCode.Unauthorized) {
onUnauthorized?.invoke()
} else {
_error.value = "Failed to load channels: ${e.message}"
}
}
}
}
@OptIn(ExperimentalTime::class)
private fun observeChannel() {
viewModelScope.launch {
_channelId.collect { id ->
@@ -69,13 +82,40 @@ class ChatViewModel(private val chatRepository: ChatRepository) : ViewModel() {
_channelError.value = null
if (id != null) {
streamJob = launch {
chatRepository.messageStream(id)
chatRepository.eventStream(id)
.catch { e ->
Log.e("Chat", "Stream error", e)
if (e is ResponseException && e.response.status == HttpStatusCode.Unauthorized) {
onUnauthorized?.invoke()
} else {
_channelError.value = "Connection lost: ${e.message}"
}
.collect { message ->
_messages.update { it + message }
}
.collect { event ->
when (event) {
is ChatEvent.SendMessage -> {
_messages.update { it + event.data }
}
is ChatEvent.EditMessage -> {
_messages.update { messages ->
messages.map {
if (it.id == event.data.id) event.data.message
else it
}
}
}
is ChatEvent.MessageAppendContent -> {
_messages.update { messages ->
messages.map { msg ->
if (msg.id == event.data.id) {
msg.copy(text = msg.text + event.data.content)
} else {
msg
}
}
}
}
}
}
}
}
@@ -108,15 +148,20 @@ class ChatViewModel(private val chatRepository: ChatRepository) : ViewModel() {
)
}.onFailure { e ->
Log.e("Chat", "Send message error", e)
if (e is ResponseException && e.response.status == HttpStatusCode.Unauthorized) {
onUnauthorized?.invoke()
} else {
_channelError.value = "Failed to send message"
}
}
}
}
fun clearChat() {
_messages.value = emptyList()
_channelId.value = null
_currentUserId.value = null
_spaces.value = emptyList()
_error.value = null
_channelError.value = null
streamJob?.cancel()
@@ -1,3 +1,5 @@
@file:OptIn(ExperimentalUuidApi::class)
package dev.zxq5.chatapp.android.feature.chat
import androidx.compose.foundation.BorderStroke
@@ -65,6 +67,7 @@ import dev.zxq5.chatapp.android.api.model.Message
import java.text.DateFormat
import java.util.Date
import kotlin.time.ExperimentalTime
import kotlin.uuid.ExperimentalUuidApi
@Composable
fun ChatScreen(
@@ -277,7 +280,7 @@ fun MessageScreen(channelId: Long, viewModel: ChatViewModel, onBack: () -> Unit)
modifier = Modifier.weight(1f).padding(horizontal = 16.dp),
verticalArrangement = Arrangement.spacedBy(10.dp)
) {
items(messages) { message ->
items(messages, key = { it.id }) { message ->
MessageBubble(message, currentUserId)
}
item { Spacer(Modifier.height(10.dp)) }
@@ -378,7 +381,7 @@ fun MessageBubble(message: Message, currentUserId: Int?) {
horizontalAlignment = if (isMe) Alignment.End else Alignment.Start
) {
Surface(
color = if (isMe) MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.5f) else MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.2f),
color = if (isMe) MaterialTheme.colorScheme.surfaceVariant else MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.2f),
shape = RoundedCornerShape(
topStart = 14.dp,
topEnd = 14.dp,
@@ -388,14 +391,7 @@ fun MessageBubble(message: Message, currentUserId: Int?) {
border = border(0.5.dp, MaterialTheme.colorScheme.outlineVariant.copy(alpha = 0.5f))
) {
Column(modifier = Modifier.padding(horizontal = 11.dp, vertical = 8.dp)) {
if (!isMe) {
Text(
message.display_name?.lowercase() ?: "unknown",
style = MaterialTheme.typography.labelSmall,
color = MaterialTheme.colorScheme.primary.copy(alpha = 0.7f),
modifier = Modifier.padding(bottom = 2.dp)
)
}
Text(
text = message.text,
style = MaterialTheme.typography.bodyLarge,
@@ -403,10 +399,11 @@ fun MessageBubble(message: Message, currentUserId: Int?) {
)
}
}
Text(
text = time,
style = MaterialTheme.typography.labelSmall,
color = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.3f),
text = if (!isMe) message.display_name.lowercase() + " . " + time else time,
style = MaterialTheme.typography.labelMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.5f),
modifier = Modifier.padding(horizontal = 4.dp, vertical = 2.dp)
)
}
@@ -2,6 +2,7 @@ package dev.zxq5.chatapp.android.feature.settings
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import dev.zxq5.chatapp.android.api.model.InviteRequest
import dev.zxq5.chatapp.android.api.model.QrResponse
import dev.zxq5.chatapp.android.core.error.ApiResult
import dev.zxq5.chatapp.android.data.repository.SettingsRepository
@@ -27,6 +28,9 @@ class SettingsViewModel(private val settingsRepository: SettingsRepository) : Vi
private val _isSuccessState = MutableStateFlow<Map<String, Boolean>>(emptyMap())
val isSuccessState: StateFlow<Map<String, Boolean>> = _isSuccessState
private val _lastInviteCode = MutableStateFlow<String?>(null)
val lastInviteCode: StateFlow<String?> = _lastInviteCode
fun clearMessages() {
_settingsError.value = null
_totpError.value = null
@@ -40,6 +44,20 @@ class SettingsViewModel(private val settingsRepository: SettingsRepository) : Vi
}
}
fun createInvite(request: InviteRequest) {
viewModelScope.launch {
_settingsError.value = null
when (val result = settingsRepository.createInvite(request)) {
is ApiResult.Success -> {
_lastInviteCode.value = result.data
triggerSuccess("invite")
}
is ApiResult.HttpError -> _settingsError.value = result.message
is ApiResult.NetworkError -> _settingsError.value = result.message
}
}
}
fun fetchTotpStatus() {
viewModelScope.launch {
when (val result = settingsRepository.getTotpStatus()) {
@@ -23,11 +23,14 @@ import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.filled.ContentCopy
import androidx.compose.material.icons.filled.KeyboardArrowDown
import androidx.compose.material.icons.filled.KeyboardArrowUp
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.DatePicker
import androidx.compose.material3.DatePickerDialog
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon
@@ -37,8 +40,10 @@ import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.OutlinedTextFieldDefaults
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.rememberDatePickerState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
@@ -57,9 +62,15 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import android.util.Base64
import android.graphics.BitmapFactory
import androidx.compose.ui.platform.LocalClipboardManager
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.style.TextAlign
import dev.zxq5.chatapp.android.api.model.InviteRequest
import kotlin.time.Duration.Companion.days
import kotlin.time.ExperimentalTime
import kotlin.time.Instant
@OptIn(ExperimentalMaterial3Api::class)
@OptIn(ExperimentalMaterial3Api::class, ExperimentalTime::class)
@Composable
fun SettingsScreen(
viewModel: SettingsViewModel,
@@ -70,6 +81,7 @@ fun SettingsScreen(
val settingsError by viewModel.settingsError.collectAsState()
val isSuccessState by viewModel.isSuccessState.collectAsState()
val totpError by viewModel.totpError.collectAsState()
val lastInviteCode by viewModel.lastInviteCode.collectAsState()
LaunchedEffect(Unit) {
viewModel.clearMessages()
@@ -274,6 +286,120 @@ fun SettingsScreen(
}
}
SettingsSection(title = "invite") {
var inviteName by remember { mutableStateOf("") }
var maxUses by remember { mutableStateOf("1") }
val clipboardManager = LocalClipboardManager.current
var showDatePicker by remember { mutableStateOf(false) }
val datePickerState = rememberDatePickerState(
initialSelectedDateMillis = System.currentTimeMillis() + 7.days.inWholeMilliseconds
)
Text("create invite token", style = MaterialTheme.typography.bodyMedium, modifier = Modifier.padding(bottom = 8.dp))
OutlinedTextField(
value = inviteName,
onValueChange = { inviteName = it },
label = { Text("name") },
modifier = Modifier.fillMaxWidth(),
shape = RoundedCornerShape(8.dp)
)
Spacer(Modifier.height(8.dp))
OutlinedTextField(
value = maxUses,
onValueChange = { if (it.all { c -> c.isDigit() }) maxUses = it },
label = { Text("max uses") },
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
modifier = Modifier.fillMaxWidth(),
shape = RoundedCornerShape(8.dp)
)
Spacer(Modifier.height(8.dp))
OutlinedTextField(
value = datePickerState.selectedDateMillis?.let { Instant.fromEpochMilliseconds(it).toString().substringBefore("T") } ?: "",
onValueChange = {},
label = { Text("expiry date") },
readOnly = true,
trailingIcon = {
IconButton(onClick = { showDatePicker = true }) {
Icon(Icons.Default.KeyboardArrowDown, contentDescription = "Select Date")
}
},
modifier = Modifier.fillMaxWidth().clickable { showDatePicker = true },
shape = RoundedCornerShape(8.dp)
)
if (showDatePicker) {
DatePickerDialog(
onDismissRequest = { showDatePicker = false },
confirmButton = {
TextButton(onClick = { showDatePicker = false }) {
Text("ok")
}
}
) {
DatePicker(state = datePickerState)
}
}
Spacer(Modifier.height(12.dp))
SuccessButton(
onClick = {
val nowMs = System.currentTimeMillis()
val expiryMs = datePickerState.selectedDateMillis ?: (nowMs + 7.days.inWholeMilliseconds)
viewModel.createInvite(
InviteRequest(
name = inviteName,
max_uses = maxUses.toIntOrNull() ?: 1,
start_date = Instant.fromEpochMilliseconds(nowMs),
expiry_date = Instant.fromEpochMilliseconds(expiryMs)
)
)
},
label = "generate invite",
isSuccess = isSuccessState["invite"] == true,
enabled = inviteName.isNotBlank(),
modifier = Modifier.fillMaxWidth()
)
if (lastInviteCode != null) {
Spacer(Modifier.height(16.dp))
Row(
modifier = Modifier
.fillMaxWidth()
.background(MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.3f), RoundedCornerShape(8.dp))
.padding(12.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween
) {
Text(
text = lastInviteCode!!,
style = MaterialTheme.typography.bodyLarge,
modifier = Modifier.weight(1f)
)
IconButton(onClick = {
clipboardManager.setText(AnnotatedString(lastInviteCode!!))
}) {
Icon(Icons.Default.ContentCopy, contentDescription = "Copy", modifier = Modifier.size(20.dp))
}
}
}
}
SettingsSection(title = "session") {
Button(
onClick = onLogout,
modifier = Modifier.fillMaxWidth(),
shape = RoundedCornerShape(8.dp),
colors = ButtonDefaults.buttonColors(containerColor = Color.White, contentColor = Color.Black)
) {
Text("logout")
}
}
SettingsSection(title = "danger zone", color = Color.Red.copy(alpha = 0.7f)) {
var deletePassword by remember { mutableStateOf("") }
var deleteTotp by remember { mutableStateOf("") }
@@ -337,18 +463,6 @@ fun SettingsScreen(
}
}
SettingsSection(title = "session") {
Spacer(Modifier.height(16.dp))
Button(
onClick = onLogout,
modifier = Modifier.fillMaxWidth(),
shape = RoundedCornerShape(8.dp),
colors = ButtonDefaults.buttonColors(containerColor = Color.White, contentColor = Color.Black)
) {
Text("logout")
}
}
if (settingsError != null) {
Text(settingsError!!, color = Color.Red, style = MaterialTheme.typography.bodySmall, modifier = Modifier.padding(top = 8.dp))
}
@@ -457,6 +571,7 @@ fun SuccessButton(
}
}
@OptIn(ExperimentalTime::class)
@Composable
fun TwoFactorSetup(
qrCodeBase64: String?,
@@ -511,15 +626,13 @@ fun TwoFactorSetup(
Text(error.lowercase(), color = Color.Red, style = MaterialTheme.typography.labelSmall, modifier = Modifier.padding(top = 8.dp))
}
Spacer(Modifier.height(24.dp))
Button(
onClick = { if (code.length == 6) onConfirm(code) },
Spacer(Modifier.height(16.dp))
SuccessButton(
onClick = { onConfirm(code) },
label = "verify and enable",
isSuccess = false, // Managed by parent
enabled = code.length == 6,
modifier = Modifier.fillMaxWidth(),
shape = RoundedCornerShape(8.dp)
) {
Text("confirm code")
}
modifier = Modifier.fillMaxWidth()
)
}
}
@@ -2,12 +2,14 @@ package dev.zxq5.chatapp.android.ui.components
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.OutlinedTextFieldDefaults
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.PasswordVisualTransformation
import androidx.compose.ui.unit.dp
@@ -31,6 +33,11 @@ fun TextField(
modifier = Modifier.fillMaxWidth(),
singleLine = true,
textStyle = MaterialTheme.typography.bodyLarge,
keyboardOptions = if (isPassword) {
KeyboardOptions(keyboardType = KeyboardType.Password)
} else {
KeyboardOptions.Default
},
visualTransformation = if (isPassword) PasswordVisualTransformation() else androidx.compose.ui.text.input.VisualTransformation.None,
shape = RoundedCornerShape(8.dp),
colors = OutlinedTextFieldDefaults.colors(
@@ -40,6 +47,6 @@ fun TextField(
unfocusedBorderColor = MaterialTheme.colorScheme.outline,
focusedTextColor = MaterialTheme.colorScheme.onSurface,
unfocusedTextColor = MaterialTheme.colorScheme.onSurface
)
),
)
}
@@ -2,7 +2,7 @@ package dev.zxq5.chatapp.android.ui.theme
import androidx.compose.ui.graphics.Color
val Black = Color(0xFF0A0A0A)
val Black = Color(0xFF000000)
val DarkGrey = Color(0xFF0D0D0D)
val Grey = Color(0xFF141414)
val LightGrey = Color(0xFF1E1E1E)
+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="uk.co.ben_gibson.git.link.SettingsState">
<option name="host" value="e0f86390-1091-4871-8aeb-f534fbc99cf0" />
</component>
</project>
+1 -1
View File
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="DataSourcePerFileMappings">
<file url="file://$PROJECT_DIR$/sql/schema.sql" value="b14acf5d-6750-469b-8aea-59c8343eb11c" />
<file url="file://$PROJECT_DIR$/sql/test.sql" value="b14acf5d-6750-469b-8aea-59c8343eb11c" />
<file url="file://$PROJECT_DIR$/src/repo/user_repo.rs" value="b14acf5d-6750-469b-8aea-59c8343eb11c" />
</component>
</project>
+2 -1
View File
@@ -1,7 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="SqlDialectMappings">
<file url="file://$PROJECT_DIR$/sql/schema.sql" dialect="PostgreSQL" />
<file url="file://$PROJECT_DIR$/migrations/20260412200102_message_id_to_uuid.sql" dialect="PostgreSQL" />
<file url="file://$PROJECT_DIR$/sql/test.sql" dialect="PostgreSQL" />
<file url="PROJECT" dialect="PostgreSQL" />
</component>
</project>
+3 -3
View File
@@ -12,7 +12,7 @@ image = "0.25.8"
jsonwebtoken = { version = "10.3.0", features = ["rust_crypto"] }
rand = "0.8"
redis = { version = "0.25.4", features = ["tokio-comp"] }
reqwest = { version = "0.12.23", features = ["json"] }
reqwest = { version = "0.12.23", features = ["json", "stream"] }
rocket = { version = "0.5.1", features = ["json", "secrets"] }
rocket_cors = "0.6.0"
rocket_db_pools = { version = "0.2.0", features = ["deadpool_redis", "sqlx_macros", "sqlx_postgres"] }
@@ -20,11 +20,11 @@ rocket_dyn_templates = { version = "0.2.0", features = ["tera"] }
serde = { version = "1.0.228", features = ["derive"] }
serde_json = "1.0.145"
sha2 = "0.10.9"
sqlx = { version = "0.7.4", features = ["chrono", "macros", "postgres", "time"] }
sqlx = { version = "0.7.4", features = ["chrono", "macros", "postgres", "time", "uuid"] }
tokio = { version = "1.47.1", features = ["full"] }
totp-rs = { version = "5.7.0", features = ["gen_secret", "qr", "rand"] }
tracing = "0.1.44"
uuid = { version = "1.18.1", features = ["v4"] }
uuid = { version = "1.18.1", features = ["serde", "v4"] }
thiserror = "1.0.69"
utoipa = { version = "5.4.0", features = ["rocket_extras", "chrono"] }
clap = { version = "4.5", features = ["derive"] }
-4
View File
@@ -12,8 +12,6 @@ COPY cdn cdn
COPY src src
COPY Cargo.toml Cargo.toml
COPY Rocket.toml Rocket.toml
COPY static static
COPY templates templates
RUN apt-get update && apt-get install -y libssl-dev pkg-config
@@ -37,9 +35,7 @@ COPY --from=build /build/main ./
## copy runtime assets which may or may not exist
COPY --from=build /build/Rocket.toml ./Rocket.toml
COPY --from=build /build/static ./static
COPY --from=build /build/cdn ./cdn
COPY --from=build /build/template[s] ./templates
## ensure the container listens globally on port 8000
ENV ROCKET_ADDRESS=0.0.0.0
+1 -1
View File
@@ -1,7 +1,7 @@
[debug]
secret_key = "yYhvCGnRh/TrcHtB8sZqCFifrVmJxoKFLBYw/WWBZeU="
address = "0.0.0.0"
port = 8000
port = 8080
[debug.databases.postgres_db]
url = "postgresql://chatapp:chatapp@100.118.108.58:5432/chatapp_dev"
@@ -1,17 +1,18 @@
services:
backend:
container_name: chatapp_backend
build:
context: ./backend
context: .
args:
- DATABASE_URL=${DATABASE_URL}
ports:
- "8000:8000"
depends_on:
- redis
environment:
- ROCKET_SECRET_KEY=${ROCKET_SECRET_KEY}
- DATABASE_URL=${DATABASE_URL}
env_file:
- .env
redis:
container_name: chatapp_redis
image: docker.io/library/redis:alpine
ports:
- "6379:6379"
@@ -1,14 +1,16 @@
services:
backend:
container_name: chatapp_backend
image: git.zxq5.dev/zxq5/chatapp-backend:latest
image: git.zxq5.dev/zxq5/chatapp-backend:v0.4.1
ports:
- "8080:8000"
- "8000:8000"
depends_on:
- redis
env_file:
- .env
environment:
- ROCKET_SECRET_KEY=${ROCKET_SECRET_KEY}
- DATABASE_URL=${DATABASE_URL}
- RELEASE_MODE=1
redis:
container_name: chatapp_redis
image: docker.io/library/redis:alpine
@@ -0,0 +1,9 @@
ALTER TABLE attachments DROP CONSTRAINT attachments_message_id_fkey;
ALTER TABLE messages ALTER COLUMN id DROP DEFAULT;
ALTER TABLE messages ALTER COLUMN id TYPE uuid USING gen_random_uuid();
ALTER TABLE messages ALTER COLUMN id SET DEFAULT gen_random_uuid();
ALTER TABLE attachments ALTER COLUMN message_id TYPE uuid USING gen_random_uuid();
ALTER TABLE attachments ADD CONSTRAINT attachments_message_id_fkey
FOREIGN KEY (message_id) REFERENCES messages(id) ON DELETE CASCADE;
+17
View File
@@ -0,0 +1,17 @@
WITH space1 AS (
INSERT INTO spaces (name, description, owner_id)
VALUES ('general', 'Boring chat idk', 1)
RETURNING id
),
space2 AS (
INSERT INTO spaces (name, description, owner_id)
VALUES ('Gaming', 'we lose games', 1)
RETURNING id
)
INSERT INTO channels (name, description, space_id)
SELECT 'General', 'General chat', id FROM space1 UNION ALL
SELECT 'Coding', 'Coding stuff', id FROM space1 UNION ALL
SELECT 'AI', '"/ask" here pls :)', id FROM space1 UNION ALL
SELECT 'The Game', '(You lost)', id FROM space2 UNION ALL
SELECT 'Backrooms', 'Beware of Smilers', id FROM space2 UNION ALL
SELECT 'SE', 'Space/Software engineering.', id FROM space2;
+71 -12
View File
@@ -1,7 +1,8 @@
use crate::error::ApiResult;
use crate::model::auth::{AccessTokenForm, AuthResponse, LoginCredentials, SignupCredentials};
use crate::svc::access_token_svc::AccessTokenService;
use crate::svc::auth_svc::AuthService;
use jsonwebtoken::{decode, encode, DecodingKey, EncodingKey, Header, Validation};
use jsonwebtoken::{DecodingKey, EncodingKey, Header, Validation, decode, encode};
use rocket::http::Status;
use rocket::request::{FromRequest, Outcome};
use rocket::serde::json::Json;
@@ -9,37 +10,45 @@ use rocket::serde::{Deserialize, Serialize};
use rocket::{Request, State};
use std::sync::LazyLock;
use std::time::{SystemTime, UNIX_EPOCH};
use crate::svc::access_token_svc::AccessTokenService;
#[post("/signup", data = "<cred>")]
pub async fn signup(
cred: Json<SignupCredentials>,
svc: &State<AuthService>
svc: &State<AuthService>,
) -> ApiResult<Json<AuthResponse>> {
let response = svc
.signup(
&cred.email, &cred.username, &cred.password, &cred.access_token,
).await?;
&cred.email,
&cred.username,
&cred.password,
&cred.access_token,
)
.await?;
Ok(Json(response))
}
#[post("/login", data = "<cred>")]
pub async fn login(
cred: Json<LoginCredentials>,
svc: &State<AuthService>
svc: &State<AuthService>,
) -> ApiResult<Json<AuthResponse>> {
Ok(Json(svc.login(&cred.username, &cred.password).await?))
}
#[post("/invite", data = "<form>")]
pub async fn generate_invite(
session: Session,
session: AdminSession,
form: Json<AccessTokenForm>,
svc: &State<AccessTokenService>
svc: &State<AccessTokenService>,
) -> ApiResult<String> {
svc.create(
session.uid, &form.name, form.max_uses,
form.start_date, form.expiry_date).await
session.uid,
&form.name,
form.max_uses,
form.start_date,
form.expiry_date,
)
.await
}
static JWT_SECRET: LazyLock<String> = LazyLock::new(|| std::env::var("JWT_SECRET").unwrap());
@@ -77,6 +86,56 @@ impl<'r> FromRequest<'r> for Session {
}
}
pub struct AdminSession {
pub uid: i64,
}
#[rocket::async_trait]
impl<'r> FromRequest<'r> for AdminSession {
type Error = ();
async fn from_request(req: &'r Request<'_>) -> Outcome<Self, Self::Error> {
// First verify the session is valid
match Claims::from_request(req).await {
Outcome::Success(user) if user.scope == TokenScope::Full => {
let uid = user.sub as i64;
// Get AuthService from Rocket state
let auth_svc = match req.guard::<&State<AuthService>>().await {
Outcome::Success(svc) => svc,
Outcome::Error(err) => {
tracing::error!("AdminSession: Failed to get AuthService from state");
return Outcome::Error(err);
}
_ => unreachable!("forward should never be called"),
};
// Check if user is admin
match auth_svc.is_admin(uid).await {
Ok(true) => Outcome::Success(AdminSession { uid }),
Ok(false) => {
tracing::debug!("non-admin user attempted to access admin session");
Outcome::Error((Status::Forbidden, ()))
}
Err(err) => {
tracing::error!("AdminSession: is_admin check failed: {:?}", err);
Outcome::Error((Status::InternalServerError, ()))
}
}
}
Outcome::Success(_) => {
tracing::debug!("warning: user with scope other than Full attempted to access admin session");
Outcome::Error((Status::Forbidden, ()))
}
Outcome::Error(err) => {
tracing::debug!("AdminSession request guard failed: {:?}", err);
Outcome::Error(err)
}
_ => unreachable!("forward should never be called"),
}
}
}
#[derive(Serialize, Deserialize)]
pub struct Claims {
pub sub: i32,
@@ -90,9 +149,9 @@ impl Claims {
sub: user_id as i32,
exp: (SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.expect("Failed to get time")
.as_secs()
+ 3600) as usize,
+ 60 * 60 * 24 * 7) as usize,
scope,
}
}
+9 -16
View File
@@ -9,15 +9,7 @@ use rocket::{Shutdown, State, ___internal_EventStream as EventStream};
use sqlx::FromRow;
use tokio::select;
use tokio::sync::broadcast;
/// ---------- Rocket routes ----------
#[derive(Debug, Serialize, Deserialize, Clone, FromRow)]
pub struct ChatMsg {
pub display_name: Option<String>,
pub user_id: i64,
pub text: String,
pub timestamp: DateTime<Utc>,
}
use crate::model::event::{ChatEvent, ChatMsg};
#[post("/chat/<channel_id>", format = "json", data = "<msg>")]
pub async fn post_message(
@@ -36,24 +28,25 @@ pub async fn event_stream(
mut shutdown: Shutdown,
channel_id: i64,
) -> ApiResult<EventStream![]> {
let messages = chat.get_messages(channel_id, 100)
let messages = chat.fetch_latest_messages_desc(channel_id, 100)
.await?; // if get message returned err, inform user.
let mut rx = chat.subscribe(channel_id).await;
let id = s.uid;
Ok(EventStream! {
for msg in messages {
yield Event::json(&msg);
for msg in messages.into_iter().rev() {
// tracing::info!("sending: {:?}", serde_json::to_string(&ChatEvent::SendMessage(msg.clone())).unwrap());
yield Event::json(&ChatEvent::SendMessage(msg));
}
loop {
select!{
_ = &mut shutdown => break, // exit early on shutdown
msg = rx.recv() => match msg {
Ok(msg) => {
tracing::info!("yielding message!");
yield Event::json(&msg)
event = rx.recv() => match event {
Ok(event) => {
// tracing::info!("yielding event: {event:?}");
yield Event::json(&event)
},
Err(broadcast::error::RecvError::Lagged(n)) => {
tracing::warn!("Receiver lagging on channel {channel_id} by {n} events",);
+10 -13
View File
@@ -1,17 +1,15 @@
use crate::error::ApiResult;
use crate::model::space::{Space, SpaceDto};
use crate::model::space::Channel;
use crate::repo::{SpaceRepo, ChannelRepo};
use rocket::serde::json::Json;
use rocket::State;
use std::sync::Arc;
use crate::api::auth::Session;
use crate::error::ApiResult;
use crate::model::space::Channel;
use crate::model::space::{Space, SpaceDto};
use crate::repo::{ChannelRepo, SpaceRepo};
use crate::svc::chat_svc::ChatService;
use rocket::State;
use rocket::serde::json::Json;
use std::sync::Arc;
#[get("/spaces")]
pub async fn list_spaces(
space_repo: &State<Arc<dyn SpaceRepo>>
) -> ApiResult<Json<Vec<Space>>> {
pub async fn list_spaces(space_repo: &State<Arc<dyn SpaceRepo>>) -> ApiResult<Json<Vec<Space>>> {
let spaces = space_repo.get_all().await?;
Ok(Json(spaces))
}
@@ -19,7 +17,7 @@ pub async fn list_spaces(
#[get("/spaces/<space_id>/channels")]
pub async fn list_channels(
space_id: i64,
channel_repo: &State<Arc<dyn ChannelRepo>>
channel_repo: &State<Arc<dyn ChannelRepo>>,
) -> ApiResult<Json<Vec<Channel>>> {
let channels = channel_repo.get_by_space_id(space_id).await?;
Ok(Json(channels))
@@ -28,9 +26,8 @@ pub async fn list_channels(
#[get("/accessible_channels")]
pub async fn get_accessible_channels(
session: Session,
svc: &State<ChatService>
svc: &State<ChatService>,
) -> ApiResult<Json<Vec<SpaceDto>>> {
let space = svc.get_accessible_channels(session.uid).await?;
println!("{:?}", space);
Ok(Json(space))
}
+47 -53
View File
@@ -4,41 +4,44 @@
#[macro_use]
extern crate rocket;
pub mod messenger;
pub mod api;
pub mod repo;
pub mod error;
pub mod svc;
pub mod model;
pub mod cli;
pub mod error;
pub mod messenger;
pub mod model;
pub mod repo;
pub mod svc;
use crate::repo::{access_token_repo::AccessTokenRepo, Repo};
use crate::repo::message_repo::MessageRepository;
use crate::repo::user_repo::UserRepository;
use crate::repo::space_repo::SpaceRepository;
use crate::repo::channel_repo::ChannelRepository;
use crate::repo::message_repo::MessageRepository;
use crate::repo::space_repo::SpaceRepository;
use crate::repo::user_repo::UserRepository;
use crate::repo::{Repo, access_token_repo::AccessTokenRepo};
use crate::svc::access_token_svc::AccessTokenService;
use crate::svc::auth_svc::AuthService;
use crate::svc::chat_svc::ChatService;
use crate::svc::llm_service::LlmService;
use crate::svc::settings_svc::SettingsService;
use crate::svc::user_svc::UserService;
use rocket::fs::{FileServer, NamedFile};
use api::cdn;
use rocket::http::Method;
use rocket_cors::{AllowedOrigins, CorsOptions};
use rocket_dyn_templates::Template;
use sqlx::postgres::PgPoolOptions;
use std::env;
use std::sync::{Arc, LazyLock};
use std::sync::Arc;
use std::time::Duration;
use api::cdn;
use crate::svc::access_token_svc::AccessTokenService;
use crate::svc::llm_service::LlmService;
pub fn rocket() -> rocket::Rocket<rocket::Build> {
if std::env::var("RELEASE_MODE").unwrap_or_default() != "1" {
dotenv::dotenv().ok();
if let Ok(var) = std::env::var("RELEASE_MODE") && var == "1" {
} else {
dotenv::dotenv().expect("Failed to load .env file");
}
let db_url = std::env::var("DATABASE_URL").expect("DATABASE_URL must be set");
println!("Running with database URL: {}", db_url);
let pool = PgPoolOptions::new()
.max_connections(25)
@@ -53,9 +56,22 @@ pub fn rocket() -> rocket::Rocket<rocket::Build> {
let space_repo: Arc<dyn repo::SpaceRepo> = Arc::new(SpaceRepository::new(pool.clone()));
let channel_repo: Arc<dyn repo::ChannelRepo> = Arc::new(ChannelRepository::new(pool.clone()));
let llm_service = LlmService::new();
let chat_service = ChatService::new(32, llm_service.clone(), message_repo.clone(), user_repo.clone(), channel_repo.clone(), space_repo.clone());
let chat_service = ChatService::new(
32,
llm_service.clone(),
message_repo.clone(),
user_repo.clone(),
channel_repo.clone(),
space_repo.clone(),
);
rocket_builder(user_repo, token_repo, space_repo, channel_repo, chat_service)
rocket_builder(
user_repo,
token_repo,
space_repo,
channel_repo,
chat_service,
)
}
pub fn rocket_builder(
@@ -63,10 +79,8 @@ pub fn rocket_builder(
token_repo: Arc<dyn repo::AccessTokenRepoTrait>,
space_repo: Arc<dyn repo::SpaceRepo>,
channel_repo: Arc<dyn repo::ChannelRepo>,
chat_service: ChatService
chat_service: ChatService,
) -> rocket::Rocket<rocket::Build> {
let cors = CorsOptions::default()
.allowed_origins(AllowedOrigins::all())
.allowed_methods(
@@ -75,7 +89,9 @@ pub fn rocket_builder(
.map(From::from)
.collect(),
)
.allow_credentials(true);
.allow_credentials(true)
.to_cors()
.expect("unable to create cors");
let access_token_svc = AccessTokenService::new(token_repo.clone());
let auth_service = AuthService::new(user_repo.clone(), access_token_svc.clone());
@@ -86,64 +102,42 @@ pub fn rocket_builder(
.manage(chat_service)
.manage(auth_service)
.manage(settings_service)
.manage(access_token_svc)
.manage(user_service)
.manage(space_repo)
.manage(channel_repo)
.attach(cors.to_cors().unwrap())
.attach(Template::fairing())
.mount("/static", FileServer::from("static"))
.mount("/cdn", cdn::routes())
.mount(
"/",
routes![
favicon,
],
)
.attach(cors)
.mount(
"/api",
routes![
cdn::upload_profile_pic,
api::profile::display_name,
// basic auth
api::auth::login,
api::auth::signup,
api::auth::generate_invite,
// 2fa
api::totp::confirm_totp,
api::totp::disable_totp,
api::totp::get_totp,
api::totp::get_totp_status,
api::totp::verify_totp,
// chat
api::chat::event_stream,
api::chat::post_message,
// user settings
api::settings::change_display_name,
api::settings::change_password,
api::settings::change_username,
api::settings::delete_account,
// spaces
api::space::list_spaces,
api::space::list_channels,
api::space::get_accessible_channels
],
)
.register(
"/",
catchers![
error::handle_401,
error::handle_404,
error::handle_default,
],
)
}
#[get("/favicon.ico")]
pub async fn favicon() -> NamedFile {
NamedFile::open("static/favicon.ico").await.unwrap()
// .register(
// "/",
// catchers![error::handle_401, error::handle_404, error::handle_default,],
// )
}
+27
View File
@@ -0,0 +1,27 @@
use rocket::serde::{Deserialize, Serialize};
use sqlx::FromRow;
use chrono::{DateTime, Utc};
use uuid::Uuid;
/// ---------- Rocket routes ----------
#[derive(Debug, Serialize, Deserialize, Clone, FromRow)]
pub struct ChatMsg {
pub id: Uuid,
pub display_name: Option<String>,
pub user_id: i64,
pub text: String,
pub timestamp: DateTime<Utc>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type", content = "data")]
pub enum ChatEvent {
SendMessage(ChatMsg),
/// for when a user explicitly edits a message
EditMessage { id: Uuid, msg: ChatMsg },
/// used for streaming content to a message
/// will not show up as edited
MessageAppendContent{ id: Uuid, content: String }
}
+1
View File
@@ -1,3 +1,4 @@
pub mod auth;
pub mod user;
pub mod space;
pub mod event;
+9
View File
@@ -2,6 +2,7 @@ use crate::api::auth::Session;
use crate::error::ApiResult;
use crate::svc::user_svc::UserService;
use chrono::{DateTime, Utc};
use rocket::serde::{Deserialize, Serialize};
use rocket::State;
use sqlx::FromRow;
use crate::api::totp::TotpStatus;
@@ -20,6 +21,14 @@ pub struct User {
pub updated_at: Option<DateTime<Utc>>,
}
#[derive(Debug, sqlx::Type, Clone, Copy, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "snake_case")]
#[sqlx(type_name = "user_role", rename_all = "lowercase")]
pub enum UserRole {
User,
Admin,
}
// pub struct UserCache {}
//
// impl UserCache {
+35 -23
View File
@@ -1,68 +1,80 @@
use crate::api::chat::ChatMsg;
use crate::model::event::ChatMsg;
use crate::repo::Repo;
use chrono::{DateTime, Utc};
use sqlx::PgPool;
use uuid::Uuid;
#[derive(Clone)]
pub struct MessageRepository {
pool: PgPool
}
impl Repo for MessageRepository {
type Target = ChatMsg;
fn new(pool: PgPool) -> Self {
impl MessageRepository {
pub(crate) fn new(pool: PgPool) -> Self {
Self { pool }
}
// TODO: caching with redis
async fn get_by_id(&self, id: i64) -> Option<Self::Target> {
async fn get_by_id(&self, id: Uuid) -> Option<ChatMsg> {
sqlx::query!(
"SELECT u.username, u.nickname, u.id as user_id, m.content, m.created_at
"SELECT m.id, u.username, u.nickname, u.id as user_id, m.content, m.created_at
FROM messages m
JOIN users u ON m.user_id = u.id
WHERE m.id = $1",
id
).fetch_optional(&self.pool).await.ok().flatten().map(|row| ChatMsg {
id: row.id,
display_name: Some(row.nickname.unwrap_or(row.username)),
user_id: row.user_id,
text: row.content,
timestamp: row.created_at,
})
}
}
impl MessageRepository {
// TODO! caching with redis
pub async fn create_new(
&self, uid: i64, channel_id: i64,
text: &str, created_at: DateTime<Utc>
) -> Result<i64, sqlx::Error> {
&self, msg: ChatMsg, channel_id: i64
) -> Result<(), sqlx::Error> {
sqlx::query!(
"INSERT INTO messages (channel_id, user_id, content, created_at)
VALUES ($1, $2, $3, $4) RETURNING id",
"INSERT INTO messages (id, channel_id, user_id, content, created_at)
VALUES ($1, $2, $3, $4, $5)",
msg.id,
channel_id,
uid,
msg.user_id,
msg.text,
msg.timestamp
).execute(&self.pool).await.map_err(|_| sqlx::Error::RowNotFound)?;
Ok(())
}
pub async fn update_text(&self, id: Uuid, text: &str) -> Result<(), sqlx::Error> {
sqlx::query!(
"UPDATE messages SET content = $1 WHERE id = $2",
text,
created_at
).fetch_optional(&self.pool).await.and_then(|row| row.map(|r| r.id).ok_or(sqlx::Error::RowNotFound))
id
).execute(&self.pool).await?;
Ok(())
}
/// TODO: caching with redis
pub async fn get_by_channel(&self, channel_id: i64, limit: usize)
-> Result<Vec<ChatMsg>, sqlx::Error> {
pub async fn get_latest_by_channel_desc(
&self, channel_id: i64, limit: usize, page: usize
) -> Result<Vec<ChatMsg>, sqlx::Error> {
sqlx::query!(
"SELECT u.username, u.nickname, u.id as user_id, m.content, m.created_at
"SELECT m.id, u.username, u.nickname, u.id as user_id, m.content, m.created_at
FROM messages m
JOIN users u ON m.user_id = u.id
WHERE m.channel_id = $1
ORDER BY m.created_at DESC LIMIT $2",
ORDER BY m.created_at DESC
LIMIT $2 OFFSET $3",
channel_id,
limit as i64
limit as i64,
page as i64
).fetch_all(&self.pool).await.map(|messages| {
messages.into_iter().rev().map(|msg| {
messages.into_iter().map(|msg| {
ChatMsg {
id: msg.id,
display_name: Some(msg.nickname.unwrap_or(msg.username)),
user_id: msg.user_id,
text: msg.content,
+15 -1
View File
@@ -1,5 +1,5 @@
use crate::repo::{UserRepo, AccessTokenRepoTrait};
use crate::model::user::User;
use crate::model::user::{User, UserRole};
use crate::model::auth::AccessToken;
use rocket::async_trait;
use std::sync::Mutex;
@@ -59,6 +59,20 @@ impl UserRepo for MockUserRepo {
}
Ok(())
}
async fn is_admin(&self, uid: i64) -> Result<UserRole, Error> {
let user = self.users.lock().unwrap().iter().find(|u| u.id == uid).cloned();
if let Some(user) = user {
if user.id == 1 {
return Ok(UserRole::Admin);
} else {
return Ok(UserRole::User);
}
}
panic!("user not found in test")
}
async fn new_user(&self, email: &str, username: &str, pass_hash: &str) -> Result<i64, sqlx::Error> {
let mut users = self.users.lock().unwrap();
let id = users.len() as i64 + 1;
+3 -1
View File
@@ -1,5 +1,5 @@
use crate::model::auth::AccessToken;
use crate::model::user::User;
use crate::model::user::{User, UserRole};
use chrono::{DateTime, Utc};
use crate::api::totp::TotpStatus;
use crate::model::space::Space;
@@ -25,6 +25,8 @@ pub trait UserRepo: Send + Sync {
async fn get_by_id(&self, id: i64) -> Option<User>;
async fn save(&self, user: &User) -> Result<(), sqlx::Error>;
async fn new_user(&self, email: &str, username: &str, pass_hash: &str) -> Result<i64, sqlx::Error>;
async fn is_admin(&self, uid: i64) -> Result<UserRole, sqlx::Error>;
async fn get_by_username(&self, username: &str) -> Result<Option<User>, sqlx::Error>;
async fn delete_by_id(&self, id: i64) -> Result<(), sqlx::Error>;
async fn set_display_name(&self, id: i64, display_name: Option<String>) -> Result<(), sqlx::Error>;
+11 -1
View File
@@ -1,7 +1,8 @@
use crate::repo::{Repo, UserRepo};
use crate::model::user::User;
use crate::model::user::{User, UserRole};
use sqlx::PgPool;
use crate::api::totp::TotpStatus;
use crate::model::user::UserRole::Admin;
#[derive(Clone)]
pub struct UserRepository {
@@ -66,6 +67,15 @@ impl UserRepo for UserRepository {
Ok(())
}
async fn is_admin(&self, uid: i64) -> Result<UserRole, sqlx::Error> {
sqlx::query!(
"SELECT role AS \"user_role!: UserRole\" FROM users WHERE id = $1", uid
)
.fetch_one(&self.pool)
.await
.map(|row| row.user_role)
}
async fn new_user(&self, email: &str, username: &str, passhash: &str) -> Result<i64, sqlx::Error> {
sqlx::query!(
"INSERT INTO users (email, username, passhash) VALUES ($1, $2, $3) RETURNING id",
+5
View File
@@ -10,6 +10,7 @@ use argon2::{Argon2, PasswordHash, PasswordHasher, PasswordVerifier};
use chrono::{DateTime, Utc};
use uuid::Uuid;
use crate::api::totp::TotpStatus::{Disabled, Enabled};
use crate::model::user::UserRole::Admin;
use crate::svc::access_token_svc::AccessTokenService;
#[derive(Clone)]
@@ -103,6 +104,10 @@ impl AuthService {
})
}
pub async fn is_admin(&self, uid: i64) -> ApiResult<bool> {
Ok(self.users.is_admin(uid).await? == Admin)
}
pub async fn get_totp_status(&self, uid: i64) -> ApiResult<bool> {
Ok(
self.users.get_totp_secret(uid).await?.is_some()
+106 -44
View File
@@ -1,12 +1,15 @@
use crate::api::chat::ChatMsg;
use crate::model::event::{ChatEvent, ChatMsg};
use crate::error::{ApiResult, AppError};
use crate::repo::message_repo::MessageRepository;
use crate::repo::{ChannelRepo, Repo, SpaceRepo, UserRepo};
use chrono::{DateTime, Utc};
use std::collections::HashMap;
use std::collections::{HashMap, VecDeque};
use std::sync::Arc;
use std::sync::mpsc::channel;
use std::time::Instant;
use tokio::sync::broadcast::Sender;
use tokio::sync::{broadcast, Mutex};
use uuid::Uuid;
use crate::model::space::SpaceDto;
use crate::svc::llm_service::LlmService;
@@ -15,15 +18,13 @@ use crate::svc::llm_service::LlmService;
#[derive(Clone)]
pub struct ChatService {
users: Arc<dyn UserRepo>,
channels: Arc<dyn ChannelRepo>,
channel_repo: Arc<dyn ChannelRepo>,
spaces: Arc<dyn SpaceRepo>,
messages: MessageRepository,
llm: LlmService,
buffer_size: usize,
senders: Arc<Mutex<HashMap<i64, Sender<ChatMsg>>>>,
channels: Arc<Mutex<HashMap<i64, ChannelState>>>,
}
impl ChatService {
@@ -33,13 +34,13 @@ impl ChatService {
channels: Arc<dyn ChannelRepo>, spaces: Arc<dyn SpaceRepo>,
) -> Self {
Self {
channels,
channel_repo: channels,
spaces,
llm,
users,
messages,
buffer_size,
senders: Arc::new(Mutex::new(std::collections::HashMap::new())),
channels: Arc::new(Mutex::new(std::collections::HashMap::new())),
}
}
@@ -50,7 +51,7 @@ impl ChatService {
let mut result = Vec::new();
for space in spaces {
let channels = self.channels.get_by_space_id(space.id).await?;
let channels = self.channel_repo.get_by_space_id(space.id).await?;
result.push(SpaceDto {
channels,
id: space.id,
@@ -65,8 +66,10 @@ impl ChatService {
Ok(result)
}
pub async fn get_messages(&self, channel_id: i64, limit: usize) -> ApiResult<Vec<ChatMsg>> {
let messages = self.messages.get_by_channel(channel_id, limit).await?;
pub async fn fetch_latest_messages_desc(&self, channel_id: i64, limit: usize) -> ApiResult<Vec<ChatMsg>> {
const PAGE: usize = 0;
let messages = self.messages.get_latest_by_channel_desc(channel_id, limit, PAGE).await?;
Ok(messages)
}
@@ -113,6 +116,7 @@ impl ChatService {
.ok_or(AppError::NotFound)?;
let message = ChatMsg {
id: Uuid::new_v4(),
display_name: Some(user
.nickname.clone()
.unwrap_or_else(|| user.username.clone())),
@@ -122,66 +126,124 @@ impl ChatService {
};
self.publish(channel_id, message.clone()).await;
let _msg_id = self.messages.create_new(uid, channel_id, text, created_at).await?;
self.messages.create_new(message.clone(), channel_id).await?;
// TODO: caching w redis at repository layer
let svc_instance = self.clone();
let Some(text) = text.strip_prefix("/ask ") else {
return Ok(())
};
if !svc_instance.llm.enabled() {
return Ok(())
if !message.text.starts_with("/ask ") {
return Ok(());
}
let svc_instance = self.clone();
if !svc_instance.llm.enabled() {
return Ok(());
}
let context = self.get_history(channel_id, 25).await?;
tokio::spawn(async move {
let sender = match svc_instance.channels.lock().await.get(&channel_id) {
Some(s) => s.get_sender(),
None => return,
};
let response = svc_instance.llm
.query(&message)
.query(&message, &context, sender)
.await;
if let Ok(reply) = response {
let Ok(reply) = response else {
tracing::warn!("Error contacting LLM: {:?}", response);
return;
};
tracing::info!("LLM reply: {}", reply.text);
svc_instance.publish(channel_id, reply.clone()).await;
// TODO: cache response (or do with redis!)
if let Err(e) = svc_instance.messages
.create_new(reply.user_id, channel_id, &reply.text, reply.timestamp).await {
if let Err(e) = svc_instance.messages.create_new(reply, channel_id).await {
tracing::error!("Failed to persist LLM reply: {}", e);
}
tracing::info!("LLM reply persisted");
} else {
tracing::warn!("Error contacting LLM: {:?}", response);
}
tracing::debug!("Full LLM reply persisted");
});
Ok(())
}
async fn get_history(&self, channel_id: i64, limit: usize) -> ApiResult<Vec<ChatMsg>> {
let mut map = self.channels.lock().await;
if let Some(channel) = map.get(&channel_id) && !channel.cache.is_empty() {
Ok(channel.history().clone().into_iter().take(limit).collect())
} else {
let messages: Vec<_> = self.messages.get_latest_by_channel_desc(channel_id, limit, 0).await?.into_iter().rev().collect();
map.insert(channel_id,
ChannelState::new(self.buffer_size, Some(messages.clone().into()))
);
Ok(messages)
}
}
/// Subscribe to the specified channel.
pub async fn subscribe(&self, channel_id: i64) -> broadcast::Receiver<ChatMsg> {
let mut map = self.senders.lock().await;
let sender = map
pub async fn subscribe(&self, channel_id: i64) -> broadcast::Receiver<ChatEvent> {
let mut map = self.channels.lock().await;
let channel = map
.entry(channel_id)
.or_insert_with(|| broadcast::channel::<ChatMsg>(self.buffer_size).0);
sender.subscribe()
.or_insert_with(|| ChannelState::new(self.buffer_size, None));
channel.subscribe()
}
// Private helper methods
/// Publish a message to the specified channel.
async fn publish(&self, channel_id: i64, msg: ChatMsg) {
let mut map = self.senders.lock().await;
let sender = map
let mut map = self.channels.lock().await;
let channel = map
.entry(channel_id)
.or_insert_with(|| broadcast::channel::<ChatMsg>(self.buffer_size).0);
let _ = sender.send(msg);
.or_insert_with(|| ChannelState::new(self.buffer_size, None));
channel.send(msg);
}
}
#[derive(Clone)]
pub struct ChannelState {
sender: Sender<ChatEvent>,
cache: VecDeque<ChatMsg>,
last_updated: Instant,
}
impl ChannelState {
const MAX_HISTORY_SIZE: usize = 100;
#[must_use]
pub fn new(buffer_size: usize, history: Option<VecDeque<ChatMsg>>) -> Self {
Self {
sender: broadcast::channel(buffer_size).0,
cache: history.unwrap_or_default(),
last_updated: Instant::now(),
}
}
pub fn history(&self) -> &VecDeque<ChatMsg> {
&self.cache
}
pub fn get_sender(&self) -> Sender<ChatEvent> {
self.sender.clone()
}
#[must_use]
pub fn send(&mut self, msg: ChatMsg) {
while self.cache.len() >= Self::MAX_HISTORY_SIZE {
self.cache.pop_front();
}
self.cache.push_back(msg.clone());
if self.sender.send(ChatEvent::SendMessage(msg)).is_err() {
tracing::warn!("Sent message to channel with no subscribers");
}
}
#[must_use]
pub fn subscribe(&self) -> broadcast::Receiver<ChatEvent> {
self.sender.subscribe()
}
}
+120 -42
View File
@@ -1,3 +1,13 @@
use std::env;
use std::sync::LazyLock;
use futures_util::StreamExt;
use serde::{Deserialize, Serialize};
use tokio::sync::broadcast::Sender;
use uuid::Uuid;
use crate::model::event::{ChatEvent, ChatMsg};
use crate::error::{ApiResult, AppError};
#[derive(Clone)]
pub struct LlmService;
@@ -15,71 +25,139 @@ impl LlmService {
LMSTUDIO_URL.is_some()
}
pub async fn query(&self, message: &ChatMsg) -> ApiResult<ChatMsg> {
pub async fn query(&self, message: &ChatMsg, context: &[ChatMsg], sender: Sender<ChatEvent>) -> ApiResult<ChatMsg> {
let Some(url) = LMSTUDIO_URL.clone() else {
return Err(AppError::internal("AI not enabled!"))
};
let model = LMSTUDIO_MODEL.clone().unwrap_or_else(|| "gpt-oss-20b".into());
let client = reqwest::Client::new();
// Build the request body
let payload = LlmRequest {
model, // whatever model you run locally
messages: vec![Message {
role: "user".into(),
content: message.text.clone(),
}],
let reply_id = Uuid::new_v4();
let timestamp = chrono::Utc::now();
let mut reply = ChatMsg {
id: reply_id,
display_name: Some("llm".into()),
user_id: 0,
text: String::new(),
timestamp,
};
let _ = sender.send(ChatEvent::SendMessage(reply.clone()));
// POST to lmstudio (default 127.0.0.1:1234)
let resp = client
let mut messages: Vec<Message> = Vec::new();
let system_prompt = format!(
"You are a helpful assistant in a group chat. \
You are talking to '{}'. \
Keep responses concise and conversational.",
message.display_name.as_deref().unwrap_or("unknown"),
);
messages.push(Message { role: "system".into(), content: system_prompt });
for msg in context {
let role = if msg.user_id == 0 {
"assistant" // your LLM user_id convention
} else {
"user"
};
messages.push(Message {
role: role.into(),
content: format!(
"{}: {}",
msg.display_name.as_deref().unwrap_or("unknown"),
msg.text
),
});
}
messages.push(Message {
role: "user".into(),
content: format!(
"{}: {}",
message.display_name.as_deref().unwrap_or("unknown"),
message.text.trim_start_matches("/ask ") // strip the command prefix
),
});
let Ok(resp) = reqwest::Client::new()
.post(url)
.json(&payload)
.json(&LlmRequest {
think: false,
model: LMSTUDIO_MODEL
.clone()
.unwrap_or_else(|| "gpt-oss-20b".into()),
messages,
stream: true,
})
.send()
.await
.map_err(|_| AppError::internal("Failed to make request to LLM server"))?;
else {
tracing::warn!("Failed to reach LLM");
let _ = sender.send(ChatEvent::MessageAppendContent {
id: reply_id,
content: String::from("I'm not available right now. Please try again later.")
});
return Err(AppError::internal("Failed to reach LLM"));
};
// The API returns a JSON with `choices[].message.content`
#[derive(Deserialize)]
struct LlmResponse {
choices: Vec<Choice>,
}
#[derive(Deserialize)]
struct Choice {
message: Message,
let mut full_text = String::new();
let mut buffer = String::new();
let mut stream = resp.bytes_stream();
while let Some(chunk) = stream.next().await {
let chunk = chunk.map_err(|_| AppError::internal("Stream error"))?;
buffer.push_str(&String::from_utf8_lossy(&chunk));
while let Some(pos) = buffer.find('\n') {
let line = buffer[..pos].trim().to_string();
buffer = buffer[pos + 1..].to_string();
if line == "data: [DONE]" {
break;
}
let llm_resp: LlmResponse = resp
.json()
.await
.map_err(|_| AppError::internal("Failed to parse LLM response"))?;
Ok(ChatMsg {
display_name: Some(String::from("llm")),
user_id: 0,
text: llm_resp.choices[0].message.content.clone(),
timestamp: chrono::Utc::now(),
})
if let Some(json) = line.strip_prefix("data: ")
&& let Ok(parsed) = serde_json::from_str::<StreamingResponse>(json)
&& let Some(content) = parsed.choices[0].delta.content.as_ref() {
full_text.push_str(content);
let _ = sender.send(ChatEvent::MessageAppendContent {
id: reply_id,
content: content.clone(),
});
}
}
}
reply.text = full_text;
Ok(reply)
}
}
use std::env;
use std::sync::LazyLock;
// src/llm.rs
use serde::{Deserialize, Serialize};
use crate::api::chat::ChatMsg;
use crate::error::{ApiResult, AppError};
use crate::svc::chat_svc::ChatService;
#[derive(Serialize)]
struct LlmRequest {
model: String,
messages: Vec<Message>,
stream: bool,
think: bool,
}
#[derive(Deserialize)]
struct StreamingResponse {
choices: Vec<StreamingChoice>,
}
#[derive(Deserialize)]
struct StreamingChoice {
delta: Delta,
#[serde(default)]
finish_reason: Option<String>,
}
#[derive(Deserialize)]
struct Delta {
#[serde(default)]
content: Option<String>,
}
#[derive(Serialize, Deserialize)]
struct Message {
role: String, // "user" or "assistant"
+1
View File
@@ -4,3 +4,4 @@ pub mod settings_svc;
pub mod user_svc;
pub mod access_token_svc;
pub mod llm_service;
pub mod relationship_svc;
+6
View File
@@ -0,0 +1,6 @@
pub struct RelationshipService {}
impl RelationshipService {
pub fn new() -> Self { Self {} }
}
-935
View File
@@ -1,935 +0,0 @@
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
background: #0a0a0a;
color: #e0e0e0;
max-height: 100dvh;
min-width: 100dvw;
height: 100dvh;
overflow: hidden;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
background: #0a0a0a;
color: #e0e0e0;
display: flex;
align-items: center;
justify-content: center;
}
.app-container {
display: flex;
width: 100%;
height: 100vh;
}
/* Chat Container */
.chat-container {
display: flex;
flex-direction: column;
flex: 1;
height: 100dvh;
background: #121212;
position: relative;
overflow: hidden;
}
/* Chat Header */
.chat-header {
padding: 10px;
background: #1a1a1a;
border-bottom: 1px solid #252525;
display: flex;
align-items: center;
gap: 10px;
}
.chat-title {
display: flex;
align-items: center;
gap: 12px;
flex: 1;
}
.status-dot {
width: 10px;
height: 10px;
background: #ff4444;
border-radius: 50%;
animation: pulse 2s infinite;
}
@keyframes pulse {
0%,
100% {
transform: scale(1);
opacity: 1;
}
50% {
transform: scale(1.3);
opacity: 0.7;
}
}
.chat-title h1 {
font-size: 17px;
font-weight: 600;
color: #ffffff;
}
/* Live Location Notification Bubble */
.notification-container {
padding: 15px 20px 10px 20px;
display: flex;
flex-direction: column;
gap: 10px;
position: absolute;
top: 70px;
left: 0;
right: 0;
z-index: 10;
pointer-events: none;
}
.live-location-bubble {
padding: 0;
border-radius: 20px;
position: relative;
overflow: hidden;
cursor: pointer;
transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
border: 1px solid rgba(138, 43, 226, 0.3);
box-shadow:
0 8px 32px rgba(106, 90, 205, 0.2),
inset 0 1px 0 rgba(255, 255, 255, 0.1);
pointer-events: auto;
max-height: 64px;
background: transparent;
}
.live-location-bubble::before {
content: "";
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: linear-gradient(
135deg,
rgba(106, 90, 205, 0.25) 0%,
rgba(72, 61, 139, 0.2) 50%,
rgba(123, 104, 238, 0.15) 100%
);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
z-index: 0;
}
.live-location-bubble.expanded::before {
opacity: 0;
}
.live-location-bubble > * {
position: relative;
z-index: 1;
}
.live-location-bubble.expanded {
max-height: 400px;
cursor: default;
}
.map-container {
width: 100%;
height: 0;
opacity: 0;
transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
overflow: hidden;
}
.live-location-bubble.expanded .map-container {
height: 260px;
opacity: 1;
}
.map-container img {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
}
.location-content {
display: flex;
align-items: center;
gap: 12px;
padding: 16px 20px;
background: linear-gradient(
135deg,
rgba(106, 90, 205, 0.25) 0%,
rgba(72, 61, 139, 0.2) 50%,
rgba(123, 104, 238, 0.15) 100%
);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
}
.live-location-bubble.expanded .location-content {
background: linear-gradient(
to bottom,
rgba(106, 90, 205, 0.45) 0%,
rgba(72, 61, 139, 0.4) 50%,
rgba(123, 104, 238, 0.35) 100%
);
}
.location-content {
display: flex;
align-items: center;
gap: 12px;
}
.live-location-bubble::before {
content: "";
position: absolute;
top: 0;
left: 0;
right: 0;
height: 1px;
background: linear-gradient(
90deg,
transparent,
rgba(255, 255, 255, 0.2),
transparent
);
}
.live-location-bubble:hover {
transform: translateY(-2px);
box-shadow:
0 12px 40px rgba(106, 90, 205, 0.35),
inset 0 1px 0 rgba(255, 255, 255, 0.15);
background: linear-gradient(
135deg,
rgba(106, 90, 205, 0.3) 0%,
rgba(72, 61, 139, 0.25) 50%,
rgba(123, 104, 238, 0.2) 100%
);
}
.live-location-bubble.active {
background: linear-gradient(
135deg,
rgba(106, 90, 205, 0.35) 0%,
rgba(72, 61, 139, 0.3) 50%,
rgba(123, 104, 238, 0.25) 100%
);
border-color: rgba(138, 43, 226, 0.5);
}
.location-content {
display: flex;
align-items: center;
gap: 12px;
}
.location-icon {
width: 32px;
height: 32px;
background: rgba(255, 255, 255, 0.15);
backdrop-filter: blur(10px);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
border: 1px solid rgba(255, 255, 255, 0.2);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
transition: all 0.3s ease;
flex-shrink: 0;
}
.location-icon svg {
width: 18px;
height: 18px;
fill: #ea4335;
filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.3));
}
.live-location-bubble.expanded .location-icon {
display: none;
}
.join-button {
display: none;
padding: 8px 20px;
background: rgba(255, 255, 255, 0.15);
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.2);
border-radius: 20px;
color: #ffffff;
font-size: 14px;
font-weight: 600;
cursor: pointer;
transition: all 0.2s ease;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
flex-shrink: 0;
}
.live-location-bubble.expanded .join-button {
display: block;
}
.join-button:hover {
background: rgba(255, 255, 255, 0.25);
transform: scale(1.05);
}
.join-button:active {
transform: scale(0.95);
}
.join-button.active {
background: rgba(106, 90, 205, 0.4);
border-color: rgba(138, 43, 226, 0.5);
}
.live-location-bubble.active .location-icon {
background: rgba(255, 255, 255, 0.25);
}
.location-text {
font-size: 15px;
font-weight: 600;
color: #ffffff;
flex: 1;
letter-spacing: 0.3px;
}
.location-users {
display: flex;
align-items: center;
}
.location-user-pic {
width: 32px;
height: 32px;
border-radius: 35%;
margin-left: -15px;
position: relative;
z-index: 1;
transition: all 0.2s ease;
}
.location-user-pic:first-child {
margin-left: 0;
}
.location-user-pic:hover {
z-index: 10;
transform: scale(1.15);
}
.location-count {
width: 32px;
height: 32px;
border-radius: 35%;
background: rgba(0, 0, 0, 0.5);
backdrop-filter: blur(10px);
margin-left: -15px;
display: flex;
align-items: center;
justify-content: center;
font-size: 10px;
font-weight: 600;
color: #ffffff;
z-index: 2;
}
.messages-container::before {
content: "";
flex: 1 0 auto;
}
/* Messages Container */
.messages-container {
display: flex;
flex-direction: column;
/*justify-content: flex-end;*/
flex: 1;
padding: 15px;
gap: 15px;
overflow-y: scroll;
background: #121212;
}
.message {
margin: 0;
padding: 10px 10px;
border-radius: 10px;
background: rgba(30, 30, 30, 0.4);
backdrop-filter: blur(10px);
border: 1px solid #252525;
animation: slideIn 0.3s ease-out;
transition: all 0.2s ease;
display: flex;
gap: 10px;
}
.message:hover {
background: #1f1f1f;
border-color: #2a2a2a;
}
@keyframes slideIn {
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.user-avatar {
width: 48px;
height: 48px;
border-radius: 25%;
background-size: cover;
border: 2px solid #252525;
flex-shrink: 0;
}
.user-avatar.blue {
background: linear-gradient(135deg, #4169e1, #6495ed);
}
.message-content {
flex: 1;
min-width: 0;
}
.message-header {
display: flex;
align-items: baseline;
gap: 8px;
margin-bottom: 4px;
}
.username {
font-weight: 600;
font-size: 15px;
color: #e0e0e0;
}
.timestamp {
font-size: 11px;
color: #666;
font-weight: 400;
}
.message-text {
font-size: 14px;
color: #b0b0b0;
line-height: 1.4;
word-wrap: break-word;
}
/* Input Container */
.input-container {
padding: 10px;
background: #1a1a1a;
border-top: 1px solid #252525;
}
.input-wrapper {
display: flex;
align-items: center;
gap: 10px;
background: #252525;
border-radius: 10px;
padding: 5px 5px;
border: 1px solid #2a2a2a;
transition: all 0.2s ease;
}
.input-wrapper:focus-within {
background: #2a2a2a;
border-color: #6a5acd;
box-shadow: 0 0 0 3px rgba(106, 90, 205, 0.1);
}
.input-wrapper input {
flex: 1;
background: none;
border: none;
color: #e0e0e0;
font-size: 14px;
outline: none;
}
.input-wrapper input::placeholder {
color: #666;
}
.send-button {
width: 32px;
height: 32px;
background: none;
border-radius: 10px;
border: none;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
font-size: 14px;
transition: all 0.2s ease;
flex-shrink: 0;
}
.send-button:hover {
transform: scale(1.1);
box-shadow: 0 4px 15px rgba(106, 90, 205, 0.4);
background: rgba(255, 255, 255, 0.4);
}
.send-button:active {
transform: scale(0.95);
}
/* Scrollbar styling */
.messages-container::-webkit-scrollbar {
width: 6px;
}
.messages-container::-webkit-scrollbar-track {
background: #1a1a1a;
}
.messages-container::-webkit-scrollbar-thumb {
background: #333;
border-radius: 3px;
}
.messages-container::-webkit-scrollbar-thumb:hover {
background: #444;
}
.signup-container {
width: 100%;
max-width: 480px;
background: #121212;
border-radius: 16px;
overflow: hidden;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
animation: slideIn 0.4s ease-out;
}
@keyframes slideIn {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.signup-header {
padding: 40px 40px 30px;
text-align: center;
background: linear-gradient(
135deg,
rgba(106, 90, 205, 0.15) 0%,
rgba(72, 61, 139, 0.1) 100%
);
border-bottom: 1px solid #252525;
}
.logo {
width: 80px;
height: 80px;
margin: 0 auto 20px;
background: linear-gradient(135deg, #6a5acd, #483d8b);
border-radius: 25%;
display: flex;
align-items: center;
justify-content: center;
font-size: 36px;
font-weight: bold;
color: #ffffff;
box-shadow: 0 4px 16px rgba(106, 90, 205, 0.3);
}
.signup-header h1 {
font-size: 28px;
font-weight: 600;
color: #ffffff;
margin-bottom: 8px;
}
.signup-header p {
font-size: 14px;
color: #888;
}
.signup-form {
padding: 40px;
}
.form-group {
margin-bottom: 24px;
}
.form-group label {
display: block;
font-size: 13px;
font-weight: 600;
color: #b0b0b0;
margin-bottom: 8px;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.input-wrapper {
position: relative;
}
.form-group input {
width: 100%;
padding: 12px 16px;
background: #1a1a1a;
border: 1px solid #252525;
border-radius: 8px;
color: #e0e0e0;
font-size: 15px;
transition: all 0.2s ease;
outline: none;
}
.form-group input:focus {
background: #1f1f1f;
border-color: #6a5acd;
box-shadow: 0 0 0 3px rgba(106, 90, 205, 0.1);
}
.form-group input::placeholder {
color: #555;
}
.error-message {
display: none;
margin-top: 8px;
font-size: 12px;
color: #ff4444;
}
.form-group.error input {
border-color: #ff4444;
}
.form-group.error .error-message {
display: block;
}
.password-toggle {
position: absolute;
right: 12px;
top: 50%;
transform: translateY(-50%);
background: none;
border: none;
color: #666;
cursor: pointer;
padding: 4px;
font-size: 12px;
transition: color 0.2s ease;
}
.password-toggle:hover {
color: #888;
}
.submit-button {
width: 100%;
padding: 14px;
background: linear-gradient(135deg, #6a5acd, #483d8b);
border: none;
border-radius: 8px;
color: #ffffff;
font-size: 16px;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
box-shadow: 0 4px 16px rgba(106, 90, 205, 0.3);
margin-top: 8px;
}
.submit-button:hover {
background: linear-gradient(135deg, #7b6bd8, #5a4ea0);
transform: translateY(-2px);
box-shadow: 0 6px 20px rgba(106, 90, 205, 0.4);
}
.submit-button:active {
transform: translateY(0);
}
.submit-button:disabled {
background: #2a2a2a;
color: #555;
cursor: not-allowed;
transform: none;
box-shadow: none;
}
.signup-footer {
padding: 20px 40px 30px;
text-align: center;
font-size: 14px;
color: #666;
}
.signup-footer a {
color: #6a5acd;
text-decoration: none;
font-weight: 600;
transition: color 0.2s ease;
}
.signup-footer a:hover {
color: #7b6bd8;
text-decoration: underline;
}
.success-message {
display: none;
padding: 16px;
background: rgba(76, 175, 80, 0.1);
border: 1px solid rgba(76, 175, 80, 0.3);
border-radius: 8px;
color: #4caf50;
font-size: 14px;
margin-bottom: 20px;
text-align: center;
}
.success-message.show {
display: block;
animation: slideIn 0.3s ease-out;
}
.loading-spinner {
display: inline-block;
width: 16px;
height: 16px;
border: 2px solid rgba(255, 255, 255, 0.3);
border-top-color: #ffffff;
border-radius: 50%;
animation: spin 0.6s linear infinite;
margin-right: 8px;
vertical-align: middle;
}
@keyframes spin {
to {
transform: rotate(360deg);
}
}
.checkbox-group {
display: flex;
align-items: flex-start;
gap: 10px;
margin-bottom: 24px;
}
.checkbox-group input[type="checkbox"] {
width: 18px;
height: 18px;
margin-top: 2px;
cursor: pointer;
accent-color: #6a5acd;
}
.checkbox-group label {
font-size: 13px;
color: #888;
line-height: 1.5;
text-transform: none;
letter-spacing: normal;
font-weight: 400;
}
.checkbox-group a {
color: #6a5acd;
text-decoration: none;
}
.checkbox-group a:hover {
text-decoration: underline;
}
/* Sidebar Styles */
.sidebar {
width: 240px;
min-width: 180px;
max-width: 400px;
background: #0f0f0f;
display: flex;
flex-direction: column;
border-right: 1px solid #252525;
position: relative;
transition:
margin-left 0.3s ease,
opacity 0.3s ease;
}
.sidebar.hidden {
margin-left: -240px;
opacity: 0;
pointer-events: none;
}
.resize-handle {
position: absolute;
right: 0;
top: 0;
bottom: 0;
width: 4px;
cursor: ew-resize;
background: transparent;
transition: background 0.2s ease;
z-index: 10;
}
.resize-handle:hover {
background: rgba(106, 90, 205, 0.5);
}
.resize-handle:active {
background: #6a5acd;
}
.sidebar-header {
padding: 16px;
border-bottom: 1px solid #252525;
background: #1a1a1a;
color: #ffffff;
font-weight: 600;
font-size: 15px;
letter-spacing: 0.3px;
}
.channels-list {
flex: 1;
overflow-y: auto;
padding: 10px 8px;
}
.channel-item {
padding: 10px 12px;
margin: 3px 0;
border-radius: 8px;
color: #b0b0b0;
cursor: pointer;
transition: all 0.2s ease;
display: flex;
align-items: center;
gap: 10px;
border: 1px solid transparent;
background: rgba(30, 30, 30, 0.3);
}
.channel-item:hover {
background: rgba(30, 30, 30, 0.6);
border-color: #2a2a2a;
color: #e0e0e0;
transform: translateX(2px);
}
.channel-item.active {
background: rgba(106, 90, 205, 0.15);
border-color: rgba(106, 90, 205, 0.3);
color: #ffffff;
box-shadow: 0 2px 8px rgba(106, 90, 205, 0.2);
}
.channel-icon {
font-size: 18px;
font-weight: 600;
color: #666;
flex-shrink: 0;
}
.channel-item:hover .channel-icon {
color: #888;
}
.channel-item.active .channel-icon {
color: #6a5acd;
}
.channel-name {
font-size: 14px;
font-weight: 500;
}
/* Scrollbar styling for sidebar */
.channels-list::-webkit-scrollbar {
width: 6px;
}
.channels-list::-webkit-scrollbar-track {
background: #0f0f0f;
}
.channels-list::-webkit-scrollbar-thumb {
background: #252525;
border-radius: 3px;
}
.channels-list::-webkit-scrollbar-thumb:hover {
background: #333;
}
.sidebar-toggle {
width: 32px;
height: 32px;
background: rgba(30, 30, 30, 0.6);
border: 1px solid #2a2a2a;
border-radius: 6px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.2s ease;
flex-shrink: 0;
color: #b0b0b0;
font-size: 18px;
}
.sidebar-toggle:hover {
background: rgba(106, 90, 205, 0.2);
border-color: rgba(106, 90, 205, 0.3);
color: #e0e0e0;
transform: scale(1.05);
}
.sidebar-toggle:active {
transform: scale(0.95);
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.
-169
View File
@@ -1,169 +0,0 @@
## Subresource Integrity
If you are loading Highlight.js via CDN you may wish to use [Subresource Integrity](https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity) to guarantee that you are using a legimitate build of the library.
To do this you simply need to add the `integrity` attribute for each JavaScript file you download via CDN. These digests are used by the browser to confirm the files downloaded have not been modified.
```html
<script
src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/highlight.min.js"
integrity="sha384-5xdYoZ0Lt6Jw8GFfRP91J0jaOVUq7DGI1J5wIyNi0D+eHVdfUwHR4gW6kPsw489E"></script>
<!-- including any other grammars you might need to load -->
<script
src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/languages/go.min.js"
integrity="sha384-HdearVH8cyfzwBIQOjL/6dSEmZxQ5rJRezN7spps8E7iu+R6utS8c2ab0AgBNFfH"></script>
```
The full list of digests for every file can be found below.
### Digests
```
sha384-gRTR/fmk+6+ygbihH/fJvHgmffnOrd/eO7DW5zgu1uN9GBohtDx+OBs0DI0ejigB /es/languages/bash.js
sha384-Pg7b9hYE6kefjcNqAabhv8jOLCVoZubUaM4bZFjUJd0CaaQ14ksDI0GVllMtAF4S /es/languages/bash.min.js
sha384-xhohaHGp8S443Qn4JZUYAcKqIIl0bQkFA79EUxpbX8GWb5oufdvvSI9ipl/Dasev /es/languages/c.js
sha384-xaTVEdq02jgKStoYDcZD8NhTN1XV/TWpIu4OM53MtMiLl08+e9YJNENo+R/6Nwp0 /es/languages/c.min.js
sha384-rFCBWxbZHxZD51qKR2cdayIcKUSHS3p1PWPIs1kjgsP7lu9ZP32ah/2DoQUm/rTg /es/languages/cpp.js
sha384-+1Koxl0St78gEZW5CpFK+dbLp7yNsfwLzzQUsSGimV4k/RVJUz6YvqtsqtdbJyKf /es/languages/cpp.min.js
sha384-0s8f7nphuRu8IIkFNCeOVZhvbjt7YKZEHl38OjfkCkdtnwIUvwRNbxxUHkCdcYjm /es/languages/csharp.js
sha384-xLfGW0hIBHie9xNFuVroNihI0BdEO8FKxOeCdyJBrO1eM7s5BsQ8F3fLtFydQZ+Z /es/languages/csharp.min.js
sha384-Gmvct15f4Mo9AXQG5bk5w78N1YjBLXXU3KIV7no+mOVnApXlwfw1dwjfueAwljIV /es/languages/css.js
sha384-1D7DbOic0Z5nM2ldSO9O/EsBfsg/5x7X7So1qnMgscI2ucDevptcg7cTvrD9rL0D /es/languages/css.min.js
sha384-CxgzMCYCdPS3oPSgukCqpDiqHKDKcrLdlyMqy9UF73u63+XVRlI32OproboitNa6 /es/languages/diff.js
sha384-joI34L4jMJOgkz6zOb3sqraHH5tmocRfXvs9HkdHfUpD3ceSxAqKlubpBT/4Q/sV /es/languages/diff.min.js
sha384-y5tpDG/EgM93k2unGm4XFn8l9V12Ru1tnk2TxhduZWqrEqAK86BQlDLuVAILe3OB /es/languages/go.js
sha384-/UGh0AcfdC41Di2LsNVYCPOJ24RfaUWWXniaZoGuM52DaQR7fwStKAHJumI+u5yY /es/languages/go.min.js
sha384-opjEyp4yq3g7Bxr5w5ZcG0+fTUsnOc798DWlLPzWPFIV+qGmKGkzzZIAr3822+oQ /es/languages/graphql.js
sha384-ycqZEp/d+8Lmf+CQrUvmfgcQkd5TJPU36i1WFGNiK18rlap/VJSTcPfSj/ft5Faf /es/languages/graphql.min.js
sha384-vZWLk+C+23/W/GAmv4PXkZSZo82LXul6DdSgWcMzutPxGltitIk38HyLrxRVsFvm /es/languages/ini.js
sha384-CVynu7LzwkkAUiajSi0jprssYhgg9Vi1WSd8iR84Vmi6JdRGq3DT4vvEfjzoxxOK /es/languages/ini.min.js
sha384-lk+aAr+DNq8Rz3hXPSZ7ga38GS+tQfXDvexuUnyDCSju1t1SAsLipVIFGlRtcUjE /es/languages/java.js
sha384-5GpB6kfA2w03pZhAUmmNSYvR5pLvne/Rzqc22BmHv+t9ES7ifMX/ZE7x5TBeqW4d /es/languages/java.min.js
sha384-g7t9fKR5Tvod4iWv7BQXN+/JMn5GT9sD6FG3h7Fgl+KCv5k4NnnCzEqUe7BMJ9Mv /es/languages/javascript.js
sha384-f7huPivS1dV2T5V+g0aJpgsY7WBHWCsioIq30tpNoXGizD65fWJYGuXXVPNI52VB /es/languages/javascript.min.js
sha384-8CRS96Xb/ZkZlQU+5ffA03XTN6/xY40QAnsXKB0Y+ow1vza1LAkRNPSrZqGSNo53 /es/languages/json.js
sha384-UHzaYxI/rAo84TEK3WlG15gVfPk49XKax76Ccn9qPWYbUxePCEHxjGkV+xp9HcS/ /es/languages/json.min.js
sha384-74O59Gvm0duu3aXH7S8RHhqn8YvAF1JlgCdNDq5MaClY/f/0bMs4zryv55Whwp2c /es/languages/kotlin.js
sha384-+aJFpyNBGTRiXRDN6BLrctauQBKExwSosxOiHLUYReXKTsckW/RgMavqX6W+zTBL /es/languages/kotlin.min.js
sha384-LRBDaxnf3ea3MTosn2yHFNe+ECfow/i4s71k6UdzkNOS1QvgHkcqRBTkDZC5aEoP /es/languages/less.js
sha384-EJ7n9HlCUKgtcBomJlrocJe2M2WegUc2r/TqymQdykuxcLeA25bQ5665qN58BWki /es/languages/less.min.js
sha384-5TnIBSbRIGDilxscXgaTNLZ8PZ9u7TEBPzF8b9z+wrbTN3e89MbD9zSSuDVdbDFj /es/languages/lua.js
sha384-HCBq0pjgKyOc3FNX31to33MxfNYza3HCbHLfWwdsnkH5r/VmmXTlRrvWSHTJyYvA /es/languages/lua.min.js
sha384-gXOyhc1mLm8alPswShRUsxnBadQf2AOcdpmFVqkKSZBNS07kTOHb3DDepD3Rf9eH /es/languages/makefile.js
sha384-iagI2W32nmVJq2EVd59zlgz2bFjR/MC0JRsbcFaeZL2gmvHzzOeyRTpTKGBSKd7q /es/languages/makefile.min.js
sha384-+KkqXkoHKtuOmUzhZ0BjyV0qjljnS+z6i4fELMEg5brFPtmDIog4zZMhylaBTsVi /es/languages/markdown.js
sha384-E7UvgBH6skA1FIOcn3B2c68GtJzrmZlOOC5p/fsxwihTZG/bBedJZu5PC1+kGX7q /es/languages/markdown.min.js
sha384-JoTXwNHosdzUqxg9EepqeL0yHV98o2Fy7EwTtN9awR+5d8T1EQRXmpdHjpRjxkUM /es/languages/objectivec.js
sha384-IA3s+KMOVf9zn8hH1+u4PCkGcunD2O3mNj4y10RDG/Wq7Gs7QWgiH6o01bjXeU1b /es/languages/objectivec.min.js
sha384-uat5CiOqKMoJM3KrhuhZShpWQriLSdeaJ4oT6XQFBg3YWhVDiofp4wa0SnBcV8LQ /es/languages/perl.js
sha384-doJqxKOhDf9Q9JYEBQXrTguSjzwPrbLiXJP2kdBkF+BYRNP55btwz9iH4b95mUTH /es/languages/perl.min.js
sha384-4OPZSHQbxzPqFMOXnndxQ6TZTI/B+J4W9aqTCHxAx/dsPS6GG25kT7wdsf66jJ1M /es/languages/php.js
sha384-VxmvZ2mUpp1EzFijS40RFvIc7vbv/d5PhMxVFG/3HMpVKD4sVvhdV9LThrJDiw9e /es/languages/php.min.js
sha384-Qin+c4lNK1aBTVV9uViy9uCeqaw3milnNPTq/TTWClWsc7ZBMi3kDc4d702bPhbf /es/languages/php-template.js
sha384-/Btu11Y1N5hp8EDB6nZJCif5GWMrSC/bYMh0Re/SH64ZoH2qZRHUtqv1SFRPbNdM /es/languages/php-template.min.js
sha384-i6sPjmXfHWLljAXTYYk0vBOwgsUnUKnKXKH41qzc9OMhaf5AFZqXH7azX4SYdUiR /es/languages/plaintext.js
sha384-OOrQLW97d+/1orj9gjftwbbQyV8LNAcgagqVKBhUYA08Hdi5w0p6VoB3yt2k7gnG /es/languages/plaintext.min.js
sha384-Cmq5lORXzyHraasLNqmfchH07JRXyEmjDF+j6tSggoXjYHwtgX/ySW6kkRytM5uu /es/languages/python.js
sha384-ZV5sgX70bBgLkDR5Mtox5UsbJedBc39hRKPdvTw6miK4lSkE/wv94cLY2iyZb/sB /es/languages/python.min.js
sha384-9jy7CI5TLYs91VYlZ4S0czQFpDsMzc9jakiJ5RqCFZugGpdPglP94JPAyEhMBwJp /es/languages/python-repl.js
sha384-CO+NiDedness48VlHW0FCIw9rQt8szFZ0IOXYiQo3LEAHLytXxM5NlKnmNYBUACQ /es/languages/python-repl.min.js
sha384-vAVurAb8AMWBKPHNWPze2lJa7m/as9wrF1wzH1FQKrJNNqiemBLJi3y6aGdyu5Zt /es/languages/r.js
sha384-WkipJgUBRzr12T7CtL8kF6QTuPHAl8f7Sx1YnmOm3KiVA/k3eDXfifuSvUW9M5nu /es/languages/r.min.js
sha384-JOe8PF7ynaYxu7HI5O0NuVfXMMXYSJlCJqP4TYVNNq0eDKgm/N2dqcmqvp9QfIDu /es/languages/ruby.js
sha384-DpXpbYSP6sX4tcP61ZRjSMsnmF8V3c/hQILWjrGWI2g3lresYaqbxVxs+tioFMJn /es/languages/ruby.min.js
sha384-JFRCn12yvr0NDhxPY8oZDk/G2Tjm7bGmqXy28Y0bq4J7D8mKha6jQJOXMB5wtTVr /es/languages/rust.js
sha384-JbkB8w/DGGyx29PIwSq8c/ZeiJB9T/X4mVAZFEyBiNlEAas98Q2NxpBPUlNIlE71 /es/languages/rust.min.js
sha384-R67rULqIohpEyV6aFbjxRv7xhK8v/KteX4cvOFmPcnZ2MTf65Zua+2DzB9MqqXuO /es/languages/scss.js
sha384-WMy5VYgOMFAnHhPJXVDCQ/Y/QPlUrBqNVPtFH6/gGg2F4uaAowyQ0y/9zWEeGpJe /es/languages/scss.min.js
sha384-1mmBZmAs44b6FtD9wpMiLJa8bLZgZv9xoAhngN6B5Q22y9CtcsU2lat0zlRtyVgy /es/languages/shell.js
sha384-u9PV7oWG/lZlm+GnftX7kn0w4b8rRfFxSv5SmJJPHWKGI03rz6VLqgZdQ1B5ez6b /es/languages/shell.min.js
sha384-s1ZfN6xtlNKAZux8QYAG7upUsit3RwK5XDoCAN3g6Kj33RrIqbmkuGjdNF9RvzPM /es/languages/sql.js
sha384-y25cn06synxhYnlKVprZdpakuFWVrm2jvn8pqiF4L85a05CI/6bNeT2+qXbUYIyW /es/languages/sql.min.js
sha384-sfRYvVvcwsysqkDUscQ/SqsFOSvNGkGX5vm/yKMHdTwTd7A++Pqx1QpJK0bGebPD /es/languages/swift.js
sha384-9NAaCxdhTO7TX6fYeUHyt+NC3ledirZOADyWdinDCTN1taeqj8sLLYqjE8YMf4Na /es/languages/swift.min.js
sha384-Z61gsCS2W7Q+3fT1fdya/Sz4wlmsotT9iEGzgIlNqP0soaKH1NzysutxWp08Hh3E /es/languages/typescript.js
sha384-Tv4mr9B7b+x2IynRXW/xcAxUj1+AoN9zyp0n9BWE1Nle3Zfm/zUeEztNLhIRjgE7 /es/languages/typescript.min.js
sha384-ZXhYu2xIPf1aci2kiX/n0hceCz4WwbJJs3QRE6ZwDXGzHRFWrsaYiQhBQSZ3Sx9K /es/languages/vbnet.js
sha384-ztGjA/YtvuFeKJwRqtrvV+3no91MVzQIzG5kQhHiIndfxmQOAum+vaaaDfA8Mg8U /es/languages/vbnet.min.js
sha384-82eHXc3kQTsEJ65AcO2c8eVqB9ynJzosSiMwdPYwt5oNRVsMKuxWoWkO5KFekVYB /es/languages/wasm.js
sha384-YBbT3eXpwj5Ddx0MS774iycYICw4gZ1Rs1ExYGIdcYC4EJhaWsfd9uNlaJZBuDaa /es/languages/wasm.min.js
sha384-9ECFzM+oWDye4s/MFx3QUXGo4mW43+SyLpWUDeQtWup6GZJ+KHFxVS89PmZt/fzl /es/languages/xml.js
sha384-PQrsaWeWrBiE1CFRw8K335CaJuQRTjDGm73vn8bXvlwaw6RyqWObdvMTBS8B75NN /es/languages/xml.min.js
sha384-7HTgKp/l2rzlyrh5vUfbfZVy+Wx1lKO4iGmfqvakienApv21u55lo+Vi+iVg4jY0 /es/languages/yaml.js
sha384-4smueUtgWTorlNLbaQIawnVCcIAuw82NetPOGWN5PbZT/pMr0rjvZXj0EUzJV1nr /es/languages/yaml.min.js
sha384-Jrkpn2hK0TY04skYBXB9fj7mMpKYy7g726cPwXGXf6mdBXnFlTDXFduxikMCRXT7 /languages/bash.js
sha384-BbT8tZtvkh8HPXIvL5RtzuljBwI3gR5KIdYxZyYSyI5C/+KNAGdzAiexvmxuroag /languages/bash.min.js
sha384-lAz0Eyld5DmFJB7cxaZonrkUJzGefh+K3niV5d7+vzzS7/P7FEeCJeLNXzMjeo+N /languages/c.js
sha384-tMmX0hBMZeMrZhX6dUNxA94/DNJLl70ao6qu2N9+b/6Ep9Y2e1pBzVjxtLygIB+d /languages/c.min.js
sha384-Z5Ja/rxBluJ4iPYwJYn2numfw2XFmlp3qLL1aJ1SZqyTjKWwMh9yWfpNCOqf3vAm /languages/cpp.js
sha384-B711MHXDqRvH/pKkxJk84RyRt9g0qyAJFsu2XukZKoCdnEiBmA6Aq9fO23ZCS7qk /languages/cpp.min.js
sha384-NTF0oluJbKDCxwGTujk+IsRQRbf+waUyDilA5GhOA+VSoxhyApQpmDWMjxfFO3dt /languages/csharp.js
sha384-Z+o7SU/ldIEIdOIqpMV+9s2n8EE1rZTFSRv5Sd7rlaSoPTpyflmmZ/oRb6ycw/2s /languages/csharp.min.js
sha384-bsb3QmLtUiyaiHwtrL4YoAVI9yLsjyqxgoAsk4Zd+ass9rSK1WWRiCDSu/hm8QRp /languages/css.js
sha384-0XGvxIU7Oq1DQMMBr1ORiozzBq3KpZPE/74mJysWRBAop1dZ9Ioq/qRWe8u30Ded /languages/css.min.js
sha384-UZBiDq19/Pu+BEZTOdnKdnew0sCWKFa2EmtRr9O+ZndYF1NgJOlya5bua3Wf++BW /languages/diff.js
sha384-04MxX6iQ0WrwX6Df4GJWGCXwfr5hVS5CQ0r9CS7aunho7Fkj/AAWbEPU8a6G+4LA /languages/diff.min.js
sha384-uh0SMHiaDpf+y9t0NE6+t9c3aMlzs8mHPxmkEU3fY12P481V2wNrKoxPMlKVG61k /languages/go.js
sha384-HdearVH8cyfzwBIQOjL/6dSEmZxQ5rJRezN7spps8E7iu+R6utS8c2ab0AgBNFfH /languages/go.min.js
sha384-IOWs5jCSdfqtJw3g+55axGoOxl+91x7BjVqyS+nhmIO3riBINecgkX3IyhdIjNQB /languages/graphql.js
sha384-M04f/a+xFV20/v8ZQLe5lPeqUKrH0A0h6HUSWFRvq4RE4xlU1yaJIE5XqNSuR2Ke /languages/graphql.min.js
sha384-izwcylRNWmKKRcyCyrYZyNQekUCyR7Fh1x8nYWNCRJoRDU5JXv6TcqlP4C+4MfIf /languages/ini.js
sha384-NrmnsdarwteQHPGjt70kaQTi1KE0XfOJNX9/VJSg6wWwU6U2nPzjl3iWkgU1cvyx /languages/ini.min.js
sha384-Dprg6CdFFkimxaHg7qM7njVaWLMlOLqughixPERBDbm0cHdX6rKujTnJReof8O6m /languages/java.js
sha384-e+59xEZvRMXSRGD31B3HOBGAGqhhs+bbkxCqPuJDkSX5QGneIGTIfwdYJckTN3AO /languages/java.min.js
sha384-yxv7Fv9ToggiLsR67t98hV5ZRup6XX6xL1Rkbi/cGV5J8y7fosCi9POqlBkiBWFg /languages/javascript.js
sha384-tPOrIubtDHoQU7Rqw0o88ilthGO0/4xEZGB47XrQKWhrc1/SchwsDx+AP74u4nk0 /languages/javascript.min.js
sha384-pUlqdjoNePvHvdi7GVKJJnh/P2T3EvXXodl5j0JtTkbNC4DRH7gwGbcHFa84bFOP /languages/json.js
sha384-3C+cPClJZgjKFYAb0bh35D7im2jasLzgk9eRix3t1c5pk1+x6b+bHghWcdrKwIo3 /languages/json.min.js
sha384-vIyPs+G4S+ut5NV5tBIN5/E17wBiWbTTkFPPFbBC+r/FZOD95/fbcSzzeo00bE3x /languages/kotlin.js
sha384-7abn027YsNDPFilpW9aLlNUanPrq7Ht81zKQL9MKQq6/nkKrLczChRK5OA8GSKep /languages/kotlin.min.js
sha384-KSqRjSg7Nn1FuuRUtjB7br82XVgWtqos5H9BlvRY1j5YQr2lftIUSg5deukqK89p /languages/less.js
sha384-M7Wfa4KRyfGnn1i52Nqpr5zWcrmVaO0luxCB+2Txz1eI2FRQfpDcNimn1f86K2Cp /languages/less.min.js
sha384-IQZHDTDQQ0zpXf1FfEYOFIfjZrBbLbNXYCn4zukU6u9mLf6JI36vvIRaV6/d175T /languages/lua.js
sha384-dbTI+BVfiAlIfjWMYrH83f/x/GYSKbujaX4g4F7q5YxbGtlS7qTLcwBQQvDdsGf6 /languages/lua.min.js
sha384-NpIMNHXY0x67yhJSnXiHh9V28uT0Bfz2cKxc30p9vURMu5IAcDhJT1TpaqUE1x0B /languages/makefile.js
sha384-DjL90zP08vzabGXs0CglFocqoxPXnzAcKhobGV+CQDA5FHGW7xCnxjylOhna+HB+ /languages/makefile.min.js
sha384-Sk9XW/OOutdl6KS1M9Wson0imuqr0LkpoTRDHi5QFH4MWe0aViI5d86BOVkh8Ds0 /languages/markdown.js
sha384-Rv26WbhHH4MDPzeExq4ECmZUYF942tlfVhqA91Drw1P+Ey55KjihLF9RJENxjWr1 /languages/markdown.min.js
sha384-hpU4KjKsUFgTYugJheYLkhFIEvecxLYra9Fg0ptjxqCxlUyMCJirJD/2IQDjZihD /languages/objectivec.js
sha384-azcLq84HapvEpXsDDJ2m1n7KovejGjCdGV4Ilw9xlcb6Yg2EyGNVr5dHZyoLdVDw /languages/objectivec.min.js
sha384-qLoCYnNDldQrhnuTfd5BAc54A/ulhuQYKYDYiU+iJRa87k5owWYLvnL0ttLWmFKQ /languages/perl.js
sha384-PK5CVcMiWQ08dZFregTL56n1urRNEsSuWT6oiH1sFm/2ac/epI35hC5lx+YzjH5U /languages/perl.min.js
sha384-0XBmTxpMLuDjB2zdfbi3Lv4Yokm2e1YFGZ9mCmI5887Kpi23jMF5N7rPrf0GdoU/ /languages/php.js
sha384-Bv/Sxv6HlOzYOdV1iQpJTG3xiqGWIIMq9xsFfEX8ss7oNWMgKqOa/J2WSFG2m7Jd /languages/php.min.js
sha384-DQroZ14Erpo7ay5JoNeZEUe41UI7w0Jra2nABCsZVG/EJVO5Zfb2sS1fEt/YGGPe /languages/php-template.js
sha384-LIzUVMUAZRreWHTENKQ/wXuNK17VO4xPf+kR1a0aBKvM3S7vsedCcFJZC7N7vdDt /languages/php-template.min.js
sha384-MZKv9uidO1+VnHz8xWxPv6ACuLO5t823eanvTcKYnmi/ocdVYD8zKZNTxmF0nKEM /languages/plaintext.js
sha384-Z9EdtPaC8UiXHEq1WuQTdvqT+FwjLwaVTIwTCZW/dGfiU9nbF8Shvltrhqtw83Qb /languages/plaintext.min.js
sha384-ueSSFZFqg7cVD0dpEqIk9EefJiJUYan0PH6I8u/p+bNLLx7dMs4J2keMaFXqCN8P /languages/python.js
sha384-eXRt+aAa2ig1yFVDQCLis8k9s/1dikTcigj+/R07yNdIxc8BAG/b1uHDyEW3of17 /languages/python.min.js
sha384-Zr5t2YaLU0giGFY/MuBA8UrK47JGpd9DuryiosYFRSQ6EJfTIF9mt8IJp/4/hpOU /languages/python-repl.js
sha384-n3iFvvEGhuJlnYpLj6JaCg7WiOhd8kQfKTZBDnpJwFZ0puRMhoq9JWtKDRw5Snyq /languages/python-repl.min.js
sha384-Wnn+wk2C8+hIgCNyvLC1dFTsN01c/yrpVqpKDNYF1M0Rg5kYCCmO8o8lS/yY3w2D /languages/r.js
sha384-poz1JEq/ihCmK+1p8IXPoluMlou+rnb+4Q3DenGB+mkNBB/JZkT0c/TERX8D+RUX /languages/r.min.js
sha384-6rhZe8x0LGCtYYrvHFTyO9QfZq2jHdoFsruI9B+lvUD0+Gc2Bn4JW0+cEC94ly3c /languages/ruby.js
sha384-Rlnlnjp0sedK9HVa29DtCyVFVEDRZyeTMQ6+aOKUaXptJmpVGTEmCk6ziXfmku6l /languages/ruby.min.js
sha384-4hMItQrXDnquJWRbDiZ+cP4udu1pcJlCVFg3Ytv9OgWNbpIwzizsWbIwzA1BAJrI /languages/rust.js
sha384-kENps59cKQW5DV3vOEzpSp6tfGzWGpPYKz748i4gGziVSjieRtupNNu/WEwG3s8n /languages/rust.min.js
sha384-e5MJZgawCv4c+BexmFUMVQU6dLcIOXdieG/a1FPCIgnlGfBIEUUcFMMo+UrKMOtN /languages/scss.js
sha384-BYdYy4D3IX6eNNlKqsviUjxC6EqavvNwCVDMzmie3QXyArWdCQf+VvvFo4ciaNaW /languages/scss.min.js
sha384-BanM6jNzM3hgNw0Vu3gSe58a3MK3PSlMUzh5s8QaaDzIvTWgB0jNetV3rNxteKHy /languages/shell.js
sha384-mSZF08WaP0Llc4GMwE0KA2V9yfZQimO5PvfcXf2AATDdqri3Q7IdV7pfbhVPJCHV /languages/shell.min.js
sha384-2sXmcW3eKeNDWiLtuq9NgFJC4NsLBN/fDTzZevmcgBrSERv6iO/k+c7r9T09Fb8J /languages/sql.js
sha384-jrnLoVn13sB+/dTfoAYVPhg0tYGQzzuzSGP3WTk8OvKAY0hDejpUXFYYI3bohAyW /languages/sql.min.js
sha384-+juhAXbxlgltos7eNuzta0Y7hfKqGQftMcEEStYqBJftSEdIiLd/FaviI8hs4d86 /languages/swift.js
sha384-CCauhmYx0fwWViYO6uiTII5shLTfiY/OzxKmLRTeCp8Ok81I2nXZS2Gb9lJVOSPC /languages/swift.min.js
sha384-8v3YMaXFO9cmTNxsHWqwn9wJsV1jVO7rwx4huxqlEQpT/P2tuDbtm+Hs0EdYqu0a /languages/typescript.js
sha384-df1w1nJ43GNwmgbSCrT8YFIYyqFAm+lzj+b6ofuziX8Cfdg9QHFwbORDgAaj//wi /languages/typescript.min.js
sha384-PWtej+1fbEACjPO/+i55ybZvKUn+nUtSRAkFKLQx6O4zrFbiIUlmnErVVh6oZAxa /languages/vbnet.js
sha384-9jaz2rSOFx5kYjZB+Loaf0a4ipf9Yvk08+8QskyozD+yaHdA14SgQKv0C52/UooX /languages/vbnet.min.js
sha384-TCN/hvup/XKpDtGmR/RyK6NSG247wkNROUpO2sAoJuwpMvcr4KP9HA+K5L2rvOKg /languages/wasm.js
sha384-J3pUKFGnHJH0czAle+lKF96F/08caYKJfTEzlt5dGbGTR9M4BwOeOqAgvSzsjOsP /languages/wasm.min.js
sha384-Pgzg6a405W6U1xFjjSs5i8d7V81Tmt/TYn8HFOa+u1psDc8cbs8nC7BuyNXbWWRK /languages/xml.js
sha384-FQjSArDMJE4WMAJGcCNAV+IXIOljcIxM3UFAD2vxjedWmBnnDaAyqRG7AQHf/uM/ /languages/xml.min.js
sha384-6GXi9L5BnOWPU6bzwYL78Zscp23qyDdMLZpZvp4mLzvF2qt0eY/DfsPHiFVXq4hv /languages/yaml.js
sha384-A/iMReLA0Bo3tLydBIoOQXQzYnrwL90jkHYUubrtERUGCbIuU7U0EHge0Xd2s5sr /languages/yaml.min.js
sha384-5ka3JsbfeTzh/0oDZbLvQwZvfZF6OxAjEYtEbOSTzc/Hr3cowRFHlvRVl9BEVkFr /highlight.js
sha384-DfuUw42ioE+mBJmUkFRnFbaafZ8+pICt6pnhycbXgWm4QiFC0B22CJt6WcvWs/40 /highlight.min.js
```
-29
View File
@@ -1,29 +0,0 @@
BSD 3-Clause License
Copyright (c) 2006, Ivan Sagalaev.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-45
View File
@@ -1,45 +0,0 @@
# Highlight.js CDN Assets
[![install size](https://packagephobia.now.sh/badge?p=highlight.js)](https://packagephobia.now.sh/result?p=highlight.js)
**This package contains only the CDN build assets of highlight.js.**
This may be what you want if you'd like to install the pre-built distributable highlight.js client-side assets via NPM. If you're wanting to use highlight.js mainly on the server-side you likely want the [highlight.js][1] package instead.
To access these files via CDN:<br>
https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@latest/build/
**If you just want a single .js file with the common languages built-in:
<https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@latest/build/highlight.min.js>**
---
## Highlight.js
Highlight.js is a syntax highlighter written in JavaScript. It works in
the browser as well as on the server. It works with pretty much any
markup, doesnt depend on any framework, and has automatic language
detection.
If you'd like to read the full README:<br>
<https://github.com/highlightjs/highlight.js/blob/main/README.md>
## License
Highlight.js is released under the BSD License. See [LICENSE][7] file
for details.
## Links
The official site for the library is at <https://highlightjs.org/>.
The Github project may be found at: <https://github.com/highlightjs/highlight.js>
Further in-depth documentation for the API and other topics is at
<http://highlightjs.readthedocs.io/>.
A list of the Core Team and contributors can be found in the [CONTRIBUTORS.md][8] file.
[1]: https://www.npmjs.com/package/highlight.js
[7]: https://github.com/highlightjs/highlight.js/blob/main/LICENSE
[8]: https://github.com/highlightjs/highlight.js/blob/main/CONTRIBUTORS.md
File diff suppressed because it is too large Load Diff
-306
View File
@@ -1,306 +0,0 @@
/*!
Highlight.js v11.11.1 (git: 08cb242e7d)
(c) 2006-2025 Josh Goebel <hello@joshgoebel.com> and other contributors
License: BSD-3-Clause
*/
function e(t){return t instanceof Map?t.clear=t.delete=t.set=()=>{
throw Error("map is read-only")}:t instanceof Set&&(t.add=t.clear=t.delete=()=>{
throw Error("set is read-only")
}),Object.freeze(t),Object.getOwnPropertyNames(t).forEach((n=>{
const i=t[n],s=typeof i;"object"!==s&&"function"!==s||Object.isFrozen(i)||e(i)
})),t}class t{constructor(e){
void 0===e.data&&(e.data={}),this.data=e.data,this.isMatchIgnored=!1}
ignoreMatch(){this.isMatchIgnored=!0}}function n(e){
return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#x27;")
}function i(e,...t){const n=Object.create(null);for(const t in e)n[t]=e[t]
;return t.forEach((e=>{for(const t in e)n[t]=e[t]})),n}const s=e=>!!e.scope
;class r{constructor(e,t){
this.buffer="",this.classPrefix=t.classPrefix,e.walk(this)}addText(e){
this.buffer+=n(e)}openNode(e){if(!s(e))return;const t=((e,{prefix:t})=>{
if(e.startsWith("language:"))return e.replace("language:","language-")
;if(e.includes(".")){const n=e.split(".")
;return[`${t}${n.shift()}`,...n.map(((e,t)=>`${e}${"_".repeat(t+1)}`))].join(" ")
}return`${t}${e}`})(e.scope,{prefix:this.classPrefix});this.span(t)}
closeNode(e){s(e)&&(this.buffer+="</span>")}value(){return this.buffer}span(e){
this.buffer+=`<span class="${e}">`}}const o=(e={})=>{const t={children:[]}
;return Object.assign(t,e),t};class a{constructor(){
this.rootNode=o(),this.stack=[this.rootNode]}get top(){
return this.stack[this.stack.length-1]}get root(){return this.rootNode}add(e){
this.top.children.push(e)}openNode(e){const t=o({scope:e})
;this.add(t),this.stack.push(t)}closeNode(){
if(this.stack.length>1)return this.stack.pop()}closeAllNodes(){
for(;this.closeNode(););}toJSON(){return JSON.stringify(this.rootNode,null,4)}
walk(e){return this.constructor._walk(e,this.rootNode)}static _walk(e,t){
return"string"==typeof t?e.addText(t):t.children&&(e.openNode(t),
t.children.forEach((t=>this._walk(e,t))),e.closeNode(t)),e}static _collapse(e){
"string"!=typeof e&&e.children&&(e.children.every((e=>"string"==typeof e))?e.children=[e.children.join("")]:e.children.forEach((e=>{
a._collapse(e)})))}}class c extends a{constructor(e){super(),this.options=e}
addText(e){""!==e&&this.add(e)}startScope(e){this.openNode(e)}endScope(){
this.closeNode()}__addSublanguage(e,t){const n=e.root
;t&&(n.scope="language:"+t),this.add(n)}toHTML(){
return new r(this,this.options).value()}finalize(){
return this.closeAllNodes(),!0}}function l(e){
return e?"string"==typeof e?e:e.source:null}function g(e){return h("(?=",e,")")}
function u(e){return h("(?:",e,")*")}function d(e){return h("(?:",e,")?")}
function h(...e){return e.map((e=>l(e))).join("")}function f(...e){const t=(e=>{
const t=e[e.length-1]
;return"object"==typeof t&&t.constructor===Object?(e.splice(e.length-1,1),t):{}
})(e);return"("+(t.capture?"":"?:")+e.map((e=>l(e))).join("|")+")"}
function p(e){return RegExp(e.toString()+"|").exec("").length-1}
const b=/\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./
;function m(e,{joinWith:t}){let n=0;return e.map((e=>{n+=1;const t=n
;let i=l(e),s="";for(;i.length>0;){const e=b.exec(i);if(!e){s+=i;break}
s+=i.substring(0,e.index),
i=i.substring(e.index+e[0].length),"\\"===e[0][0]&&e[1]?s+="\\"+(Number(e[1])+t):(s+=e[0],
"("===e[0]&&n++)}return s})).map((e=>`(${e})`)).join(t)}
const E="[a-zA-Z]\\w*",x="[a-zA-Z_]\\w*",_="\\b\\d+(\\.\\d+)?",y="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",w="\\b(0b[01]+)",O={
begin:"\\\\[\\s\\S]",relevance:0},k={scope:"string",begin:"'",end:"'",
illegal:"\\n",contains:[O]},v={scope:"string",begin:'"',end:'"',illegal:"\\n",
contains:[O]},N=(e,t,n={})=>{const s=i({scope:"comment",begin:e,end:t,
contains:[]},n);s.contains.push({scope:"doctag",
begin:"[ ]*(?=(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):)",
end:/(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):/,excludeBegin:!0,relevance:0})
;const r=f("I","a","is","so","us","to","at","if","in","it","on",/[A-Za-z]+['](d|ve|re|ll|t|s|n)/,/[A-Za-z]+[-][a-z]+/,/[A-Za-z][a-z]{2,}/)
;return s.contains.push({begin:h(/[ ]+/,"(",r,/[.]?[:]?([.][ ]|[ ])/,"){3}")}),s
},S=N("//","$"),M=N("/\\*","\\*/"),R=N("#","$");var A=Object.freeze({
__proto__:null,APOS_STRING_MODE:k,BACKSLASH_ESCAPE:O,BINARY_NUMBER_MODE:{
scope:"number",begin:w,relevance:0},BINARY_NUMBER_RE:w,COMMENT:N,
C_BLOCK_COMMENT_MODE:M,C_LINE_COMMENT_MODE:S,C_NUMBER_MODE:{scope:"number",
begin:y,relevance:0},C_NUMBER_RE:y,END_SAME_AS_BEGIN:e=>Object.assign(e,{
"on:begin":(e,t)=>{t.data._beginMatch=e[1]},"on:end":(e,t)=>{
t.data._beginMatch!==e[1]&&t.ignoreMatch()}}),HASH_COMMENT_MODE:R,IDENT_RE:E,
MATCH_NOTHING_RE:/\b\B/,METHOD_GUARD:{begin:"\\.\\s*"+x,relevance:0},
NUMBER_MODE:{scope:"number",begin:_,relevance:0},NUMBER_RE:_,
PHRASAL_WORDS_MODE:{
begin:/\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/
},QUOTE_STRING_MODE:v,REGEXP_MODE:{scope:"regexp",begin:/\/(?=[^/\n]*\/)/,
end:/\/[gimuy]*/,contains:[O,{begin:/\[/,end:/\]/,relevance:0,contains:[O]}]},
RE_STARTERS_RE:"!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~",
SHEBANG:(e={})=>{const t=/^#![ ]*\//
;return e.binary&&(e.begin=h(t,/.*\b/,e.binary,/\b.*/)),i({scope:"meta",begin:t,
end:/$/,relevance:0,"on:begin":(e,t)=>{0!==e.index&&t.ignoreMatch()}},e)},
TITLE_MODE:{scope:"title",begin:E,relevance:0},UNDERSCORE_IDENT_RE:x,
UNDERSCORE_TITLE_MODE:{scope:"title",begin:x,relevance:0}});function j(e,t){
"."===e.input[e.index-1]&&t.ignoreMatch()}function I(e,t){
void 0!==e.className&&(e.scope=e.className,delete e.className)}function T(e,t){
t&&e.beginKeywords&&(e.begin="\\b("+e.beginKeywords.split(" ").join("|")+")(?!\\.)(?=\\b|\\s)",
e.__beforeBegin=j,e.keywords=e.keywords||e.beginKeywords,delete e.beginKeywords,
void 0===e.relevance&&(e.relevance=0))}function L(e,t){
Array.isArray(e.illegal)&&(e.illegal=f(...e.illegal))}function B(e,t){
if(e.match){
if(e.begin||e.end)throw Error("begin & end are not supported with match")
;e.begin=e.match,delete e.match}}function P(e,t){
void 0===e.relevance&&(e.relevance=1)}const D=(e,t)=>{if(!e.beforeMatch)return
;if(e.starts)throw Error("beforeMatch cannot be used with starts")
;const n=Object.assign({},e);Object.keys(e).forEach((t=>{delete e[t]
})),e.keywords=n.keywords,e.begin=h(n.beforeMatch,g(n.begin)),e.starts={
relevance:0,contains:[Object.assign(n,{endsParent:!0})]
},e.relevance=0,delete n.beforeMatch
},H=["of","and","for","in","not","or","if","then","parent","list","value"]
;function C(e,t,n="keyword"){const i=Object.create(null)
;return"string"==typeof e?s(n,e.split(" ")):Array.isArray(e)?s(n,e):Object.keys(e).forEach((n=>{
Object.assign(i,C(e[n],t,n))})),i;function s(e,n){
t&&(n=n.map((e=>e.toLowerCase()))),n.forEach((t=>{const n=t.split("|")
;i[n[0]]=[e,$(n[0],n[1])]}))}}function $(e,t){
return t?Number(t):(e=>H.includes(e.toLowerCase()))(e)?0:1}const U={},z=e=>{
console.error(e)},W=(e,...t)=>{console.log("WARN: "+e,...t)},X=(e,t)=>{
U[`${e}/${t}`]||(console.log(`Deprecated as of ${e}. ${t}`),U[`${e}/${t}`]=!0)
},G=Error();function K(e,t,{key:n}){let i=0;const s=e[n],r={},o={}
;for(let e=1;e<=t.length;e++)o[e+i]=s[e],r[e+i]=!0,i+=p(t[e-1])
;e[n]=o,e[n]._emit=r,e[n]._multi=!0}function F(e){(e=>{
e.scope&&"object"==typeof e.scope&&null!==e.scope&&(e.beginScope=e.scope,
delete e.scope)})(e),"string"==typeof e.beginScope&&(e.beginScope={
_wrap:e.beginScope}),"string"==typeof e.endScope&&(e.endScope={_wrap:e.endScope
}),(e=>{if(Array.isArray(e.begin)){
if(e.skip||e.excludeBegin||e.returnBegin)throw z("skip, excludeBegin, returnBegin not compatible with beginScope: {}"),
G
;if("object"!=typeof e.beginScope||null===e.beginScope)throw z("beginScope must be object"),
G;K(e,e.begin,{key:"beginScope"}),e.begin=m(e.begin,{joinWith:""})}})(e),(e=>{
if(Array.isArray(e.end)){
if(e.skip||e.excludeEnd||e.returnEnd)throw z("skip, excludeEnd, returnEnd not compatible with endScope: {}"),
G
;if("object"!=typeof e.endScope||null===e.endScope)throw z("endScope must be object"),
G;K(e,e.end,{key:"endScope"}),e.end=m(e.end,{joinWith:""})}})(e)}function Z(e){
function t(t,n){
return RegExp(l(t),"m"+(e.case_insensitive?"i":"")+(e.unicodeRegex?"u":"")+(n?"g":""))
}class n{constructor(){
this.matchIndexes={},this.regexes=[],this.matchAt=1,this.position=0}
addRule(e,t){
t.position=this.position++,this.matchIndexes[this.matchAt]=t,this.regexes.push([t,e]),
this.matchAt+=p(e)+1}compile(){0===this.regexes.length&&(this.exec=()=>null)
;const e=this.regexes.map((e=>e[1]));this.matcherRe=t(m(e,{joinWith:"|"
}),!0),this.lastIndex=0}exec(e){this.matcherRe.lastIndex=this.lastIndex
;const t=this.matcherRe.exec(e);if(!t)return null
;const n=t.findIndex(((e,t)=>t>0&&void 0!==e)),i=this.matchIndexes[n]
;return t.splice(0,n),Object.assign(t,i)}}class s{constructor(){
this.rules=[],this.multiRegexes=[],
this.count=0,this.lastIndex=0,this.regexIndex=0}getMatcher(e){
if(this.multiRegexes[e])return this.multiRegexes[e];const t=new n
;return this.rules.slice(e).forEach((([e,n])=>t.addRule(e,n))),
t.compile(),this.multiRegexes[e]=t,t}resumingScanAtSamePosition(){
return 0!==this.regexIndex}considerAll(){this.regexIndex=0}addRule(e,t){
this.rules.push([e,t]),"begin"===t.type&&this.count++}exec(e){
const t=this.getMatcher(this.regexIndex);t.lastIndex=this.lastIndex
;let n=t.exec(e)
;if(this.resumingScanAtSamePosition())if(n&&n.index===this.lastIndex);else{
const t=this.getMatcher(0);t.lastIndex=this.lastIndex+1,n=t.exec(e)}
return n&&(this.regexIndex+=n.position+1,
this.regexIndex===this.count&&this.considerAll()),n}}
if(e.compilerExtensions||(e.compilerExtensions=[]),
e.contains&&e.contains.includes("self"))throw Error("ERR: contains `self` is not supported at the top-level of a language. See documentation.")
;return e.classNameAliases=i(e.classNameAliases||{}),function n(r,o){const a=r
;if(r.isCompiled)return a
;[I,B,F,D].forEach((e=>e(r,o))),e.compilerExtensions.forEach((e=>e(r,o))),
r.__beforeBegin=null,[T,L,P].forEach((e=>e(r,o))),r.isCompiled=!0;let c=null
;return"object"==typeof r.keywords&&r.keywords.$pattern&&(r.keywords=Object.assign({},r.keywords),
c=r.keywords.$pattern,
delete r.keywords.$pattern),c=c||/\w+/,r.keywords&&(r.keywords=C(r.keywords,e.case_insensitive)),
a.keywordPatternRe=t(c,!0),
o&&(r.begin||(r.begin=/\B|\b/),a.beginRe=t(a.begin),r.end||r.endsWithParent||(r.end=/\B|\b/),
r.end&&(a.endRe=t(a.end)),
a.terminatorEnd=l(a.end)||"",r.endsWithParent&&o.terminatorEnd&&(a.terminatorEnd+=(r.end?"|":"")+o.terminatorEnd)),
r.illegal&&(a.illegalRe=t(r.illegal)),
r.contains||(r.contains=[]),r.contains=[].concat(...r.contains.map((e=>(e=>(e.variants&&!e.cachedVariants&&(e.cachedVariants=e.variants.map((t=>i(e,{
variants:null},t)))),e.cachedVariants?e.cachedVariants:V(e)?i(e,{
starts:e.starts?i(e.starts):null
}):Object.isFrozen(e)?i(e):e))("self"===e?r:e)))),r.contains.forEach((e=>{n(e,a)
})),r.starts&&n(r.starts,o),a.matcher=(e=>{const t=new s
;return e.contains.forEach((e=>t.addRule(e.begin,{rule:e,type:"begin"
}))),e.terminatorEnd&&t.addRule(e.terminatorEnd,{type:"end"
}),e.illegal&&t.addRule(e.illegal,{type:"illegal"}),t})(a),a}(e)}function V(e){
return!!e&&(e.endsWithParent||V(e.starts))}class q extends Error{
constructor(e,t){super(e),this.name="HTMLInjectionError",this.html=t}}
const J=n,Y=i,Q=Symbol("nomatch"),ee=n=>{
const i=Object.create(null),s=Object.create(null),r=[];let o=!0
;const a="Could not find the language '{}', did you forget to load/include a language module?",l={
disableAutodetect:!0,name:"Plain text",contains:[]};let p={
ignoreUnescapedHTML:!1,throwUnescapedHTML:!1,noHighlightRe:/^(no-?highlight)$/i,
languageDetectRe:/\blang(?:uage)?-([\w-]+)\b/i,classPrefix:"hljs-",
cssSelector:"pre code",languages:null,__emitter:c};function b(e){
return p.noHighlightRe.test(e)}function m(e,t,n){let i="",s=""
;"object"==typeof t?(i=e,
n=t.ignoreIllegals,s=t.language):(X("10.7.0","highlight(lang, code, ...args) has been deprecated."),
X("10.7.0","Please use highlight(code, options) instead.\nhttps://github.com/highlightjs/highlight.js/issues/2277"),
s=e,i=t),void 0===n&&(n=!0);const r={code:i,language:s};N("before:highlight",r)
;const o=r.result?r.result:E(r.language,r.code,n)
;return o.code=r.code,N("after:highlight",o),o}function E(e,n,s,r){
const c=Object.create(null);function l(){if(!N.keywords)return void M.addText(R)
;let e=0;N.keywordPatternRe.lastIndex=0;let t=N.keywordPatternRe.exec(R),n=""
;for(;t;){n+=R.substring(e,t.index)
;const s=w.case_insensitive?t[0].toLowerCase():t[0],r=(i=s,N.keywords[i]);if(r){
const[e,i]=r
;if(M.addText(n),n="",c[s]=(c[s]||0)+1,c[s]<=7&&(A+=i),e.startsWith("_"))n+=t[0];else{
const n=w.classNameAliases[e]||e;u(t[0],n)}}else n+=t[0]
;e=N.keywordPatternRe.lastIndex,t=N.keywordPatternRe.exec(R)}var i
;n+=R.substring(e),M.addText(n)}function g(){null!=N.subLanguage?(()=>{
if(""===R)return;let e=null;if("string"==typeof N.subLanguage){
if(!i[N.subLanguage])return void M.addText(R)
;e=E(N.subLanguage,R,!0,S[N.subLanguage]),S[N.subLanguage]=e._top
}else e=x(R,N.subLanguage.length?N.subLanguage:null)
;N.relevance>0&&(A+=e.relevance),M.__addSublanguage(e._emitter,e.language)
})():l(),R=""}function u(e,t){
""!==e&&(M.startScope(t),M.addText(e),M.endScope())}function d(e,t){let n=1
;const i=t.length-1;for(;n<=i;){if(!e._emit[n]){n++;continue}
const i=w.classNameAliases[e[n]]||e[n],s=t[n];i?u(s,i):(R=s,l(),R=""),n++}}
function h(e,t){
return e.scope&&"string"==typeof e.scope&&M.openNode(w.classNameAliases[e.scope]||e.scope),
e.beginScope&&(e.beginScope._wrap?(u(R,w.classNameAliases[e.beginScope._wrap]||e.beginScope._wrap),
R=""):e.beginScope._multi&&(d(e.beginScope,t),R="")),N=Object.create(e,{parent:{
value:N}}),N}function f(e,n,i){let s=((e,t)=>{const n=e&&e.exec(t)
;return n&&0===n.index})(e.endRe,i);if(s){if(e["on:end"]){const i=new t(e)
;e["on:end"](n,i),i.isMatchIgnored&&(s=!1)}if(s){
for(;e.endsParent&&e.parent;)e=e.parent;return e}}
if(e.endsWithParent)return f(e.parent,n,i)}function b(e){
return 0===N.matcher.regexIndex?(R+=e[0],1):(T=!0,0)}function m(e){
const t=e[0],i=n.substring(e.index),s=f(N,e,i);if(!s)return Q;const r=N
;N.endScope&&N.endScope._wrap?(g(),
u(t,N.endScope._wrap)):N.endScope&&N.endScope._multi?(g(),
d(N.endScope,e)):r.skip?R+=t:(r.returnEnd||r.excludeEnd||(R+=t),
g(),r.excludeEnd&&(R=t));do{
N.scope&&M.closeNode(),N.skip||N.subLanguage||(A+=N.relevance),N=N.parent
}while(N!==s.parent);return s.starts&&h(s.starts,e),r.returnEnd?0:t.length}
let _={};function y(i,r){const a=r&&r[0];if(R+=i,null==a)return g(),0
;if("begin"===_.type&&"end"===r.type&&_.index===r.index&&""===a){
if(R+=n.slice(r.index,r.index+1),!o){const t=Error(`0 width match regex (${e})`)
;throw t.languageName=e,t.badRule=_.rule,t}return 1}
if(_=r,"begin"===r.type)return(e=>{
const n=e[0],i=e.rule,s=new t(i),r=[i.__beforeBegin,i["on:begin"]]
;for(const t of r)if(t&&(t(e,s),s.isMatchIgnored))return b(n)
;return i.skip?R+=n:(i.excludeBegin&&(R+=n),
g(),i.returnBegin||i.excludeBegin||(R=n)),h(i,e),i.returnBegin?0:n.length})(r)
;if("illegal"===r.type&&!s){
const e=Error('Illegal lexeme "'+a+'" for mode "'+(N.scope||"<unnamed>")+'"')
;throw e.mode=N,e}if("end"===r.type){const e=m(r);if(e!==Q)return e}
if("illegal"===r.type&&""===a)return R+="\n",1
;if(I>1e5&&I>3*r.index)throw Error("potential infinite loop, way more iterations than matches")
;return R+=a,a.length}const w=O(e)
;if(!w)throw z(a.replace("{}",e)),Error('Unknown language: "'+e+'"')
;const k=Z(w);let v="",N=r||k;const S={},M=new p.__emitter(p);(()=>{const e=[]
;for(let t=N;t!==w;t=t.parent)t.scope&&e.unshift(t.scope)
;e.forEach((e=>M.openNode(e)))})();let R="",A=0,j=0,I=0,T=!1;try{
if(w.__emitTokens)w.__emitTokens(n,M);else{for(N.matcher.considerAll();;){
I++,T?T=!1:N.matcher.considerAll(),N.matcher.lastIndex=j
;const e=N.matcher.exec(n);if(!e)break;const t=y(n.substring(j,e.index),e)
;j=e.index+t}y(n.substring(j))}return M.finalize(),v=M.toHTML(),{language:e,
value:v,relevance:A,illegal:!1,_emitter:M,_top:N}}catch(t){
if(t.message&&t.message.includes("Illegal"))return{language:e,value:J(n),
illegal:!0,relevance:0,_illegalBy:{message:t.message,index:j,
context:n.slice(j-100,j+100),mode:t.mode,resultSoFar:v},_emitter:M};if(o)return{
language:e,value:J(n),illegal:!1,relevance:0,errorRaised:t,_emitter:M,_top:N}
;throw t}}function x(e,t){t=t||p.languages||Object.keys(i);const n=(e=>{
const t={value:J(e),illegal:!1,relevance:0,_top:l,_emitter:new p.__emitter(p)}
;return t._emitter.addText(e),t})(e),s=t.filter(O).filter(v).map((t=>E(t,e,!1)))
;s.unshift(n);const r=s.sort(((e,t)=>{
if(e.relevance!==t.relevance)return t.relevance-e.relevance
;if(e.language&&t.language){if(O(e.language).supersetOf===t.language)return 1
;if(O(t.language).supersetOf===e.language)return-1}return 0})),[o,a]=r,c=o
;return c.secondBest=a,c}function _(e){let t=null;const n=(e=>{
let t=e.className+" ";t+=e.parentNode?e.parentNode.className:""
;const n=p.languageDetectRe.exec(t);if(n){const t=O(n[1])
;return t||(W(a.replace("{}",n[1])),
W("Falling back to no-highlight mode for this block.",e)),t?n[1]:"no-highlight"}
return t.split(/\s+/).find((e=>b(e)||O(e)))})(e);if(b(n))return
;if(N("before:highlightElement",{el:e,language:n
}),e.dataset.highlighted)return void console.log("Element previously highlighted. To highlight again, first unset `dataset.highlighted`.",e)
;if(e.children.length>0&&(p.ignoreUnescapedHTML||(console.warn("One of your code blocks includes unescaped HTML. This is a potentially serious security risk."),
console.warn("https://github.com/highlightjs/highlight.js/wiki/security"),
console.warn("The element with unescaped HTML:"),
console.warn(e)),p.throwUnescapedHTML))throw new q("One of your code blocks includes unescaped HTML.",e.innerHTML)
;t=e;const i=t.textContent,r=n?m(i,{language:n,ignoreIllegals:!0}):x(i)
;e.innerHTML=r.value,e.dataset.highlighted="yes",((e,t,n)=>{const i=t&&s[t]||n
;e.classList.add("hljs"),e.classList.add("language-"+i)
})(e,n,r.language),e.result={language:r.language,re:r.relevance,
relevance:r.relevance},r.secondBest&&(e.secondBest={
language:r.secondBest.language,relevance:r.secondBest.relevance
}),N("after:highlightElement",{el:e,result:r,text:i})}let y=!1;function w(){
if("loading"===document.readyState)return y||window.addEventListener("DOMContentLoaded",(()=>{
w()}),!1),void(y=!0);document.querySelectorAll(p.cssSelector).forEach(_)}
function O(e){return e=(e||"").toLowerCase(),i[e]||i[s[e]]}
function k(e,{languageName:t}){"string"==typeof e&&(e=[e]),e.forEach((e=>{
s[e.toLowerCase()]=t}))}function v(e){const t=O(e)
;return t&&!t.disableAutodetect}function N(e,t){const n=e;r.forEach((e=>{
e[n]&&e[n](t)}))}Object.assign(n,{highlight:m,highlightAuto:x,highlightAll:w,
highlightElement:_,
highlightBlock:e=>(X("10.7.0","highlightBlock will be removed entirely in v12.0"),
X("10.7.0","Please use highlightElement now."),_(e)),configure:e=>{p=Y(p,e)},
initHighlighting:()=>{
w(),X("10.6.0","initHighlighting() deprecated. Use highlightAll() now.")},
initHighlightingOnLoad:()=>{
w(),X("10.6.0","initHighlightingOnLoad() deprecated. Use highlightAll() now.")
},registerLanguage:(e,t)=>{let s=null;try{s=t(n)}catch(t){
if(z("Language definition for '{}' could not be registered.".replace("{}",e)),
!o)throw t;z(t),s=l}
s.name||(s.name=e),i[e]=s,s.rawDefinition=t.bind(null,n),s.aliases&&k(s.aliases,{
languageName:e})},unregisterLanguage:e=>{delete i[e]
;for(const t of Object.keys(s))s[t]===e&&delete s[t]},
listLanguages:()=>Object.keys(i),getLanguage:O,registerAliases:k,
autoDetection:v,inherit:Y,addPlugin:e=>{(e=>{
e["before:highlightBlock"]&&!e["before:highlightElement"]&&(e["before:highlightElement"]=t=>{
e["before:highlightBlock"](Object.assign({block:t.el},t))
}),e["after:highlightBlock"]&&!e["after:highlightElement"]&&(e["after:highlightElement"]=t=>{
e["after:highlightBlock"](Object.assign({block:t.el},t))})})(e),r.push(e)},
removePlugin:e=>{const t=r.indexOf(e);-1!==t&&r.splice(t,1)}}),n.debugMode=()=>{
o=!1},n.safeMode=()=>{o=!0},n.versionString="11.11.1",n.regex={concat:h,
lookahead:g,either:f,optional:d,anyNumberOfTimes:u}
;for(const t in A)"object"==typeof A[t]&&e(A[t]);return Object.assign(n,A),n
},te=ee({});te.newInstance=()=>ee({});export{te as default};
File diff suppressed because it is too large Load Diff
-306
View File
@@ -1,306 +0,0 @@
/*!
Highlight.js v11.11.1 (git: 08cb242e7d)
(c) 2006-2025 Josh Goebel <hello@joshgoebel.com> and other contributors
License: BSD-3-Clause
*/
function e(t){return t instanceof Map?t.clear=t.delete=t.set=()=>{
throw Error("map is read-only")}:t instanceof Set&&(t.add=t.clear=t.delete=()=>{
throw Error("set is read-only")
}),Object.freeze(t),Object.getOwnPropertyNames(t).forEach((n=>{
const i=t[n],s=typeof i;"object"!==s&&"function"!==s||Object.isFrozen(i)||e(i)
})),t}class t{constructor(e){
void 0===e.data&&(e.data={}),this.data=e.data,this.isMatchIgnored=!1}
ignoreMatch(){this.isMatchIgnored=!0}}function n(e){
return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#x27;")
}function i(e,...t){const n=Object.create(null);for(const t in e)n[t]=e[t]
;return t.forEach((e=>{for(const t in e)n[t]=e[t]})),n}const s=e=>!!e.scope
;class r{constructor(e,t){
this.buffer="",this.classPrefix=t.classPrefix,e.walk(this)}addText(e){
this.buffer+=n(e)}openNode(e){if(!s(e))return;const t=((e,{prefix:t})=>{
if(e.startsWith("language:"))return e.replace("language:","language-")
;if(e.includes(".")){const n=e.split(".")
;return[`${t}${n.shift()}`,...n.map(((e,t)=>`${e}${"_".repeat(t+1)}`))].join(" ")
}return`${t}${e}`})(e.scope,{prefix:this.classPrefix});this.span(t)}
closeNode(e){s(e)&&(this.buffer+="</span>")}value(){return this.buffer}span(e){
this.buffer+=`<span class="${e}">`}}const o=(e={})=>{const t={children:[]}
;return Object.assign(t,e),t};class a{constructor(){
this.rootNode=o(),this.stack=[this.rootNode]}get top(){
return this.stack[this.stack.length-1]}get root(){return this.rootNode}add(e){
this.top.children.push(e)}openNode(e){const t=o({scope:e})
;this.add(t),this.stack.push(t)}closeNode(){
if(this.stack.length>1)return this.stack.pop()}closeAllNodes(){
for(;this.closeNode(););}toJSON(){return JSON.stringify(this.rootNode,null,4)}
walk(e){return this.constructor._walk(e,this.rootNode)}static _walk(e,t){
return"string"==typeof t?e.addText(t):t.children&&(e.openNode(t),
t.children.forEach((t=>this._walk(e,t))),e.closeNode(t)),e}static _collapse(e){
"string"!=typeof e&&e.children&&(e.children.every((e=>"string"==typeof e))?e.children=[e.children.join("")]:e.children.forEach((e=>{
a._collapse(e)})))}}class c extends a{constructor(e){super(),this.options=e}
addText(e){""!==e&&this.add(e)}startScope(e){this.openNode(e)}endScope(){
this.closeNode()}__addSublanguage(e,t){const n=e.root
;t&&(n.scope="language:"+t),this.add(n)}toHTML(){
return new r(this,this.options).value()}finalize(){
return this.closeAllNodes(),!0}}function l(e){
return e?"string"==typeof e?e:e.source:null}function g(e){return h("(?=",e,")")}
function u(e){return h("(?:",e,")*")}function d(e){return h("(?:",e,")?")}
function h(...e){return e.map((e=>l(e))).join("")}function f(...e){const t=(e=>{
const t=e[e.length-1]
;return"object"==typeof t&&t.constructor===Object?(e.splice(e.length-1,1),t):{}
})(e);return"("+(t.capture?"":"?:")+e.map((e=>l(e))).join("|")+")"}
function p(e){return RegExp(e.toString()+"|").exec("").length-1}
const b=/\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./
;function m(e,{joinWith:t}){let n=0;return e.map((e=>{n+=1;const t=n
;let i=l(e),s="";for(;i.length>0;){const e=b.exec(i);if(!e){s+=i;break}
s+=i.substring(0,e.index),
i=i.substring(e.index+e[0].length),"\\"===e[0][0]&&e[1]?s+="\\"+(Number(e[1])+t):(s+=e[0],
"("===e[0]&&n++)}return s})).map((e=>`(${e})`)).join(t)}
const E="[a-zA-Z]\\w*",x="[a-zA-Z_]\\w*",_="\\b\\d+(\\.\\d+)?",y="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",w="\\b(0b[01]+)",O={
begin:"\\\\[\\s\\S]",relevance:0},k={scope:"string",begin:"'",end:"'",
illegal:"\\n",contains:[O]},v={scope:"string",begin:'"',end:'"',illegal:"\\n",
contains:[O]},N=(e,t,n={})=>{const s=i({scope:"comment",begin:e,end:t,
contains:[]},n);s.contains.push({scope:"doctag",
begin:"[ ]*(?=(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):)",
end:/(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):/,excludeBegin:!0,relevance:0})
;const r=f("I","a","is","so","us","to","at","if","in","it","on",/[A-Za-z]+['](d|ve|re|ll|t|s|n)/,/[A-Za-z]+[-][a-z]+/,/[A-Za-z][a-z]{2,}/)
;return s.contains.push({begin:h(/[ ]+/,"(",r,/[.]?[:]?([.][ ]|[ ])/,"){3}")}),s
},S=N("//","$"),M=N("/\\*","\\*/"),R=N("#","$");var A=Object.freeze({
__proto__:null,APOS_STRING_MODE:k,BACKSLASH_ESCAPE:O,BINARY_NUMBER_MODE:{
scope:"number",begin:w,relevance:0},BINARY_NUMBER_RE:w,COMMENT:N,
C_BLOCK_COMMENT_MODE:M,C_LINE_COMMENT_MODE:S,C_NUMBER_MODE:{scope:"number",
begin:y,relevance:0},C_NUMBER_RE:y,END_SAME_AS_BEGIN:e=>Object.assign(e,{
"on:begin":(e,t)=>{t.data._beginMatch=e[1]},"on:end":(e,t)=>{
t.data._beginMatch!==e[1]&&t.ignoreMatch()}}),HASH_COMMENT_MODE:R,IDENT_RE:E,
MATCH_NOTHING_RE:/\b\B/,METHOD_GUARD:{begin:"\\.\\s*"+x,relevance:0},
NUMBER_MODE:{scope:"number",begin:_,relevance:0},NUMBER_RE:_,
PHRASAL_WORDS_MODE:{
begin:/\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/
},QUOTE_STRING_MODE:v,REGEXP_MODE:{scope:"regexp",begin:/\/(?=[^/\n]*\/)/,
end:/\/[gimuy]*/,contains:[O,{begin:/\[/,end:/\]/,relevance:0,contains:[O]}]},
RE_STARTERS_RE:"!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~",
SHEBANG:(e={})=>{const t=/^#![ ]*\//
;return e.binary&&(e.begin=h(t,/.*\b/,e.binary,/\b.*/)),i({scope:"meta",begin:t,
end:/$/,relevance:0,"on:begin":(e,t)=>{0!==e.index&&t.ignoreMatch()}},e)},
TITLE_MODE:{scope:"title",begin:E,relevance:0},UNDERSCORE_IDENT_RE:x,
UNDERSCORE_TITLE_MODE:{scope:"title",begin:x,relevance:0}});function j(e,t){
"."===e.input[e.index-1]&&t.ignoreMatch()}function I(e,t){
void 0!==e.className&&(e.scope=e.className,delete e.className)}function T(e,t){
t&&e.beginKeywords&&(e.begin="\\b("+e.beginKeywords.split(" ").join("|")+")(?!\\.)(?=\\b|\\s)",
e.__beforeBegin=j,e.keywords=e.keywords||e.beginKeywords,delete e.beginKeywords,
void 0===e.relevance&&(e.relevance=0))}function L(e,t){
Array.isArray(e.illegal)&&(e.illegal=f(...e.illegal))}function B(e,t){
if(e.match){
if(e.begin||e.end)throw Error("begin & end are not supported with match")
;e.begin=e.match,delete e.match}}function P(e,t){
void 0===e.relevance&&(e.relevance=1)}const D=(e,t)=>{if(!e.beforeMatch)return
;if(e.starts)throw Error("beforeMatch cannot be used with starts")
;const n=Object.assign({},e);Object.keys(e).forEach((t=>{delete e[t]
})),e.keywords=n.keywords,e.begin=h(n.beforeMatch,g(n.begin)),e.starts={
relevance:0,contains:[Object.assign(n,{endsParent:!0})]
},e.relevance=0,delete n.beforeMatch
},H=["of","and","for","in","not","or","if","then","parent","list","value"]
;function C(e,t,n="keyword"){const i=Object.create(null)
;return"string"==typeof e?s(n,e.split(" ")):Array.isArray(e)?s(n,e):Object.keys(e).forEach((n=>{
Object.assign(i,C(e[n],t,n))})),i;function s(e,n){
t&&(n=n.map((e=>e.toLowerCase()))),n.forEach((t=>{const n=t.split("|")
;i[n[0]]=[e,$(n[0],n[1])]}))}}function $(e,t){
return t?Number(t):(e=>H.includes(e.toLowerCase()))(e)?0:1}const U={},z=e=>{
console.error(e)},W=(e,...t)=>{console.log("WARN: "+e,...t)},X=(e,t)=>{
U[`${e}/${t}`]||(console.log(`Deprecated as of ${e}. ${t}`),U[`${e}/${t}`]=!0)
},G=Error();function K(e,t,{key:n}){let i=0;const s=e[n],r={},o={}
;for(let e=1;e<=t.length;e++)o[e+i]=s[e],r[e+i]=!0,i+=p(t[e-1])
;e[n]=o,e[n]._emit=r,e[n]._multi=!0}function F(e){(e=>{
e.scope&&"object"==typeof e.scope&&null!==e.scope&&(e.beginScope=e.scope,
delete e.scope)})(e),"string"==typeof e.beginScope&&(e.beginScope={
_wrap:e.beginScope}),"string"==typeof e.endScope&&(e.endScope={_wrap:e.endScope
}),(e=>{if(Array.isArray(e.begin)){
if(e.skip||e.excludeBegin||e.returnBegin)throw z("skip, excludeBegin, returnBegin not compatible with beginScope: {}"),
G
;if("object"!=typeof e.beginScope||null===e.beginScope)throw z("beginScope must be object"),
G;K(e,e.begin,{key:"beginScope"}),e.begin=m(e.begin,{joinWith:""})}})(e),(e=>{
if(Array.isArray(e.end)){
if(e.skip||e.excludeEnd||e.returnEnd)throw z("skip, excludeEnd, returnEnd not compatible with endScope: {}"),
G
;if("object"!=typeof e.endScope||null===e.endScope)throw z("endScope must be object"),
G;K(e,e.end,{key:"endScope"}),e.end=m(e.end,{joinWith:""})}})(e)}function Z(e){
function t(t,n){
return RegExp(l(t),"m"+(e.case_insensitive?"i":"")+(e.unicodeRegex?"u":"")+(n?"g":""))
}class n{constructor(){
this.matchIndexes={},this.regexes=[],this.matchAt=1,this.position=0}
addRule(e,t){
t.position=this.position++,this.matchIndexes[this.matchAt]=t,this.regexes.push([t,e]),
this.matchAt+=p(e)+1}compile(){0===this.regexes.length&&(this.exec=()=>null)
;const e=this.regexes.map((e=>e[1]));this.matcherRe=t(m(e,{joinWith:"|"
}),!0),this.lastIndex=0}exec(e){this.matcherRe.lastIndex=this.lastIndex
;const t=this.matcherRe.exec(e);if(!t)return null
;const n=t.findIndex(((e,t)=>t>0&&void 0!==e)),i=this.matchIndexes[n]
;return t.splice(0,n),Object.assign(t,i)}}class s{constructor(){
this.rules=[],this.multiRegexes=[],
this.count=0,this.lastIndex=0,this.regexIndex=0}getMatcher(e){
if(this.multiRegexes[e])return this.multiRegexes[e];const t=new n
;return this.rules.slice(e).forEach((([e,n])=>t.addRule(e,n))),
t.compile(),this.multiRegexes[e]=t,t}resumingScanAtSamePosition(){
return 0!==this.regexIndex}considerAll(){this.regexIndex=0}addRule(e,t){
this.rules.push([e,t]),"begin"===t.type&&this.count++}exec(e){
const t=this.getMatcher(this.regexIndex);t.lastIndex=this.lastIndex
;let n=t.exec(e)
;if(this.resumingScanAtSamePosition())if(n&&n.index===this.lastIndex);else{
const t=this.getMatcher(0);t.lastIndex=this.lastIndex+1,n=t.exec(e)}
return n&&(this.regexIndex+=n.position+1,
this.regexIndex===this.count&&this.considerAll()),n}}
if(e.compilerExtensions||(e.compilerExtensions=[]),
e.contains&&e.contains.includes("self"))throw Error("ERR: contains `self` is not supported at the top-level of a language. See documentation.")
;return e.classNameAliases=i(e.classNameAliases||{}),function n(r,o){const a=r
;if(r.isCompiled)return a
;[I,B,F,D].forEach((e=>e(r,o))),e.compilerExtensions.forEach((e=>e(r,o))),
r.__beforeBegin=null,[T,L,P].forEach((e=>e(r,o))),r.isCompiled=!0;let c=null
;return"object"==typeof r.keywords&&r.keywords.$pattern&&(r.keywords=Object.assign({},r.keywords),
c=r.keywords.$pattern,
delete r.keywords.$pattern),c=c||/\w+/,r.keywords&&(r.keywords=C(r.keywords,e.case_insensitive)),
a.keywordPatternRe=t(c,!0),
o&&(r.begin||(r.begin=/\B|\b/),a.beginRe=t(a.begin),r.end||r.endsWithParent||(r.end=/\B|\b/),
r.end&&(a.endRe=t(a.end)),
a.terminatorEnd=l(a.end)||"",r.endsWithParent&&o.terminatorEnd&&(a.terminatorEnd+=(r.end?"|":"")+o.terminatorEnd)),
r.illegal&&(a.illegalRe=t(r.illegal)),
r.contains||(r.contains=[]),r.contains=[].concat(...r.contains.map((e=>(e=>(e.variants&&!e.cachedVariants&&(e.cachedVariants=e.variants.map((t=>i(e,{
variants:null},t)))),e.cachedVariants?e.cachedVariants:V(e)?i(e,{
starts:e.starts?i(e.starts):null
}):Object.isFrozen(e)?i(e):e))("self"===e?r:e)))),r.contains.forEach((e=>{n(e,a)
})),r.starts&&n(r.starts,o),a.matcher=(e=>{const t=new s
;return e.contains.forEach((e=>t.addRule(e.begin,{rule:e,type:"begin"
}))),e.terminatorEnd&&t.addRule(e.terminatorEnd,{type:"end"
}),e.illegal&&t.addRule(e.illegal,{type:"illegal"}),t})(a),a}(e)}function V(e){
return!!e&&(e.endsWithParent||V(e.starts))}class q extends Error{
constructor(e,t){super(e),this.name="HTMLInjectionError",this.html=t}}
const J=n,Y=i,Q=Symbol("nomatch"),ee=n=>{
const i=Object.create(null),s=Object.create(null),r=[];let o=!0
;const a="Could not find the language '{}', did you forget to load/include a language module?",l={
disableAutodetect:!0,name:"Plain text",contains:[]};let p={
ignoreUnescapedHTML:!1,throwUnescapedHTML:!1,noHighlightRe:/^(no-?highlight)$/i,
languageDetectRe:/\blang(?:uage)?-([\w-]+)\b/i,classPrefix:"hljs-",
cssSelector:"pre code",languages:null,__emitter:c};function b(e){
return p.noHighlightRe.test(e)}function m(e,t,n){let i="",s=""
;"object"==typeof t?(i=e,
n=t.ignoreIllegals,s=t.language):(X("10.7.0","highlight(lang, code, ...args) has been deprecated."),
X("10.7.0","Please use highlight(code, options) instead.\nhttps://github.com/highlightjs/highlight.js/issues/2277"),
s=e,i=t),void 0===n&&(n=!0);const r={code:i,language:s};N("before:highlight",r)
;const o=r.result?r.result:E(r.language,r.code,n)
;return o.code=r.code,N("after:highlight",o),o}function E(e,n,s,r){
const c=Object.create(null);function l(){if(!N.keywords)return void M.addText(R)
;let e=0;N.keywordPatternRe.lastIndex=0;let t=N.keywordPatternRe.exec(R),n=""
;for(;t;){n+=R.substring(e,t.index)
;const s=w.case_insensitive?t[0].toLowerCase():t[0],r=(i=s,N.keywords[i]);if(r){
const[e,i]=r
;if(M.addText(n),n="",c[s]=(c[s]||0)+1,c[s]<=7&&(A+=i),e.startsWith("_"))n+=t[0];else{
const n=w.classNameAliases[e]||e;u(t[0],n)}}else n+=t[0]
;e=N.keywordPatternRe.lastIndex,t=N.keywordPatternRe.exec(R)}var i
;n+=R.substring(e),M.addText(n)}function g(){null!=N.subLanguage?(()=>{
if(""===R)return;let e=null;if("string"==typeof N.subLanguage){
if(!i[N.subLanguage])return void M.addText(R)
;e=E(N.subLanguage,R,!0,S[N.subLanguage]),S[N.subLanguage]=e._top
}else e=x(R,N.subLanguage.length?N.subLanguage:null)
;N.relevance>0&&(A+=e.relevance),M.__addSublanguage(e._emitter,e.language)
})():l(),R=""}function u(e,t){
""!==e&&(M.startScope(t),M.addText(e),M.endScope())}function d(e,t){let n=1
;const i=t.length-1;for(;n<=i;){if(!e._emit[n]){n++;continue}
const i=w.classNameAliases[e[n]]||e[n],s=t[n];i?u(s,i):(R=s,l(),R=""),n++}}
function h(e,t){
return e.scope&&"string"==typeof e.scope&&M.openNode(w.classNameAliases[e.scope]||e.scope),
e.beginScope&&(e.beginScope._wrap?(u(R,w.classNameAliases[e.beginScope._wrap]||e.beginScope._wrap),
R=""):e.beginScope._multi&&(d(e.beginScope,t),R="")),N=Object.create(e,{parent:{
value:N}}),N}function f(e,n,i){let s=((e,t)=>{const n=e&&e.exec(t)
;return n&&0===n.index})(e.endRe,i);if(s){if(e["on:end"]){const i=new t(e)
;e["on:end"](n,i),i.isMatchIgnored&&(s=!1)}if(s){
for(;e.endsParent&&e.parent;)e=e.parent;return e}}
if(e.endsWithParent)return f(e.parent,n,i)}function b(e){
return 0===N.matcher.regexIndex?(R+=e[0],1):(T=!0,0)}function m(e){
const t=e[0],i=n.substring(e.index),s=f(N,e,i);if(!s)return Q;const r=N
;N.endScope&&N.endScope._wrap?(g(),
u(t,N.endScope._wrap)):N.endScope&&N.endScope._multi?(g(),
d(N.endScope,e)):r.skip?R+=t:(r.returnEnd||r.excludeEnd||(R+=t),
g(),r.excludeEnd&&(R=t));do{
N.scope&&M.closeNode(),N.skip||N.subLanguage||(A+=N.relevance),N=N.parent
}while(N!==s.parent);return s.starts&&h(s.starts,e),r.returnEnd?0:t.length}
let _={};function y(i,r){const a=r&&r[0];if(R+=i,null==a)return g(),0
;if("begin"===_.type&&"end"===r.type&&_.index===r.index&&""===a){
if(R+=n.slice(r.index,r.index+1),!o){const t=Error(`0 width match regex (${e})`)
;throw t.languageName=e,t.badRule=_.rule,t}return 1}
if(_=r,"begin"===r.type)return(e=>{
const n=e[0],i=e.rule,s=new t(i),r=[i.__beforeBegin,i["on:begin"]]
;for(const t of r)if(t&&(t(e,s),s.isMatchIgnored))return b(n)
;return i.skip?R+=n:(i.excludeBegin&&(R+=n),
g(),i.returnBegin||i.excludeBegin||(R=n)),h(i,e),i.returnBegin?0:n.length})(r)
;if("illegal"===r.type&&!s){
const e=Error('Illegal lexeme "'+a+'" for mode "'+(N.scope||"<unnamed>")+'"')
;throw e.mode=N,e}if("end"===r.type){const e=m(r);if(e!==Q)return e}
if("illegal"===r.type&&""===a)return R+="\n",1
;if(I>1e5&&I>3*r.index)throw Error("potential infinite loop, way more iterations than matches")
;return R+=a,a.length}const w=O(e)
;if(!w)throw z(a.replace("{}",e)),Error('Unknown language: "'+e+'"')
;const k=Z(w);let v="",N=r||k;const S={},M=new p.__emitter(p);(()=>{const e=[]
;for(let t=N;t!==w;t=t.parent)t.scope&&e.unshift(t.scope)
;e.forEach((e=>M.openNode(e)))})();let R="",A=0,j=0,I=0,T=!1;try{
if(w.__emitTokens)w.__emitTokens(n,M);else{for(N.matcher.considerAll();;){
I++,T?T=!1:N.matcher.considerAll(),N.matcher.lastIndex=j
;const e=N.matcher.exec(n);if(!e)break;const t=y(n.substring(j,e.index),e)
;j=e.index+t}y(n.substring(j))}return M.finalize(),v=M.toHTML(),{language:e,
value:v,relevance:A,illegal:!1,_emitter:M,_top:N}}catch(t){
if(t.message&&t.message.includes("Illegal"))return{language:e,value:J(n),
illegal:!0,relevance:0,_illegalBy:{message:t.message,index:j,
context:n.slice(j-100,j+100),mode:t.mode,resultSoFar:v},_emitter:M};if(o)return{
language:e,value:J(n),illegal:!1,relevance:0,errorRaised:t,_emitter:M,_top:N}
;throw t}}function x(e,t){t=t||p.languages||Object.keys(i);const n=(e=>{
const t={value:J(e),illegal:!1,relevance:0,_top:l,_emitter:new p.__emitter(p)}
;return t._emitter.addText(e),t})(e),s=t.filter(O).filter(v).map((t=>E(t,e,!1)))
;s.unshift(n);const r=s.sort(((e,t)=>{
if(e.relevance!==t.relevance)return t.relevance-e.relevance
;if(e.language&&t.language){if(O(e.language).supersetOf===t.language)return 1
;if(O(t.language).supersetOf===e.language)return-1}return 0})),[o,a]=r,c=o
;return c.secondBest=a,c}function _(e){let t=null;const n=(e=>{
let t=e.className+" ";t+=e.parentNode?e.parentNode.className:""
;const n=p.languageDetectRe.exec(t);if(n){const t=O(n[1])
;return t||(W(a.replace("{}",n[1])),
W("Falling back to no-highlight mode for this block.",e)),t?n[1]:"no-highlight"}
return t.split(/\s+/).find((e=>b(e)||O(e)))})(e);if(b(n))return
;if(N("before:highlightElement",{el:e,language:n
}),e.dataset.highlighted)return void console.log("Element previously highlighted. To highlight again, first unset `dataset.highlighted`.",e)
;if(e.children.length>0&&(p.ignoreUnescapedHTML||(console.warn("One of your code blocks includes unescaped HTML. This is a potentially serious security risk."),
console.warn("https://github.com/highlightjs/highlight.js/wiki/security"),
console.warn("The element with unescaped HTML:"),
console.warn(e)),p.throwUnescapedHTML))throw new q("One of your code blocks includes unescaped HTML.",e.innerHTML)
;t=e;const i=t.textContent,r=n?m(i,{language:n,ignoreIllegals:!0}):x(i)
;e.innerHTML=r.value,e.dataset.highlighted="yes",((e,t,n)=>{const i=t&&s[t]||n
;e.classList.add("hljs"),e.classList.add("language-"+i)
})(e,n,r.language),e.result={language:r.language,re:r.relevance,
relevance:r.relevance},r.secondBest&&(e.secondBest={
language:r.secondBest.language,relevance:r.secondBest.relevance
}),N("after:highlightElement",{el:e,result:r,text:i})}let y=!1;function w(){
if("loading"===document.readyState)return y||window.addEventListener("DOMContentLoaded",(()=>{
w()}),!1),void(y=!0);document.querySelectorAll(p.cssSelector).forEach(_)}
function O(e){return e=(e||"").toLowerCase(),i[e]||i[s[e]]}
function k(e,{languageName:t}){"string"==typeof e&&(e=[e]),e.forEach((e=>{
s[e.toLowerCase()]=t}))}function v(e){const t=O(e)
;return t&&!t.disableAutodetect}function N(e,t){const n=e;r.forEach((e=>{
e[n]&&e[n](t)}))}Object.assign(n,{highlight:m,highlightAuto:x,highlightAll:w,
highlightElement:_,
highlightBlock:e=>(X("10.7.0","highlightBlock will be removed entirely in v12.0"),
X("10.7.0","Please use highlightElement now."),_(e)),configure:e=>{p=Y(p,e)},
initHighlighting:()=>{
w(),X("10.6.0","initHighlighting() deprecated. Use highlightAll() now.")},
initHighlightingOnLoad:()=>{
w(),X("10.6.0","initHighlightingOnLoad() deprecated. Use highlightAll() now.")
},registerLanguage:(e,t)=>{let s=null;try{s=t(n)}catch(t){
if(z("Language definition for '{}' could not be registered.".replace("{}",e)),
!o)throw t;z(t),s=l}
s.name||(s.name=e),i[e]=s,s.rawDefinition=t.bind(null,n),s.aliases&&k(s.aliases,{
languageName:e})},unregisterLanguage:e=>{delete i[e]
;for(const t of Object.keys(s))s[t]===e&&delete s[t]},
listLanguages:()=>Object.keys(i),getLanguage:O,registerAliases:k,
autoDetection:v,inherit:Y,addPlugin:e=>{(e=>{
e["before:highlightBlock"]&&!e["before:highlightElement"]&&(e["before:highlightElement"]=t=>{
e["before:highlightBlock"](Object.assign({block:t.el},t))
}),e["after:highlightBlock"]&&!e["after:highlightElement"]&&(e["after:highlightElement"]=t=>{
e["after:highlightBlock"](Object.assign({block:t.el},t))})})(e),r.push(e)},
removePlugin:e=>{const t=r.indexOf(e);-1!==t&&r.splice(t,1)}}),n.debugMode=()=>{
o=!1},n.safeMode=()=>{o=!0},n.versionString="11.11.1",n.regex={concat:h,
lookahead:g,either:f,optional:d,anyNumberOfTimes:u}
;for(const t in A)"object"==typeof A[t]&&e(A[t]);return Object.assign(n,A),n
},te=ee({});te.newInstance=()=>ee({});export{te as default};
@@ -1,417 +0,0 @@
/*! `bash` grammar compiled for Highlight.js 11.11.1 */
var hljsGrammar = (function () {
'use strict';
/*
Language: Bash
Author: vah <vahtenberg@gmail.com>
Contributrors: Benjamin Pannell <contact@sierrasoftworks.com>
Website: https://www.gnu.org/software/bash/
Category: common, scripting
*/
/** @type LanguageFn */
function bash(hljs) {
const regex = hljs.regex;
const VAR = {};
const BRACED_VAR = {
begin: /\$\{/,
end: /\}/,
contains: [
"self",
{
begin: /:-/,
contains: [ VAR ]
} // default values
]
};
Object.assign(VAR, {
className: 'variable',
variants: [
{ begin: regex.concat(/\$[\w\d#@][\w\d_]*/,
// negative look-ahead tries to avoid matching patterns that are not
// Perl at all like $ident$, @ident@, etc.
`(?![\\w\\d])(?![$])`) },
BRACED_VAR
]
});
const SUBST = {
className: 'subst',
begin: /\$\(/,
end: /\)/,
contains: [ hljs.BACKSLASH_ESCAPE ]
};
const COMMENT = hljs.inherit(
hljs.COMMENT(),
{
match: [
/(^|\s)/,
/#.*$/
],
scope: {
2: 'comment'
}
}
);
const HERE_DOC = {
begin: /<<-?\s*(?=\w+)/,
starts: { contains: [
hljs.END_SAME_AS_BEGIN({
begin: /(\w+)/,
end: /(\w+)/,
className: 'string'
})
] }
};
const QUOTE_STRING = {
className: 'string',
begin: /"/,
end: /"/,
contains: [
hljs.BACKSLASH_ESCAPE,
VAR,
SUBST
]
};
SUBST.contains.push(QUOTE_STRING);
const ESCAPED_QUOTE = {
match: /\\"/
};
const APOS_STRING = {
className: 'string',
begin: /'/,
end: /'/
};
const ESCAPED_APOS = {
match: /\\'/
};
const ARITHMETIC = {
begin: /\$?\(\(/,
end: /\)\)/,
contains: [
{
begin: /\d+#[0-9a-f]+/,
className: "number"
},
hljs.NUMBER_MODE,
VAR
]
};
const SH_LIKE_SHELLS = [
"fish",
"bash",
"zsh",
"sh",
"csh",
"ksh",
"tcsh",
"dash",
"scsh",
];
const KNOWN_SHEBANG = hljs.SHEBANG({
binary: `(${SH_LIKE_SHELLS.join("|")})`,
relevance: 10
});
const FUNCTION = {
className: 'function',
begin: /\w[\w\d_]*\s*\(\s*\)\s*\{/,
returnBegin: true,
contains: [ hljs.inherit(hljs.TITLE_MODE, { begin: /\w[\w\d_]*/ }) ],
relevance: 0
};
const KEYWORDS = [
"if",
"then",
"else",
"elif",
"fi",
"time",
"for",
"while",
"until",
"in",
"do",
"done",
"case",
"esac",
"coproc",
"function",
"select"
];
const LITERALS = [
"true",
"false"
];
// to consume paths to prevent keyword matches inside them
const PATH_MODE = { match: /(\/[a-z._-]+)+/ };
// http://www.gnu.org/software/bash/manual/html_node/Shell-Builtin-Commands.html
const SHELL_BUILT_INS = [
"break",
"cd",
"continue",
"eval",
"exec",
"exit",
"export",
"getopts",
"hash",
"pwd",
"readonly",
"return",
"shift",
"test",
"times",
"trap",
"umask",
"unset"
];
const BASH_BUILT_INS = [
"alias",
"bind",
"builtin",
"caller",
"command",
"declare",
"echo",
"enable",
"help",
"let",
"local",
"logout",
"mapfile",
"printf",
"read",
"readarray",
"source",
"sudo",
"type",
"typeset",
"ulimit",
"unalias"
];
const ZSH_BUILT_INS = [
"autoload",
"bg",
"bindkey",
"bye",
"cap",
"chdir",
"clone",
"comparguments",
"compcall",
"compctl",
"compdescribe",
"compfiles",
"compgroups",
"compquote",
"comptags",
"comptry",
"compvalues",
"dirs",
"disable",
"disown",
"echotc",
"echoti",
"emulate",
"fc",
"fg",
"float",
"functions",
"getcap",
"getln",
"history",
"integer",
"jobs",
"kill",
"limit",
"log",
"noglob",
"popd",
"print",
"pushd",
"pushln",
"rehash",
"sched",
"setcap",
"setopt",
"stat",
"suspend",
"ttyctl",
"unfunction",
"unhash",
"unlimit",
"unsetopt",
"vared",
"wait",
"whence",
"where",
"which",
"zcompile",
"zformat",
"zftp",
"zle",
"zmodload",
"zparseopts",
"zprof",
"zpty",
"zregexparse",
"zsocket",
"zstyle",
"ztcp"
];
const GNU_CORE_UTILS = [
"chcon",
"chgrp",
"chown",
"chmod",
"cp",
"dd",
"df",
"dir",
"dircolors",
"ln",
"ls",
"mkdir",
"mkfifo",
"mknod",
"mktemp",
"mv",
"realpath",
"rm",
"rmdir",
"shred",
"sync",
"touch",
"truncate",
"vdir",
"b2sum",
"base32",
"base64",
"cat",
"cksum",
"comm",
"csplit",
"cut",
"expand",
"fmt",
"fold",
"head",
"join",
"md5sum",
"nl",
"numfmt",
"od",
"paste",
"ptx",
"pr",
"sha1sum",
"sha224sum",
"sha256sum",
"sha384sum",
"sha512sum",
"shuf",
"sort",
"split",
"sum",
"tac",
"tail",
"tr",
"tsort",
"unexpand",
"uniq",
"wc",
"arch",
"basename",
"chroot",
"date",
"dirname",
"du",
"echo",
"env",
"expr",
"factor",
// "false", // keyword literal already
"groups",
"hostid",
"id",
"link",
"logname",
"nice",
"nohup",
"nproc",
"pathchk",
"pinky",
"printenv",
"printf",
"pwd",
"readlink",
"runcon",
"seq",
"sleep",
"stat",
"stdbuf",
"stty",
"tee",
"test",
"timeout",
// "true", // keyword literal already
"tty",
"uname",
"unlink",
"uptime",
"users",
"who",
"whoami",
"yes"
];
return {
name: 'Bash',
aliases: [
'sh',
'zsh'
],
keywords: {
$pattern: /\b[a-z][a-z0-9._-]+\b/,
keyword: KEYWORDS,
literal: LITERALS,
built_in: [
...SHELL_BUILT_INS,
...BASH_BUILT_INS,
// Shell modifiers
"set",
"shopt",
...ZSH_BUILT_INS,
...GNU_CORE_UTILS
]
},
contains: [
KNOWN_SHEBANG, // to catch known shells and boost relevancy
hljs.SHEBANG(), // to catch unknown shells but still highlight the shebang
FUNCTION,
ARITHMETIC,
COMMENT,
HERE_DOC,
PATH_MODE,
QUOTE_STRING,
ESCAPED_QUOTE,
APOS_STRING,
ESCAPED_APOS,
VAR
]
};
}
return bash;
})();
;
export default hljsGrammar;
-21
View File
@@ -1,21 +0,0 @@
/*! `bash` grammar compiled for Highlight.js 11.11.1 */
var hljsGrammar=(()=>{"use strict";return e=>{const s=e.regex,t={},a={
begin:/\$\{/,end:/\}/,contains:["self",{begin:/:-/,contains:[t]}]}
;Object.assign(t,{className:"variable",variants:[{
begin:s.concat(/\$[\w\d#@][\w\d_]*/,"(?![\\w\\d])(?![$])")},a]});const n={
className:"subst",begin:/\$\(/,end:/\)/,contains:[e.BACKSLASH_ESCAPE]
},c=e.inherit(e.COMMENT(),{match:[/(^|\s)/,/#.*$/],scope:{2:"comment"}}),i={
begin:/<<-?\s*(?=\w+)/,starts:{contains:[e.END_SAME_AS_BEGIN({begin:/(\w+)/,
end:/(\w+)/,className:"string"})]}},o={className:"string",begin:/"/,end:/"/,
contains:[e.BACKSLASH_ESCAPE,t,n]};n.contains.push(o);const r={begin:/\$?\(\(/,
end:/\)\)/,contains:[{begin:/\d+#[0-9a-f]+/,className:"number"},e.NUMBER_MODE,t]
},l=e.SHEBANG({binary:"(fish|bash|zsh|sh|csh|ksh|tcsh|dash|scsh)",relevance:10
}),m={className:"function",begin:/\w[\w\d_]*\s*\(\s*\)\s*\{/,returnBegin:!0,
contains:[e.inherit(e.TITLE_MODE,{begin:/\w[\w\d_]*/})],relevance:0};return{
name:"Bash",aliases:["sh","zsh"],keywords:{$pattern:/\b[a-z][a-z0-9._-]+\b/,
keyword:["if","then","else","elif","fi","time","for","while","until","in","do","done","case","esac","coproc","function","select"],
literal:["true","false"],
built_in:["break","cd","continue","eval","exec","exit","export","getopts","hash","pwd","readonly","return","shift","test","times","trap","umask","unset","alias","bind","builtin","caller","command","declare","echo","enable","help","let","local","logout","mapfile","printf","read","readarray","source","sudo","type","typeset","ulimit","unalias","set","shopt","autoload","bg","bindkey","bye","cap","chdir","clone","comparguments","compcall","compctl","compdescribe","compfiles","compgroups","compquote","comptags","comptry","compvalues","dirs","disable","disown","echotc","echoti","emulate","fc","fg","float","functions","getcap","getln","history","integer","jobs","kill","limit","log","noglob","popd","print","pushd","pushln","rehash","sched","setcap","setopt","stat","suspend","ttyctl","unfunction","unhash","unlimit","unsetopt","vared","wait","whence","where","which","zcompile","zformat","zftp","zle","zmodload","zparseopts","zprof","zpty","zregexparse","zsocket","zstyle","ztcp","chcon","chgrp","chown","chmod","cp","dd","df","dir","dircolors","ln","ls","mkdir","mkfifo","mknod","mktemp","mv","realpath","rm","rmdir","shred","sync","touch","truncate","vdir","b2sum","base32","base64","cat","cksum","comm","csplit","cut","expand","fmt","fold","head","join","md5sum","nl","numfmt","od","paste","ptx","pr","sha1sum","sha224sum","sha256sum","sha384sum","sha512sum","shuf","sort","split","sum","tac","tail","tr","tsort","unexpand","uniq","wc","arch","basename","chroot","date","dirname","du","echo","env","expr","factor","groups","hostid","id","link","logname","nice","nohup","nproc","pathchk","pinky","printenv","printf","pwd","readlink","runcon","seq","sleep","stat","stdbuf","stty","tee","test","timeout","tty","uname","unlink","uptime","users","who","whoami","yes"]
},contains:[l,e.SHEBANG(),m,r,c,i,{match:/(\/[a-z._-]+)+/},o,{match:/\\"/},{
className:"string",begin:/'/,end:/'/},{match:/\\'/},t]}}})()
;export default hljsGrammar;
@@ -1,341 +0,0 @@
/*! `c` grammar compiled for Highlight.js 11.11.1 */
var hljsGrammar = (function () {
'use strict';
/*
Language: C
Category: common, system
Website: https://en.wikipedia.org/wiki/C_(programming_language)
*/
/** @type LanguageFn */
function c(hljs) {
const regex = hljs.regex;
// added for historic reasons because `hljs.C_LINE_COMMENT_MODE` does
// not include such support nor can we be sure all the grammars depending
// on it would desire this behavior
const C_LINE_COMMENT_MODE = hljs.COMMENT('//', '$', { contains: [ { begin: /\\\n/ } ] });
const DECLTYPE_AUTO_RE = 'decltype\\(auto\\)';
const NAMESPACE_RE = '[a-zA-Z_]\\w*::';
const TEMPLATE_ARGUMENT_RE = '<[^<>]+>';
const FUNCTION_TYPE_RE = '('
+ DECLTYPE_AUTO_RE + '|'
+ regex.optional(NAMESPACE_RE)
+ '[a-zA-Z_]\\w*' + regex.optional(TEMPLATE_ARGUMENT_RE)
+ ')';
const TYPES = {
className: 'type',
variants: [
{ begin: '\\b[a-z\\d_]*_t\\b' },
{ match: /\batomic_[a-z]{3,6}\b/ }
]
};
// https://en.cppreference.com/w/cpp/language/escape
// \\ \x \xFF \u2837 \u00323747 \374
const CHARACTER_ESCAPES = '\\\\(x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4,8}|[0-7]{3}|\\S)';
const STRINGS = {
className: 'string',
variants: [
{
begin: '(u8?|U|L)?"',
end: '"',
illegal: '\\n',
contains: [ hljs.BACKSLASH_ESCAPE ]
},
{
begin: '(u8?|U|L)?\'(' + CHARACTER_ESCAPES + "|.)",
end: '\'',
illegal: '.'
},
hljs.END_SAME_AS_BEGIN({
begin: /(?:u8?|U|L)?R"([^()\\ ]{0,16})\(/,
end: /\)([^()\\ ]{0,16})"/
})
]
};
const NUMBERS = {
className: 'number',
variants: [
{ match: /\b(0b[01']+)/ },
{ match: /(-?)\b([\d']+(\.[\d']*)?|\.[\d']+)((ll|LL|l|L)(u|U)?|(u|U)(ll|LL|l|L)?|f|F|b|B)/ },
{ match: /(-?)\b(0[xX][a-fA-F0-9]+(?:'[a-fA-F0-9]+)*(?:\.[a-fA-F0-9]*(?:'[a-fA-F0-9]*)*)?(?:[pP][-+]?[0-9]+)?(l|L)?(u|U)?)/ },
{ match: /(-?)\b\d+(?:'\d+)*(?:\.\d*(?:'\d*)*)?(?:[eE][-+]?\d+)?/ }
],
relevance: 0
};
const PREPROCESSOR = {
className: 'meta',
begin: /#\s*[a-z]+\b/,
end: /$/,
keywords: { keyword:
'if else elif endif define undef warning error line '
+ 'pragma _Pragma ifdef ifndef elifdef elifndef include' },
contains: [
{
begin: /\\\n/,
relevance: 0
},
hljs.inherit(STRINGS, { className: 'string' }),
{
className: 'string',
begin: /<.*?>/
},
C_LINE_COMMENT_MODE,
hljs.C_BLOCK_COMMENT_MODE
]
};
const TITLE_MODE = {
className: 'title',
begin: regex.optional(NAMESPACE_RE) + hljs.IDENT_RE,
relevance: 0
};
const FUNCTION_TITLE = regex.optional(NAMESPACE_RE) + hljs.IDENT_RE + '\\s*\\(';
const C_KEYWORDS = [
"asm",
"auto",
"break",
"case",
"continue",
"default",
"do",
"else",
"enum",
"extern",
"for",
"fortran",
"goto",
"if",
"inline",
"register",
"restrict",
"return",
"sizeof",
"typeof",
"typeof_unqual",
"struct",
"switch",
"typedef",
"union",
"volatile",
"while",
"_Alignas",
"_Alignof",
"_Atomic",
"_Generic",
"_Noreturn",
"_Static_assert",
"_Thread_local",
// aliases
"alignas",
"alignof",
"noreturn",
"static_assert",
"thread_local",
// not a C keyword but is, for all intents and purposes, treated exactly like one.
"_Pragma"
];
const C_TYPES = [
"float",
"double",
"signed",
"unsigned",
"int",
"short",
"long",
"char",
"void",
"_Bool",
"_BitInt",
"_Complex",
"_Imaginary",
"_Decimal32",
"_Decimal64",
"_Decimal96",
"_Decimal128",
"_Decimal64x",
"_Decimal128x",
"_Float16",
"_Float32",
"_Float64",
"_Float128",
"_Float32x",
"_Float64x",
"_Float128x",
// modifiers
"const",
"static",
"constexpr",
// aliases
"complex",
"bool",
"imaginary"
];
const KEYWORDS = {
keyword: C_KEYWORDS,
type: C_TYPES,
literal: 'true false NULL',
// TODO: apply hinting work similar to what was done in cpp.js
built_in: 'std string wstring cin cout cerr clog stdin stdout stderr stringstream istringstream ostringstream '
+ 'auto_ptr deque list queue stack vector map set pair bitset multiset multimap unordered_set '
+ 'unordered_map unordered_multiset unordered_multimap priority_queue make_pair array shared_ptr abort terminate abs acos '
+ 'asin atan2 atan calloc ceil cosh cos exit exp fabs floor fmod fprintf fputs free frexp '
+ 'fscanf future isalnum isalpha iscntrl isdigit isgraph islower isprint ispunct isspace isupper '
+ 'isxdigit tolower toupper labs ldexp log10 log malloc realloc memchr memcmp memcpy memset modf pow '
+ 'printf putchar puts scanf sinh sin snprintf sprintf sqrt sscanf strcat strchr strcmp '
+ 'strcpy strcspn strlen strncat strncmp strncpy strpbrk strrchr strspn strstr tanh tan '
+ 'vfprintf vprintf vsprintf endl initializer_list unique_ptr',
};
const EXPRESSION_CONTAINS = [
PREPROCESSOR,
TYPES,
C_LINE_COMMENT_MODE,
hljs.C_BLOCK_COMMENT_MODE,
NUMBERS,
STRINGS
];
const EXPRESSION_CONTEXT = {
// This mode covers expression context where we can't expect a function
// definition and shouldn't highlight anything that looks like one:
// `return some()`, `else if()`, `(x*sum(1, 2))`
variants: [
{
begin: /=/,
end: /;/
},
{
begin: /\(/,
end: /\)/
},
{
beginKeywords: 'new throw return else',
end: /;/
}
],
keywords: KEYWORDS,
contains: EXPRESSION_CONTAINS.concat([
{
begin: /\(/,
end: /\)/,
keywords: KEYWORDS,
contains: EXPRESSION_CONTAINS.concat([ 'self' ]),
relevance: 0
}
]),
relevance: 0
};
const FUNCTION_DECLARATION = {
begin: '(' + FUNCTION_TYPE_RE + '[\\*&\\s]+)+' + FUNCTION_TITLE,
returnBegin: true,
end: /[{;=]/,
excludeEnd: true,
keywords: KEYWORDS,
illegal: /[^\w\s\*&:<>.]/,
contains: [
{ // to prevent it from being confused as the function title
begin: DECLTYPE_AUTO_RE,
keywords: KEYWORDS,
relevance: 0
},
{
begin: FUNCTION_TITLE,
returnBegin: true,
contains: [ hljs.inherit(TITLE_MODE, { className: "title.function" }) ],
relevance: 0
},
// allow for multiple declarations, e.g.:
// extern void f(int), g(char);
{
relevance: 0,
match: /,/
},
{
className: 'params',
begin: /\(/,
end: /\)/,
keywords: KEYWORDS,
relevance: 0,
contains: [
C_LINE_COMMENT_MODE,
hljs.C_BLOCK_COMMENT_MODE,
STRINGS,
NUMBERS,
TYPES,
// Count matching parentheses.
{
begin: /\(/,
end: /\)/,
keywords: KEYWORDS,
relevance: 0,
contains: [
'self',
C_LINE_COMMENT_MODE,
hljs.C_BLOCK_COMMENT_MODE,
STRINGS,
NUMBERS,
TYPES
]
}
]
},
TYPES,
C_LINE_COMMENT_MODE,
hljs.C_BLOCK_COMMENT_MODE,
PREPROCESSOR
]
};
return {
name: "C",
aliases: [ 'h' ],
keywords: KEYWORDS,
// Until differentiations are added between `c` and `cpp`, `c` will
// not be auto-detected to avoid auto-detect conflicts between C and C++
disableAutodetect: true,
illegal: '</',
contains: [].concat(
EXPRESSION_CONTEXT,
FUNCTION_DECLARATION,
EXPRESSION_CONTAINS,
[
PREPROCESSOR,
{
begin: hljs.IDENT_RE + '::',
keywords: KEYWORDS
},
{
className: 'class',
beginKeywords: 'enum class struct union',
end: /[{;:<>=]/,
contains: [
{ beginKeywords: "final class struct" },
hljs.TITLE_MODE
]
}
]),
exports: {
preprocessor: PREPROCESSOR,
strings: STRINGS,
keywords: KEYWORDS
}
};
}
return c;
})();
;
export default hljsGrammar;
-41
View File
@@ -1,41 +0,0 @@
/*! `c` grammar compiled for Highlight.js 11.11.1 */
var hljsGrammar=(()=>{"use strict";return e=>{
const t=e.regex,a=e.COMMENT("//","$",{contains:[{begin:/\\\n/}]
}),n="decltype\\(auto\\)",s="[a-zA-Z_]\\w*::",r="("+n+"|"+t.optional(s)+"[a-zA-Z_]\\w*"+t.optional("<[^<>]+>")+")",i={
className:"type",variants:[{begin:"\\b[a-z\\d_]*_t\\b"},{
match:/\batomic_[a-z]{3,6}\b/}]},l={className:"string",variants:[{
begin:'(u8?|U|L)?"',end:'"',illegal:"\\n",contains:[e.BACKSLASH_ESCAPE]},{
begin:"(u8?|U|L)?'(\\\\(x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4,8}|[0-7]{3}|\\S)|.)",
end:"'",illegal:"."},e.END_SAME_AS_BEGIN({
begin:/(?:u8?|U|L)?R"([^()\\ ]{0,16})\(/,end:/\)([^()\\ ]{0,16})"/})]},o={
className:"number",variants:[{match:/\b(0b[01']+)/},{
match:/(-?)\b([\d']+(\.[\d']*)?|\.[\d']+)((ll|LL|l|L)(u|U)?|(u|U)(ll|LL|l|L)?|f|F|b|B)/
},{
match:/(-?)\b(0[xX][a-fA-F0-9]+(?:'[a-fA-F0-9]+)*(?:\.[a-fA-F0-9]*(?:'[a-fA-F0-9]*)*)?(?:[pP][-+]?[0-9]+)?(l|L)?(u|U)?)/
},{match:/(-?)\b\d+(?:'\d+)*(?:\.\d*(?:'\d*)*)?(?:[eE][-+]?\d+)?/}],relevance:0
},c={className:"meta",begin:/#\s*[a-z]+\b/,end:/$/,keywords:{
keyword:"if else elif endif define undef warning error line pragma _Pragma ifdef ifndef elifdef elifndef include"
},contains:[{begin:/\\\n/,relevance:0},e.inherit(l,{className:"string"}),{
className:"string",begin:/<.*?>/},a,e.C_BLOCK_COMMENT_MODE]},d={
className:"title",begin:t.optional(s)+e.IDENT_RE,relevance:0
},m=t.optional(s)+e.IDENT_RE+"\\s*\\(",_={
keyword:["asm","auto","break","case","continue","default","do","else","enum","extern","for","fortran","goto","if","inline","register","restrict","return","sizeof","typeof","typeof_unqual","struct","switch","typedef","union","volatile","while","_Alignas","_Alignof","_Atomic","_Generic","_Noreturn","_Static_assert","_Thread_local","alignas","alignof","noreturn","static_assert","thread_local","_Pragma"],
type:["float","double","signed","unsigned","int","short","long","char","void","_Bool","_BitInt","_Complex","_Imaginary","_Decimal32","_Decimal64","_Decimal96","_Decimal128","_Decimal64x","_Decimal128x","_Float16","_Float32","_Float64","_Float128","_Float32x","_Float64x","_Float128x","const","static","constexpr","complex","bool","imaginary"],
literal:"true false NULL",
built_in:"std string wstring cin cout cerr clog stdin stdout stderr stringstream istringstream ostringstream auto_ptr deque list queue stack vector map set pair bitset multiset multimap unordered_set unordered_map unordered_multiset unordered_multimap priority_queue make_pair array shared_ptr abort terminate abs acos asin atan2 atan calloc ceil cosh cos exit exp fabs floor fmod fprintf fputs free frexp fscanf future isalnum isalpha iscntrl isdigit isgraph islower isprint ispunct isspace isupper isxdigit tolower toupper labs ldexp log10 log malloc realloc memchr memcmp memcpy memset modf pow printf putchar puts scanf sinh sin snprintf sprintf sqrt sscanf strcat strchr strcmp strcpy strcspn strlen strncat strncmp strncpy strpbrk strrchr strspn strstr tanh tan vfprintf vprintf vsprintf endl initializer_list unique_ptr"
},u=[c,i,a,e.C_BLOCK_COMMENT_MODE,o,l],p={variants:[{begin:/=/,end:/;/},{
begin:/\(/,end:/\)/},{beginKeywords:"new throw return else",end:/;/}],
keywords:_,contains:u.concat([{begin:/\(/,end:/\)/,keywords:_,
contains:u.concat(["self"]),relevance:0}]),relevance:0},f={
begin:"("+r+"[\\*&\\s]+)+"+m,returnBegin:!0,end:/[{;=]/,excludeEnd:!0,
keywords:_,illegal:/[^\w\s\*&:<>.]/,contains:[{begin:n,keywords:_,relevance:0},{
begin:m,returnBegin:!0,contains:[e.inherit(d,{className:"title.function"})],
relevance:0},{relevance:0,match:/,/},{className:"params",begin:/\(/,end:/\)/,
keywords:_,relevance:0,contains:[a,e.C_BLOCK_COMMENT_MODE,l,o,i,{begin:/\(/,
end:/\)/,keywords:_,relevance:0,contains:["self",a,e.C_BLOCK_COMMENT_MODE,l,o,i]
}]},i,a,e.C_BLOCK_COMMENT_MODE,c]};return{name:"C",aliases:["h"],keywords:_,
disableAutodetect:!0,illegal:"</",contains:[].concat(p,f,u,[c,{
begin:e.IDENT_RE+"::",keywords:_},{className:"class",
beginKeywords:"enum class struct union",end:/[{;:<>=]/,contains:[{
beginKeywords:"final class struct"},e.TITLE_MODE]}]),exports:{preprocessor:c,
strings:l,keywords:_}}}})();export default hljsGrammar;
@@ -1,613 +0,0 @@
/*! `cpp` grammar compiled for Highlight.js 11.11.1 */
var hljsGrammar = (function () {
'use strict';
/*
Language: C++
Category: common, system
Website: https://isocpp.org
*/
/** @type LanguageFn */
function cpp(hljs) {
const regex = hljs.regex;
// added for historic reasons because `hljs.C_LINE_COMMENT_MODE` does
// not include such support nor can we be sure all the grammars depending
// on it would desire this behavior
const C_LINE_COMMENT_MODE = hljs.COMMENT('//', '$', { contains: [ { begin: /\\\n/ } ] });
const DECLTYPE_AUTO_RE = 'decltype\\(auto\\)';
const NAMESPACE_RE = '[a-zA-Z_]\\w*::';
const TEMPLATE_ARGUMENT_RE = '<[^<>]+>';
const FUNCTION_TYPE_RE = '(?!struct)('
+ DECLTYPE_AUTO_RE + '|'
+ regex.optional(NAMESPACE_RE)
+ '[a-zA-Z_]\\w*' + regex.optional(TEMPLATE_ARGUMENT_RE)
+ ')';
const CPP_PRIMITIVE_TYPES = {
className: 'type',
begin: '\\b[a-z\\d_]*_t\\b'
};
// https://en.cppreference.com/w/cpp/language/escape
// \\ \x \xFF \u2837 \u00323747 \374
const CHARACTER_ESCAPES = '\\\\(x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4,8}|[0-7]{3}|\\S)';
const STRINGS = {
className: 'string',
variants: [
{
begin: '(u8?|U|L)?"',
end: '"',
illegal: '\\n',
contains: [ hljs.BACKSLASH_ESCAPE ]
},
{
begin: '(u8?|U|L)?\'(' + CHARACTER_ESCAPES + '|.)',
end: '\'',
illegal: '.'
},
hljs.END_SAME_AS_BEGIN({
begin: /(?:u8?|U|L)?R"([^()\\ ]{0,16})\(/,
end: /\)([^()\\ ]{0,16})"/
})
]
};
const NUMBERS = {
className: 'number',
variants: [
// Floating-point literal.
{ begin:
"[+-]?(?:" // Leading sign.
// Decimal.
+ "(?:"
+"[0-9](?:'?[0-9])*\\.(?:[0-9](?:'?[0-9])*)?"
+ "|\\.[0-9](?:'?[0-9])*"
+ ")(?:[Ee][+-]?[0-9](?:'?[0-9])*)?"
+ "|[0-9](?:'?[0-9])*[Ee][+-]?[0-9](?:'?[0-9])*"
// Hexadecimal.
+ "|0[Xx](?:"
+"[0-9A-Fa-f](?:'?[0-9A-Fa-f])*(?:\\.(?:[0-9A-Fa-f](?:'?[0-9A-Fa-f])*)?)?"
+ "|\\.[0-9A-Fa-f](?:'?[0-9A-Fa-f])*"
+ ")[Pp][+-]?[0-9](?:'?[0-9])*"
+ ")(?:" // Literal suffixes.
+ "[Ff](?:16|32|64|128)?"
+ "|(BF|bf)16"
+ "|[Ll]"
+ "|" // Literal suffix is optional.
+ ")"
},
// Integer literal.
{ begin:
"[+-]?\\b(?:" // Leading sign.
+ "0[Bb][01](?:'?[01])*" // Binary.
+ "|0[Xx][0-9A-Fa-f](?:'?[0-9A-Fa-f])*" // Hexadecimal.
+ "|0(?:'?[0-7])*" // Octal or just a lone zero.
+ "|[1-9](?:'?[0-9])*" // Decimal.
+ ")(?:" // Literal suffixes.
+ "[Uu](?:LL?|ll?)"
+ "|[Uu][Zz]?"
+ "|(?:LL?|ll?)[Uu]?"
+ "|[Zz][Uu]"
+ "|" // Literal suffix is optional.
+ ")"
// Note: there are user-defined literal suffixes too, but perhaps having the custom suffix not part of the
// literal highlight actually makes it stand out more.
}
],
relevance: 0
};
const PREPROCESSOR = {
className: 'meta',
begin: /#\s*[a-z]+\b/,
end: /$/,
keywords: { keyword:
'if else elif endif define undef warning error line '
+ 'pragma _Pragma ifdef ifndef include' },
contains: [
{
begin: /\\\n/,
relevance: 0
},
hljs.inherit(STRINGS, { className: 'string' }),
{
className: 'string',
begin: /<.*?>/
},
C_LINE_COMMENT_MODE,
hljs.C_BLOCK_COMMENT_MODE
]
};
const TITLE_MODE = {
className: 'title',
begin: regex.optional(NAMESPACE_RE) + hljs.IDENT_RE,
relevance: 0
};
const FUNCTION_TITLE = regex.optional(NAMESPACE_RE) + hljs.IDENT_RE + '\\s*\\(';
// https://en.cppreference.com/w/cpp/keyword
const RESERVED_KEYWORDS = [
'alignas',
'alignof',
'and',
'and_eq',
'asm',
'atomic_cancel',
'atomic_commit',
'atomic_noexcept',
'auto',
'bitand',
'bitor',
'break',
'case',
'catch',
'class',
'co_await',
'co_return',
'co_yield',
'compl',
'concept',
'const_cast|10',
'consteval',
'constexpr',
'constinit',
'continue',
'decltype',
'default',
'delete',
'do',
'dynamic_cast|10',
'else',
'enum',
'explicit',
'export',
'extern',
'false',
'final',
'for',
'friend',
'goto',
'if',
'import',
'inline',
'module',
'mutable',
'namespace',
'new',
'noexcept',
'not',
'not_eq',
'nullptr',
'operator',
'or',
'or_eq',
'override',
'private',
'protected',
'public',
'reflexpr',
'register',
'reinterpret_cast|10',
'requires',
'return',
'sizeof',
'static_assert',
'static_cast|10',
'struct',
'switch',
'synchronized',
'template',
'this',
'thread_local',
'throw',
'transaction_safe',
'transaction_safe_dynamic',
'true',
'try',
'typedef',
'typeid',
'typename',
'union',
'using',
'virtual',
'volatile',
'while',
'xor',
'xor_eq'
];
// https://en.cppreference.com/w/cpp/keyword
const RESERVED_TYPES = [
'bool',
'char',
'char16_t',
'char32_t',
'char8_t',
'double',
'float',
'int',
'long',
'short',
'void',
'wchar_t',
'unsigned',
'signed',
'const',
'static'
];
const TYPE_HINTS = [
'any',
'auto_ptr',
'barrier',
'binary_semaphore',
'bitset',
'complex',
'condition_variable',
'condition_variable_any',
'counting_semaphore',
'deque',
'false_type',
'flat_map',
'flat_set',
'future',
'imaginary',
'initializer_list',
'istringstream',
'jthread',
'latch',
'lock_guard',
'multimap',
'multiset',
'mutex',
'optional',
'ostringstream',
'packaged_task',
'pair',
'promise',
'priority_queue',
'queue',
'recursive_mutex',
'recursive_timed_mutex',
'scoped_lock',
'set',
'shared_future',
'shared_lock',
'shared_mutex',
'shared_timed_mutex',
'shared_ptr',
'stack',
'string_view',
'stringstream',
'timed_mutex',
'thread',
'true_type',
'tuple',
'unique_lock',
'unique_ptr',
'unordered_map',
'unordered_multimap',
'unordered_multiset',
'unordered_set',
'variant',
'vector',
'weak_ptr',
'wstring',
'wstring_view'
];
const FUNCTION_HINTS = [
'abort',
'abs',
'acos',
'apply',
'as_const',
'asin',
'atan',
'atan2',
'calloc',
'ceil',
'cerr',
'cin',
'clog',
'cos',
'cosh',
'cout',
'declval',
'endl',
'exchange',
'exit',
'exp',
'fabs',
'floor',
'fmod',
'forward',
'fprintf',
'fputs',
'free',
'frexp',
'fscanf',
'future',
'invoke',
'isalnum',
'isalpha',
'iscntrl',
'isdigit',
'isgraph',
'islower',
'isprint',
'ispunct',
'isspace',
'isupper',
'isxdigit',
'labs',
'launder',
'ldexp',
'log',
'log10',
'make_pair',
'make_shared',
'make_shared_for_overwrite',
'make_tuple',
'make_unique',
'malloc',
'memchr',
'memcmp',
'memcpy',
'memset',
'modf',
'move',
'pow',
'printf',
'putchar',
'puts',
'realloc',
'scanf',
'sin',
'sinh',
'snprintf',
'sprintf',
'sqrt',
'sscanf',
'std',
'stderr',
'stdin',
'stdout',
'strcat',
'strchr',
'strcmp',
'strcpy',
'strcspn',
'strlen',
'strncat',
'strncmp',
'strncpy',
'strpbrk',
'strrchr',
'strspn',
'strstr',
'swap',
'tan',
'tanh',
'terminate',
'to_underlying',
'tolower',
'toupper',
'vfprintf',
'visit',
'vprintf',
'vsprintf'
];
const LITERALS = [
'NULL',
'false',
'nullopt',
'nullptr',
'true'
];
// https://en.cppreference.com/w/cpp/keyword
const BUILT_IN = [ '_Pragma' ];
const CPP_KEYWORDS = {
type: RESERVED_TYPES,
keyword: RESERVED_KEYWORDS,
literal: LITERALS,
built_in: BUILT_IN,
_type_hints: TYPE_HINTS
};
const FUNCTION_DISPATCH = {
className: 'function.dispatch',
relevance: 0,
keywords: {
// Only for relevance, not highlighting.
_hint: FUNCTION_HINTS },
begin: regex.concat(
/\b/,
/(?!decltype)/,
/(?!if)/,
/(?!for)/,
/(?!switch)/,
/(?!while)/,
hljs.IDENT_RE,
regex.lookahead(/(<[^<>]+>|)\s*\(/))
};
const EXPRESSION_CONTAINS = [
FUNCTION_DISPATCH,
PREPROCESSOR,
CPP_PRIMITIVE_TYPES,
C_LINE_COMMENT_MODE,
hljs.C_BLOCK_COMMENT_MODE,
NUMBERS,
STRINGS
];
const EXPRESSION_CONTEXT = {
// This mode covers expression context where we can't expect a function
// definition and shouldn't highlight anything that looks like one:
// `return some()`, `else if()`, `(x*sum(1, 2))`
variants: [
{
begin: /=/,
end: /;/
},
{
begin: /\(/,
end: /\)/
},
{
beginKeywords: 'new throw return else',
end: /;/
}
],
keywords: CPP_KEYWORDS,
contains: EXPRESSION_CONTAINS.concat([
{
begin: /\(/,
end: /\)/,
keywords: CPP_KEYWORDS,
contains: EXPRESSION_CONTAINS.concat([ 'self' ]),
relevance: 0
}
]),
relevance: 0
};
const FUNCTION_DECLARATION = {
className: 'function',
begin: '(' + FUNCTION_TYPE_RE + '[\\*&\\s]+)+' + FUNCTION_TITLE,
returnBegin: true,
end: /[{;=]/,
excludeEnd: true,
keywords: CPP_KEYWORDS,
illegal: /[^\w\s\*&:<>.]/,
contains: [
{ // to prevent it from being confused as the function title
begin: DECLTYPE_AUTO_RE,
keywords: CPP_KEYWORDS,
relevance: 0
},
{
begin: FUNCTION_TITLE,
returnBegin: true,
contains: [ TITLE_MODE ],
relevance: 0
},
// needed because we do not have look-behind on the below rule
// to prevent it from grabbing the final : in a :: pair
{
begin: /::/,
relevance: 0
},
// initializers
{
begin: /:/,
endsWithParent: true,
contains: [
STRINGS,
NUMBERS
]
},
// allow for multiple declarations, e.g.:
// extern void f(int), g(char);
{
relevance: 0,
match: /,/
},
{
className: 'params',
begin: /\(/,
end: /\)/,
keywords: CPP_KEYWORDS,
relevance: 0,
contains: [
C_LINE_COMMENT_MODE,
hljs.C_BLOCK_COMMENT_MODE,
STRINGS,
NUMBERS,
CPP_PRIMITIVE_TYPES,
// Count matching parentheses.
{
begin: /\(/,
end: /\)/,
keywords: CPP_KEYWORDS,
relevance: 0,
contains: [
'self',
C_LINE_COMMENT_MODE,
hljs.C_BLOCK_COMMENT_MODE,
STRINGS,
NUMBERS,
CPP_PRIMITIVE_TYPES
]
}
]
},
CPP_PRIMITIVE_TYPES,
C_LINE_COMMENT_MODE,
hljs.C_BLOCK_COMMENT_MODE,
PREPROCESSOR
]
};
return {
name: 'C++',
aliases: [
'cc',
'c++',
'h++',
'hpp',
'hh',
'hxx',
'cxx'
],
keywords: CPP_KEYWORDS,
illegal: '</',
classNameAliases: { 'function.dispatch': 'built_in' },
contains: [].concat(
EXPRESSION_CONTEXT,
FUNCTION_DECLARATION,
FUNCTION_DISPATCH,
EXPRESSION_CONTAINS,
[
PREPROCESSOR,
{ // containers: ie, `vector <int> rooms (9);`
begin: '\\b(deque|list|queue|priority_queue|pair|stack|vector|map|set|bitset|multiset|multimap|unordered_map|unordered_set|unordered_multiset|unordered_multimap|array|tuple|optional|variant|function|flat_map|flat_set)\\s*<(?!<)',
end: '>',
keywords: CPP_KEYWORDS,
contains: [
'self',
CPP_PRIMITIVE_TYPES
]
},
{
begin: hljs.IDENT_RE + '::',
keywords: CPP_KEYWORDS
},
{
match: [
// extra complexity to deal with `enum class` and `enum struct`
/\b(?:enum(?:\s+(?:class|struct))?|class|struct|union)/,
/\s+/,
/\w+/
],
className: {
1: 'keyword',
3: 'title.class'
}
}
])
};
}
return cpp;
})();
;
export default hljsGrammar;
-46
View File
@@ -1,46 +0,0 @@
/*! `cpp` grammar compiled for Highlight.js 11.11.1 */
var hljsGrammar=(()=>{"use strict";return e=>{
const t=e.regex,a=e.COMMENT("//","$",{contains:[{begin:/\\\n/}]
}),n="decltype\\(auto\\)",r="[a-zA-Z_]\\w*::",i="(?!struct)("+n+"|"+t.optional(r)+"[a-zA-Z_]\\w*"+t.optional("<[^<>]+>")+")",s={
className:"type",begin:"\\b[a-z\\d_]*_t\\b"},c={className:"string",variants:[{
begin:'(u8?|U|L)?"',end:'"',illegal:"\\n",contains:[e.BACKSLASH_ESCAPE]},{
begin:"(u8?|U|L)?'(\\\\(x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4,8}|[0-7]{3}|\\S)|.)",
end:"'",illegal:"."},e.END_SAME_AS_BEGIN({
begin:/(?:u8?|U|L)?R"([^()\\ ]{0,16})\(/,end:/\)([^()\\ ]{0,16})"/})]},o={
className:"number",variants:[{
begin:"[+-]?(?:(?:[0-9](?:'?[0-9])*\\.(?:[0-9](?:'?[0-9])*)?|\\.[0-9](?:'?[0-9])*)(?:[Ee][+-]?[0-9](?:'?[0-9])*)?|[0-9](?:'?[0-9])*[Ee][+-]?[0-9](?:'?[0-9])*|0[Xx](?:[0-9A-Fa-f](?:'?[0-9A-Fa-f])*(?:\\.(?:[0-9A-Fa-f](?:'?[0-9A-Fa-f])*)?)?|\\.[0-9A-Fa-f](?:'?[0-9A-Fa-f])*)[Pp][+-]?[0-9](?:'?[0-9])*)(?:[Ff](?:16|32|64|128)?|(BF|bf)16|[Ll]|)"
},{
begin:"[+-]?\\b(?:0[Bb][01](?:'?[01])*|0[Xx][0-9A-Fa-f](?:'?[0-9A-Fa-f])*|0(?:'?[0-7])*|[1-9](?:'?[0-9])*)(?:[Uu](?:LL?|ll?)|[Uu][Zz]?|(?:LL?|ll?)[Uu]?|[Zz][Uu]|)"
}],relevance:0},l={className:"meta",begin:/#\s*[a-z]+\b/,end:/$/,keywords:{
keyword:"if else elif endif define undef warning error line pragma _Pragma ifdef ifndef include"
},contains:[{begin:/\\\n/,relevance:0},e.inherit(c,{className:"string"}),{
className:"string",begin:/<.*?>/},a,e.C_BLOCK_COMMENT_MODE]},u={
className:"title",begin:t.optional(r)+e.IDENT_RE,relevance:0
},d=t.optional(r)+e.IDENT_RE+"\\s*\\(",_={
type:["bool","char","char16_t","char32_t","char8_t","double","float","int","long","short","void","wchar_t","unsigned","signed","const","static"],
keyword:["alignas","alignof","and","and_eq","asm","atomic_cancel","atomic_commit","atomic_noexcept","auto","bitand","bitor","break","case","catch","class","co_await","co_return","co_yield","compl","concept","const_cast|10","consteval","constexpr","constinit","continue","decltype","default","delete","do","dynamic_cast|10","else","enum","explicit","export","extern","false","final","for","friend","goto","if","import","inline","module","mutable","namespace","new","noexcept","not","not_eq","nullptr","operator","or","or_eq","override","private","protected","public","reflexpr","register","reinterpret_cast|10","requires","return","sizeof","static_assert","static_cast|10","struct","switch","synchronized","template","this","thread_local","throw","transaction_safe","transaction_safe_dynamic","true","try","typedef","typeid","typename","union","using","virtual","volatile","while","xor","xor_eq"],
literal:["NULL","false","nullopt","nullptr","true"],built_in:["_Pragma"],
_type_hints:["any","auto_ptr","barrier","binary_semaphore","bitset","complex","condition_variable","condition_variable_any","counting_semaphore","deque","false_type","flat_map","flat_set","future","imaginary","initializer_list","istringstream","jthread","latch","lock_guard","multimap","multiset","mutex","optional","ostringstream","packaged_task","pair","promise","priority_queue","queue","recursive_mutex","recursive_timed_mutex","scoped_lock","set","shared_future","shared_lock","shared_mutex","shared_timed_mutex","shared_ptr","stack","string_view","stringstream","timed_mutex","thread","true_type","tuple","unique_lock","unique_ptr","unordered_map","unordered_multimap","unordered_multiset","unordered_set","variant","vector","weak_ptr","wstring","wstring_view"]
},p={className:"function.dispatch",relevance:0,keywords:{
_hint:["abort","abs","acos","apply","as_const","asin","atan","atan2","calloc","ceil","cerr","cin","clog","cos","cosh","cout","declval","endl","exchange","exit","exp","fabs","floor","fmod","forward","fprintf","fputs","free","frexp","fscanf","future","invoke","isalnum","isalpha","iscntrl","isdigit","isgraph","islower","isprint","ispunct","isspace","isupper","isxdigit","labs","launder","ldexp","log","log10","make_pair","make_shared","make_shared_for_overwrite","make_tuple","make_unique","malloc","memchr","memcmp","memcpy","memset","modf","move","pow","printf","putchar","puts","realloc","scanf","sin","sinh","snprintf","sprintf","sqrt","sscanf","std","stderr","stdin","stdout","strcat","strchr","strcmp","strcpy","strcspn","strlen","strncat","strncmp","strncpy","strpbrk","strrchr","strspn","strstr","swap","tan","tanh","terminate","to_underlying","tolower","toupper","vfprintf","visit","vprintf","vsprintf"]
},
begin:t.concat(/\b/,/(?!decltype)/,/(?!if)/,/(?!for)/,/(?!switch)/,/(?!while)/,e.IDENT_RE,t.lookahead(/(<[^<>]+>|)\s*\(/))
},m=[p,l,s,a,e.C_BLOCK_COMMENT_MODE,o,c],f={variants:[{begin:/=/,end:/;/},{
begin:/\(/,end:/\)/},{beginKeywords:"new throw return else",end:/;/}],
keywords:_,contains:m.concat([{begin:/\(/,end:/\)/,keywords:_,
contains:m.concat(["self"]),relevance:0}]),relevance:0},g={className:"function",
begin:"("+i+"[\\*&\\s]+)+"+d,returnBegin:!0,end:/[{;=]/,excludeEnd:!0,
keywords:_,illegal:/[^\w\s\*&:<>.]/,contains:[{begin:n,keywords:_,relevance:0},{
begin:d,returnBegin:!0,contains:[u],relevance:0},{begin:/::/,relevance:0},{
begin:/:/,endsWithParent:!0,contains:[c,o]},{relevance:0,match:/,/},{
className:"params",begin:/\(/,end:/\)/,keywords:_,relevance:0,
contains:[a,e.C_BLOCK_COMMENT_MODE,c,o,s,{begin:/\(/,end:/\)/,keywords:_,
relevance:0,contains:["self",a,e.C_BLOCK_COMMENT_MODE,c,o,s]}]
},s,a,e.C_BLOCK_COMMENT_MODE,l]};return{name:"C++",
aliases:["cc","c++","h++","hpp","hh","hxx","cxx"],keywords:_,illegal:"</",
classNameAliases:{"function.dispatch":"built_in"},
contains:[].concat(f,g,p,m,[l,{
begin:"\\b(deque|list|queue|priority_queue|pair|stack|vector|map|set|bitset|multiset|multimap|unordered_map|unordered_set|unordered_multiset|unordered_multimap|array|tuple|optional|variant|function|flat_map|flat_set)\\s*<(?!<)",
end:">",keywords:_,contains:["self",s]},{begin:e.IDENT_RE+"::",keywords:_},{
match:[/\b(?:enum(?:\s+(?:class|struct))?|class|struct|union)/,/\s+/,/\w+/],
className:{1:"keyword",3:"title.class"}}])}}})();export default hljsGrammar;
@@ -1,420 +0,0 @@
/*! `csharp` grammar compiled for Highlight.js 11.11.1 */
var hljsGrammar = (function () {
'use strict';
/*
Language: C#
Author: Jason Diamond <jason@diamond.name>
Contributor: Nicolas LLOBERA <nllobera@gmail.com>, Pieter Vantorre <pietervantorre@gmail.com>, David Pine <david.pine@microsoft.com>
Website: https://docs.microsoft.com/dotnet/csharp/
Category: common
*/
/** @type LanguageFn */
function csharp(hljs) {
const BUILT_IN_KEYWORDS = [
'bool',
'byte',
'char',
'decimal',
'delegate',
'double',
'dynamic',
'enum',
'float',
'int',
'long',
'nint',
'nuint',
'object',
'sbyte',
'short',
'string',
'ulong',
'uint',
'ushort'
];
const FUNCTION_MODIFIERS = [
'public',
'private',
'protected',
'static',
'internal',
'protected',
'abstract',
'async',
'extern',
'override',
'unsafe',
'virtual',
'new',
'sealed',
'partial'
];
const LITERAL_KEYWORDS = [
'default',
'false',
'null',
'true'
];
const NORMAL_KEYWORDS = [
'abstract',
'as',
'base',
'break',
'case',
'catch',
'class',
'const',
'continue',
'do',
'else',
'event',
'explicit',
'extern',
'finally',
'fixed',
'for',
'foreach',
'goto',
'if',
'implicit',
'in',
'interface',
'internal',
'is',
'lock',
'namespace',
'new',
'operator',
'out',
'override',
'params',
'private',
'protected',
'public',
'readonly',
'record',
'ref',
'return',
'scoped',
'sealed',
'sizeof',
'stackalloc',
'static',
'struct',
'switch',
'this',
'throw',
'try',
'typeof',
'unchecked',
'unsafe',
'using',
'virtual',
'void',
'volatile',
'while'
];
const CONTEXTUAL_KEYWORDS = [
'add',
'alias',
'and',
'ascending',
'args',
'async',
'await',
'by',
'descending',
'dynamic',
'equals',
'file',
'from',
'get',
'global',
'group',
'init',
'into',
'join',
'let',
'nameof',
'not',
'notnull',
'on',
'or',
'orderby',
'partial',
'record',
'remove',
'required',
'scoped',
'select',
'set',
'unmanaged',
'value|0',
'var',
'when',
'where',
'with',
'yield'
];
const KEYWORDS = {
keyword: NORMAL_KEYWORDS.concat(CONTEXTUAL_KEYWORDS),
built_in: BUILT_IN_KEYWORDS,
literal: LITERAL_KEYWORDS
};
const TITLE_MODE = hljs.inherit(hljs.TITLE_MODE, { begin: '[a-zA-Z](\\.?\\w)*' });
const NUMBERS = {
className: 'number',
variants: [
{ begin: '\\b(0b[01\']+)' },
{ begin: '(-?)\\b([\\d\']+(\\.[\\d\']*)?|\\.[\\d\']+)(u|U|l|L|ul|UL|f|F|b|B)' },
{ begin: '(-?)(\\b0[xX][a-fA-F0-9\']+|(\\b[\\d\']+(\\.[\\d\']*)?|\\.[\\d\']+)([eE][-+]?[\\d\']+)?)' }
],
relevance: 0
};
const RAW_STRING = {
className: 'string',
begin: /"""("*)(?!")(.|\n)*?"""\1/,
relevance: 1
};
const VERBATIM_STRING = {
className: 'string',
begin: '@"',
end: '"',
contains: [ { begin: '""' } ]
};
const VERBATIM_STRING_NO_LF = hljs.inherit(VERBATIM_STRING, { illegal: /\n/ });
const SUBST = {
className: 'subst',
begin: /\{/,
end: /\}/,
keywords: KEYWORDS
};
const SUBST_NO_LF = hljs.inherit(SUBST, { illegal: /\n/ });
const INTERPOLATED_STRING = {
className: 'string',
begin: /\$"/,
end: '"',
illegal: /\n/,
contains: [
{ begin: /\{\{/ },
{ begin: /\}\}/ },
hljs.BACKSLASH_ESCAPE,
SUBST_NO_LF
]
};
const INTERPOLATED_VERBATIM_STRING = {
className: 'string',
begin: /\$@"/,
end: '"',
contains: [
{ begin: /\{\{/ },
{ begin: /\}\}/ },
{ begin: '""' },
SUBST
]
};
const INTERPOLATED_VERBATIM_STRING_NO_LF = hljs.inherit(INTERPOLATED_VERBATIM_STRING, {
illegal: /\n/,
contains: [
{ begin: /\{\{/ },
{ begin: /\}\}/ },
{ begin: '""' },
SUBST_NO_LF
]
});
SUBST.contains = [
INTERPOLATED_VERBATIM_STRING,
INTERPOLATED_STRING,
VERBATIM_STRING,
hljs.APOS_STRING_MODE,
hljs.QUOTE_STRING_MODE,
NUMBERS,
hljs.C_BLOCK_COMMENT_MODE
];
SUBST_NO_LF.contains = [
INTERPOLATED_VERBATIM_STRING_NO_LF,
INTERPOLATED_STRING,
VERBATIM_STRING_NO_LF,
hljs.APOS_STRING_MODE,
hljs.QUOTE_STRING_MODE,
NUMBERS,
hljs.inherit(hljs.C_BLOCK_COMMENT_MODE, { illegal: /\n/ })
];
const STRING = { variants: [
RAW_STRING,
INTERPOLATED_VERBATIM_STRING,
INTERPOLATED_STRING,
VERBATIM_STRING,
hljs.APOS_STRING_MODE,
hljs.QUOTE_STRING_MODE
] };
const GENERIC_MODIFIER = {
begin: "<",
end: ">",
contains: [
{ beginKeywords: "in out" },
TITLE_MODE
]
};
const TYPE_IDENT_RE = hljs.IDENT_RE + '(<' + hljs.IDENT_RE + '(\\s*,\\s*' + hljs.IDENT_RE + ')*>)?(\\[\\])?';
const AT_IDENTIFIER = {
// prevents expressions like `@class` from incorrect flagging
// `class` as a keyword
begin: "@" + hljs.IDENT_RE,
relevance: 0
};
return {
name: 'C#',
aliases: [
'cs',
'c#'
],
keywords: KEYWORDS,
illegal: /::/,
contains: [
hljs.COMMENT(
'///',
'$',
{
returnBegin: true,
contains: [
{
className: 'doctag',
variants: [
{
begin: '///',
relevance: 0
},
{ begin: '<!--|-->' },
{
begin: '</?',
end: '>'
}
]
}
]
}
),
hljs.C_LINE_COMMENT_MODE,
hljs.C_BLOCK_COMMENT_MODE,
{
className: 'meta',
begin: '#',
end: '$',
keywords: { keyword: 'if else elif endif define undef warning error line region endregion pragma checksum' }
},
STRING,
NUMBERS,
{
beginKeywords: 'class interface',
relevance: 0,
end: /[{;=]/,
illegal: /[^\s:,]/,
contains: [
{ beginKeywords: "where class" },
TITLE_MODE,
GENERIC_MODIFIER,
hljs.C_LINE_COMMENT_MODE,
hljs.C_BLOCK_COMMENT_MODE
]
},
{
beginKeywords: 'namespace',
relevance: 0,
end: /[{;=]/,
illegal: /[^\s:]/,
contains: [
TITLE_MODE,
hljs.C_LINE_COMMENT_MODE,
hljs.C_BLOCK_COMMENT_MODE
]
},
{
beginKeywords: 'record',
relevance: 0,
end: /[{;=]/,
illegal: /[^\s:]/,
contains: [
TITLE_MODE,
GENERIC_MODIFIER,
hljs.C_LINE_COMMENT_MODE,
hljs.C_BLOCK_COMMENT_MODE
]
},
{
// [Attributes("")]
className: 'meta',
begin: '^\\s*\\[(?=[\\w])',
excludeBegin: true,
end: '\\]',
excludeEnd: true,
contains: [
{
className: 'string',
begin: /"/,
end: /"/
}
]
},
{
// Expression keywords prevent 'keyword Name(...)' from being
// recognized as a function definition
beginKeywords: 'new return throw await else',
relevance: 0
},
{
className: 'function',
begin: '(' + TYPE_IDENT_RE + '\\s+)+' + hljs.IDENT_RE + '\\s*(<[^=]+>\\s*)?\\(',
returnBegin: true,
end: /\s*[{;=]/,
excludeEnd: true,
keywords: KEYWORDS,
contains: [
// prevents these from being highlighted `title`
{
beginKeywords: FUNCTION_MODIFIERS.join(" "),
relevance: 0
},
{
begin: hljs.IDENT_RE + '\\s*(<[^=]+>\\s*)?\\(',
returnBegin: true,
contains: [
hljs.TITLE_MODE,
GENERIC_MODIFIER
],
relevance: 0
},
{ match: /\(\)/ },
{
className: 'params',
begin: /\(/,
end: /\)/,
excludeBegin: true,
excludeEnd: true,
keywords: KEYWORDS,
relevance: 0,
contains: [
STRING,
NUMBERS,
hljs.C_BLOCK_COMMENT_MODE
]
},
hljs.C_LINE_COMMENT_MODE,
hljs.C_BLOCK_COMMENT_MODE
]
},
AT_IDENTIFIER
]
};
}
return csharp;
})();
;
export default hljsGrammar;
-49
View File
@@ -1,49 +0,0 @@
/*! `csharp` grammar compiled for Highlight.js 11.11.1 */
var hljsGrammar=(()=>{"use strict";return e=>{const n={
keyword:["abstract","as","base","break","case","catch","class","const","continue","do","else","event","explicit","extern","finally","fixed","for","foreach","goto","if","implicit","in","interface","internal","is","lock","namespace","new","operator","out","override","params","private","protected","public","readonly","record","ref","return","scoped","sealed","sizeof","stackalloc","static","struct","switch","this","throw","try","typeof","unchecked","unsafe","using","virtual","void","volatile","while"].concat(["add","alias","and","ascending","args","async","await","by","descending","dynamic","equals","file","from","get","global","group","init","into","join","let","nameof","not","notnull","on","or","orderby","partial","record","remove","required","scoped","select","set","unmanaged","value|0","var","when","where","with","yield"]),
built_in:["bool","byte","char","decimal","delegate","double","dynamic","enum","float","int","long","nint","nuint","object","sbyte","short","string","ulong","uint","ushort"],
literal:["default","false","null","true"]},a=e.inherit(e.TITLE_MODE,{
begin:"[a-zA-Z](\\.?\\w)*"}),i={className:"number",variants:[{
begin:"\\b(0b[01']+)"},{
begin:"(-?)\\b([\\d']+(\\.[\\d']*)?|\\.[\\d']+)(u|U|l|L|ul|UL|f|F|b|B)"},{
begin:"(-?)(\\b0[xX][a-fA-F0-9']+|(\\b[\\d']+(\\.[\\d']*)?|\\.[\\d']+)([eE][-+]?[\\d']+)?)"
}],relevance:0},s={className:"string",begin:'@"',end:'"',contains:[{begin:'""'}]
},r=e.inherit(s,{illegal:/\n/}),t={className:"subst",begin:/\{/,end:/\}/,
keywords:n},l=e.inherit(t,{illegal:/\n/}),c={className:"string",begin:/\$"/,
end:'"',illegal:/\n/,contains:[{begin:/\{\{/},{begin:/\}\}/
},e.BACKSLASH_ESCAPE,l]},o={className:"string",begin:/\$@"/,end:'"',contains:[{
begin:/\{\{/},{begin:/\}\}/},{begin:'""'},t]},d=e.inherit(o,{illegal:/\n/,
contains:[{begin:/\{\{/},{begin:/\}\}/},{begin:'""'},l]})
;t.contains=[o,c,s,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,i,e.C_BLOCK_COMMENT_MODE],
l.contains=[d,c,r,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,i,e.inherit(e.C_BLOCK_COMMENT_MODE,{
illegal:/\n/})];const g={variants:[{className:"string",
begin:/"""("*)(?!")(.|\n)*?"""\1/,relevance:1
},o,c,s,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE]},E={begin:"<",end:">",
contains:[{beginKeywords:"in out"},a]
},_=e.IDENT_RE+"(<"+e.IDENT_RE+"(\\s*,\\s*"+e.IDENT_RE+")*>)?(\\[\\])?",b={
begin:"@"+e.IDENT_RE,relevance:0};return{name:"C#",aliases:["cs","c#"],
keywords:n,illegal:/::/,contains:[e.COMMENT("///","$",{returnBegin:!0,
contains:[{className:"doctag",variants:[{begin:"///",relevance:0},{
begin:"\x3c!--|--\x3e"},{begin:"</?",end:">"}]}]
}),e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,{className:"meta",begin:"#",
end:"$",keywords:{
keyword:"if else elif endif define undef warning error line region endregion pragma checksum"
}},g,i,{beginKeywords:"class interface",relevance:0,end:/[{;=]/,
illegal:/[^\s:,]/,contains:[{beginKeywords:"where class"
},a,E,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{beginKeywords:"namespace",
relevance:0,end:/[{;=]/,illegal:/[^\s:]/,
contains:[a,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{
beginKeywords:"record",relevance:0,end:/[{;=]/,illegal:/[^\s:]/,
contains:[a,E,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{className:"meta",
begin:"^\\s*\\[(?=[\\w])",excludeBegin:!0,end:"\\]",excludeEnd:!0,contains:[{
className:"string",begin:/"/,end:/"/}]},{
beginKeywords:"new return throw await else",relevance:0},{className:"function",
begin:"("+_+"\\s+)+"+e.IDENT_RE+"\\s*(<[^=]+>\\s*)?\\(",returnBegin:!0,
end:/\s*[{;=]/,excludeEnd:!0,keywords:n,contains:[{
beginKeywords:"public private protected static internal protected abstract async extern override unsafe virtual new sealed partial",
relevance:0},{begin:e.IDENT_RE+"\\s*(<[^=]+>\\s*)?\\(",returnBegin:!0,
contains:[e.TITLE_MODE,E],relevance:0},{match:/\(\)/},{className:"params",
begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:n,relevance:0,
contains:[g,i,e.C_BLOCK_COMMENT_MODE]
},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},b]}}})()
;export default hljsGrammar;
@@ -1,957 +0,0 @@
/*! `css` grammar compiled for Highlight.js 11.11.1 */
var hljsGrammar = (function () {
'use strict';
const MODES = (hljs) => {
return {
IMPORTANT: {
scope: 'meta',
begin: '!important'
},
BLOCK_COMMENT: hljs.C_BLOCK_COMMENT_MODE,
HEXCOLOR: {
scope: 'number',
begin: /#(([0-9a-fA-F]{3,4})|(([0-9a-fA-F]{2}){3,4}))\b/
},
FUNCTION_DISPATCH: {
className: "built_in",
begin: /[\w-]+(?=\()/
},
ATTRIBUTE_SELECTOR_MODE: {
scope: 'selector-attr',
begin: /\[/,
end: /\]/,
illegal: '$',
contains: [
hljs.APOS_STRING_MODE,
hljs.QUOTE_STRING_MODE
]
},
CSS_NUMBER_MODE: {
scope: 'number',
begin: hljs.NUMBER_RE + '(' +
'%|em|ex|ch|rem' +
'|vw|vh|vmin|vmax' +
'|cm|mm|in|pt|pc|px' +
'|deg|grad|rad|turn' +
'|s|ms' +
'|Hz|kHz' +
'|dpi|dpcm|dppx' +
')?',
relevance: 0
},
CSS_VARIABLE: {
className: "attr",
begin: /--[A-Za-z_][A-Za-z0-9_-]*/
}
};
};
const HTML_TAGS = [
'a',
'abbr',
'address',
'article',
'aside',
'audio',
'b',
'blockquote',
'body',
'button',
'canvas',
'caption',
'cite',
'code',
'dd',
'del',
'details',
'dfn',
'div',
'dl',
'dt',
'em',
'fieldset',
'figcaption',
'figure',
'footer',
'form',
'h1',
'h2',
'h3',
'h4',
'h5',
'h6',
'header',
'hgroup',
'html',
'i',
'iframe',
'img',
'input',
'ins',
'kbd',
'label',
'legend',
'li',
'main',
'mark',
'menu',
'nav',
'object',
'ol',
'optgroup',
'option',
'p',
'picture',
'q',
'quote',
'samp',
'section',
'select',
'source',
'span',
'strong',
'summary',
'sup',
'table',
'tbody',
'td',
'textarea',
'tfoot',
'th',
'thead',
'time',
'tr',
'ul',
'var',
'video'
];
const SVG_TAGS = [
'defs',
'g',
'marker',
'mask',
'pattern',
'svg',
'switch',
'symbol',
'feBlend',
'feColorMatrix',
'feComponentTransfer',
'feComposite',
'feConvolveMatrix',
'feDiffuseLighting',
'feDisplacementMap',
'feFlood',
'feGaussianBlur',
'feImage',
'feMerge',
'feMorphology',
'feOffset',
'feSpecularLighting',
'feTile',
'feTurbulence',
'linearGradient',
'radialGradient',
'stop',
'circle',
'ellipse',
'image',
'line',
'path',
'polygon',
'polyline',
'rect',
'text',
'use',
'textPath',
'tspan',
'foreignObject',
'clipPath'
];
const TAGS = [
...HTML_TAGS,
...SVG_TAGS,
];
// Sorting, then reversing makes sure longer attributes/elements like
// `font-weight` are matched fully instead of getting false positives on say `font`
const MEDIA_FEATURES = [
'any-hover',
'any-pointer',
'aspect-ratio',
'color',
'color-gamut',
'color-index',
'device-aspect-ratio',
'device-height',
'device-width',
'display-mode',
'forced-colors',
'grid',
'height',
'hover',
'inverted-colors',
'monochrome',
'orientation',
'overflow-block',
'overflow-inline',
'pointer',
'prefers-color-scheme',
'prefers-contrast',
'prefers-reduced-motion',
'prefers-reduced-transparency',
'resolution',
'scan',
'scripting',
'update',
'width',
// TODO: find a better solution?
'min-width',
'max-width',
'min-height',
'max-height'
].sort().reverse();
// https://developer.mozilla.org/en-US/docs/Web/CSS/Pseudo-classes
const PSEUDO_CLASSES = [
'active',
'any-link',
'blank',
'checked',
'current',
'default',
'defined',
'dir', // dir()
'disabled',
'drop',
'empty',
'enabled',
'first',
'first-child',
'first-of-type',
'fullscreen',
'future',
'focus',
'focus-visible',
'focus-within',
'has', // has()
'host', // host or host()
'host-context', // host-context()
'hover',
'indeterminate',
'in-range',
'invalid',
'is', // is()
'lang', // lang()
'last-child',
'last-of-type',
'left',
'link',
'local-link',
'not', // not()
'nth-child', // nth-child()
'nth-col', // nth-col()
'nth-last-child', // nth-last-child()
'nth-last-col', // nth-last-col()
'nth-last-of-type', //nth-last-of-type()
'nth-of-type', //nth-of-type()
'only-child',
'only-of-type',
'optional',
'out-of-range',
'past',
'placeholder-shown',
'read-only',
'read-write',
'required',
'right',
'root',
'scope',
'target',
'target-within',
'user-invalid',
'valid',
'visited',
'where' // where()
].sort().reverse();
// https://developer.mozilla.org/en-US/docs/Web/CSS/Pseudo-elements
const PSEUDO_ELEMENTS = [
'after',
'backdrop',
'before',
'cue',
'cue-region',
'first-letter',
'first-line',
'grammar-error',
'marker',
'part',
'placeholder',
'selection',
'slotted',
'spelling-error'
].sort().reverse();
const ATTRIBUTES = [
'accent-color',
'align-content',
'align-items',
'align-self',
'alignment-baseline',
'all',
'anchor-name',
'animation',
'animation-composition',
'animation-delay',
'animation-direction',
'animation-duration',
'animation-fill-mode',
'animation-iteration-count',
'animation-name',
'animation-play-state',
'animation-range',
'animation-range-end',
'animation-range-start',
'animation-timeline',
'animation-timing-function',
'appearance',
'aspect-ratio',
'backdrop-filter',
'backface-visibility',
'background',
'background-attachment',
'background-blend-mode',
'background-clip',
'background-color',
'background-image',
'background-origin',
'background-position',
'background-position-x',
'background-position-y',
'background-repeat',
'background-size',
'baseline-shift',
'block-size',
'border',
'border-block',
'border-block-color',
'border-block-end',
'border-block-end-color',
'border-block-end-style',
'border-block-end-width',
'border-block-start',
'border-block-start-color',
'border-block-start-style',
'border-block-start-width',
'border-block-style',
'border-block-width',
'border-bottom',
'border-bottom-color',
'border-bottom-left-radius',
'border-bottom-right-radius',
'border-bottom-style',
'border-bottom-width',
'border-collapse',
'border-color',
'border-end-end-radius',
'border-end-start-radius',
'border-image',
'border-image-outset',
'border-image-repeat',
'border-image-slice',
'border-image-source',
'border-image-width',
'border-inline',
'border-inline-color',
'border-inline-end',
'border-inline-end-color',
'border-inline-end-style',
'border-inline-end-width',
'border-inline-start',
'border-inline-start-color',
'border-inline-start-style',
'border-inline-start-width',
'border-inline-style',
'border-inline-width',
'border-left',
'border-left-color',
'border-left-style',
'border-left-width',
'border-radius',
'border-right',
'border-right-color',
'border-right-style',
'border-right-width',
'border-spacing',
'border-start-end-radius',
'border-start-start-radius',
'border-style',
'border-top',
'border-top-color',
'border-top-left-radius',
'border-top-right-radius',
'border-top-style',
'border-top-width',
'border-width',
'bottom',
'box-align',
'box-decoration-break',
'box-direction',
'box-flex',
'box-flex-group',
'box-lines',
'box-ordinal-group',
'box-orient',
'box-pack',
'box-shadow',
'box-sizing',
'break-after',
'break-before',
'break-inside',
'caption-side',
'caret-color',
'clear',
'clip',
'clip-path',
'clip-rule',
'color',
'color-interpolation',
'color-interpolation-filters',
'color-profile',
'color-rendering',
'color-scheme',
'column-count',
'column-fill',
'column-gap',
'column-rule',
'column-rule-color',
'column-rule-style',
'column-rule-width',
'column-span',
'column-width',
'columns',
'contain',
'contain-intrinsic-block-size',
'contain-intrinsic-height',
'contain-intrinsic-inline-size',
'contain-intrinsic-size',
'contain-intrinsic-width',
'container',
'container-name',
'container-type',
'content',
'content-visibility',
'counter-increment',
'counter-reset',
'counter-set',
'cue',
'cue-after',
'cue-before',
'cursor',
'cx',
'cy',
'direction',
'display',
'dominant-baseline',
'empty-cells',
'enable-background',
'field-sizing',
'fill',
'fill-opacity',
'fill-rule',
'filter',
'flex',
'flex-basis',
'flex-direction',
'flex-flow',
'flex-grow',
'flex-shrink',
'flex-wrap',
'float',
'flood-color',
'flood-opacity',
'flow',
'font',
'font-display',
'font-family',
'font-feature-settings',
'font-kerning',
'font-language-override',
'font-optical-sizing',
'font-palette',
'font-size',
'font-size-adjust',
'font-smooth',
'font-smoothing',
'font-stretch',
'font-style',
'font-synthesis',
'font-synthesis-position',
'font-synthesis-small-caps',
'font-synthesis-style',
'font-synthesis-weight',
'font-variant',
'font-variant-alternates',
'font-variant-caps',
'font-variant-east-asian',
'font-variant-emoji',
'font-variant-ligatures',
'font-variant-numeric',
'font-variant-position',
'font-variation-settings',
'font-weight',
'forced-color-adjust',
'gap',
'glyph-orientation-horizontal',
'glyph-orientation-vertical',
'grid',
'grid-area',
'grid-auto-columns',
'grid-auto-flow',
'grid-auto-rows',
'grid-column',
'grid-column-end',
'grid-column-start',
'grid-gap',
'grid-row',
'grid-row-end',
'grid-row-start',
'grid-template',
'grid-template-areas',
'grid-template-columns',
'grid-template-rows',
'hanging-punctuation',
'height',
'hyphenate-character',
'hyphenate-limit-chars',
'hyphens',
'icon',
'image-orientation',
'image-rendering',
'image-resolution',
'ime-mode',
'initial-letter',
'initial-letter-align',
'inline-size',
'inset',
'inset-area',
'inset-block',
'inset-block-end',
'inset-block-start',
'inset-inline',
'inset-inline-end',
'inset-inline-start',
'isolation',
'justify-content',
'justify-items',
'justify-self',
'kerning',
'left',
'letter-spacing',
'lighting-color',
'line-break',
'line-height',
'line-height-step',
'list-style',
'list-style-image',
'list-style-position',
'list-style-type',
'margin',
'margin-block',
'margin-block-end',
'margin-block-start',
'margin-bottom',
'margin-inline',
'margin-inline-end',
'margin-inline-start',
'margin-left',
'margin-right',
'margin-top',
'margin-trim',
'marker',
'marker-end',
'marker-mid',
'marker-start',
'marks',
'mask',
'mask-border',
'mask-border-mode',
'mask-border-outset',
'mask-border-repeat',
'mask-border-slice',
'mask-border-source',
'mask-border-width',
'mask-clip',
'mask-composite',
'mask-image',
'mask-mode',
'mask-origin',
'mask-position',
'mask-repeat',
'mask-size',
'mask-type',
'masonry-auto-flow',
'math-depth',
'math-shift',
'math-style',
'max-block-size',
'max-height',
'max-inline-size',
'max-width',
'min-block-size',
'min-height',
'min-inline-size',
'min-width',
'mix-blend-mode',
'nav-down',
'nav-index',
'nav-left',
'nav-right',
'nav-up',
'none',
'normal',
'object-fit',
'object-position',
'offset',
'offset-anchor',
'offset-distance',
'offset-path',
'offset-position',
'offset-rotate',
'opacity',
'order',
'orphans',
'outline',
'outline-color',
'outline-offset',
'outline-style',
'outline-width',
'overflow',
'overflow-anchor',
'overflow-block',
'overflow-clip-margin',
'overflow-inline',
'overflow-wrap',
'overflow-x',
'overflow-y',
'overlay',
'overscroll-behavior',
'overscroll-behavior-block',
'overscroll-behavior-inline',
'overscroll-behavior-x',
'overscroll-behavior-y',
'padding',
'padding-block',
'padding-block-end',
'padding-block-start',
'padding-bottom',
'padding-inline',
'padding-inline-end',
'padding-inline-start',
'padding-left',
'padding-right',
'padding-top',
'page',
'page-break-after',
'page-break-before',
'page-break-inside',
'paint-order',
'pause',
'pause-after',
'pause-before',
'perspective',
'perspective-origin',
'place-content',
'place-items',
'place-self',
'pointer-events',
'position',
'position-anchor',
'position-visibility',
'print-color-adjust',
'quotes',
'r',
'resize',
'rest',
'rest-after',
'rest-before',
'right',
'rotate',
'row-gap',
'ruby-align',
'ruby-position',
'scale',
'scroll-behavior',
'scroll-margin',
'scroll-margin-block',
'scroll-margin-block-end',
'scroll-margin-block-start',
'scroll-margin-bottom',
'scroll-margin-inline',
'scroll-margin-inline-end',
'scroll-margin-inline-start',
'scroll-margin-left',
'scroll-margin-right',
'scroll-margin-top',
'scroll-padding',
'scroll-padding-block',
'scroll-padding-block-end',
'scroll-padding-block-start',
'scroll-padding-bottom',
'scroll-padding-inline',
'scroll-padding-inline-end',
'scroll-padding-inline-start',
'scroll-padding-left',
'scroll-padding-right',
'scroll-padding-top',
'scroll-snap-align',
'scroll-snap-stop',
'scroll-snap-type',
'scroll-timeline',
'scroll-timeline-axis',
'scroll-timeline-name',
'scrollbar-color',
'scrollbar-gutter',
'scrollbar-width',
'shape-image-threshold',
'shape-margin',
'shape-outside',
'shape-rendering',
'speak',
'speak-as',
'src', // @font-face
'stop-color',
'stop-opacity',
'stroke',
'stroke-dasharray',
'stroke-dashoffset',
'stroke-linecap',
'stroke-linejoin',
'stroke-miterlimit',
'stroke-opacity',
'stroke-width',
'tab-size',
'table-layout',
'text-align',
'text-align-all',
'text-align-last',
'text-anchor',
'text-combine-upright',
'text-decoration',
'text-decoration-color',
'text-decoration-line',
'text-decoration-skip',
'text-decoration-skip-ink',
'text-decoration-style',
'text-decoration-thickness',
'text-emphasis',
'text-emphasis-color',
'text-emphasis-position',
'text-emphasis-style',
'text-indent',
'text-justify',
'text-orientation',
'text-overflow',
'text-rendering',
'text-shadow',
'text-size-adjust',
'text-transform',
'text-underline-offset',
'text-underline-position',
'text-wrap',
'text-wrap-mode',
'text-wrap-style',
'timeline-scope',
'top',
'touch-action',
'transform',
'transform-box',
'transform-origin',
'transform-style',
'transition',
'transition-behavior',
'transition-delay',
'transition-duration',
'transition-property',
'transition-timing-function',
'translate',
'unicode-bidi',
'user-modify',
'user-select',
'vector-effect',
'vertical-align',
'view-timeline',
'view-timeline-axis',
'view-timeline-inset',
'view-timeline-name',
'view-transition-name',
'visibility',
'voice-balance',
'voice-duration',
'voice-family',
'voice-pitch',
'voice-range',
'voice-rate',
'voice-stress',
'voice-volume',
'white-space',
'white-space-collapse',
'widows',
'width',
'will-change',
'word-break',
'word-spacing',
'word-wrap',
'writing-mode',
'x',
'y',
'z-index',
'zoom'
].sort().reverse();
/*
Language: CSS
Category: common, css, web
Website: https://developer.mozilla.org/en-US/docs/Web/CSS
*/
/** @type LanguageFn */
function css(hljs) {
const regex = hljs.regex;
const modes = MODES(hljs);
const VENDOR_PREFIX = { begin: /-(webkit|moz|ms|o)-(?=[a-z])/ };
const AT_MODIFIERS = "and or not only";
const AT_PROPERTY_RE = /@-?\w[\w]*(-\w+)*/; // @-webkit-keyframes
const IDENT_RE = '[a-zA-Z-][a-zA-Z0-9_-]*';
const STRINGS = [
hljs.APOS_STRING_MODE,
hljs.QUOTE_STRING_MODE
];
return {
name: 'CSS',
case_insensitive: true,
illegal: /[=|'\$]/,
keywords: { keyframePosition: "from to" },
classNameAliases: {
// for visual continuity with `tag {}` and because we
// don't have a great class for this?
keyframePosition: "selector-tag" },
contains: [
modes.BLOCK_COMMENT,
VENDOR_PREFIX,
// to recognize keyframe 40% etc which are outside the scope of our
// attribute value mode
modes.CSS_NUMBER_MODE,
{
className: 'selector-id',
begin: /#[A-Za-z0-9_-]+/,
relevance: 0
},
{
className: 'selector-class',
begin: '\\.' + IDENT_RE,
relevance: 0
},
modes.ATTRIBUTE_SELECTOR_MODE,
{
className: 'selector-pseudo',
variants: [
{ begin: ':(' + PSEUDO_CLASSES.join('|') + ')' },
{ begin: ':(:)?(' + PSEUDO_ELEMENTS.join('|') + ')' }
]
},
// we may actually need this (12/2020)
// { // pseudo-selector params
// begin: /\(/,
// end: /\)/,
// contains: [ hljs.CSS_NUMBER_MODE ]
// },
modes.CSS_VARIABLE,
{
className: 'attribute',
begin: '\\b(' + ATTRIBUTES.join('|') + ')\\b'
},
// attribute values
{
begin: /:/,
end: /[;}{]/,
contains: [
modes.BLOCK_COMMENT,
modes.HEXCOLOR,
modes.IMPORTANT,
modes.CSS_NUMBER_MODE,
...STRINGS,
// needed to highlight these as strings and to avoid issues with
// illegal characters that might be inside urls that would tigger the
// languages illegal stack
{
begin: /(url|data-uri)\(/,
end: /\)/,
relevance: 0, // from keywords
keywords: { built_in: "url data-uri" },
contains: [
...STRINGS,
{
className: "string",
// any character other than `)` as in `url()` will be the start
// of a string, which ends with `)` (from the parent mode)
begin: /[^)]/,
endsWithParent: true,
excludeEnd: true
}
]
},
modes.FUNCTION_DISPATCH
]
},
{
begin: regex.lookahead(/@/),
end: '[{;]',
relevance: 0,
illegal: /:/, // break on Less variables @var: ...
contains: [
{
className: 'keyword',
begin: AT_PROPERTY_RE
},
{
begin: /\s/,
endsWithParent: true,
excludeEnd: true,
relevance: 0,
keywords: {
$pattern: /[a-z-]+/,
keyword: AT_MODIFIERS,
attribute: MEDIA_FEATURES.join(" ")
},
contains: [
{
begin: /[a-z-]+(?=:)/,
className: "attribute"
},
...STRINGS,
modes.CSS_NUMBER_MODE
]
}
]
},
{
className: 'selector-tag',
begin: '\\b(' + TAGS.join('|') + ')\\b'
}
]
};
}
return css;
})();
;
export default hljsGrammar;
File diff suppressed because one or more lines are too long
@@ -1,70 +0,0 @@
/*! `diff` grammar compiled for Highlight.js 11.11.1 */
var hljsGrammar = (function () {
'use strict';
/*
Language: Diff
Description: Unified and context diff
Author: Vasily Polovnyov <vast@whiteants.net>
Website: https://www.gnu.org/software/diffutils/
Category: common
*/
/** @type LanguageFn */
function diff(hljs) {
const regex = hljs.regex;
return {
name: 'Diff',
aliases: [ 'patch' ],
contains: [
{
className: 'meta',
relevance: 10,
match: regex.either(
/^@@ +-\d+,\d+ +\+\d+,\d+ +@@/,
/^\*\*\* +\d+,\d+ +\*\*\*\*$/,
/^--- +\d+,\d+ +----$/
)
},
{
className: 'comment',
variants: [
{
begin: regex.either(
/Index: /,
/^index/,
/={3,}/,
/^-{3}/,
/^\*{3} /,
/^\+{3}/,
/^diff --git/
),
end: /$/
},
{ match: /^\*{15}$/ }
]
},
{
className: 'addition',
begin: /^\+/,
end: /$/
},
{
className: 'deletion',
begin: /^-/,
end: /$/
},
{
className: 'addition',
begin: /^!/,
end: /$/
}
]
};
}
return diff;
})();
;
export default hljsGrammar;
-9
View File
@@ -1,9 +0,0 @@
/*! `diff` grammar compiled for Highlight.js 11.11.1 */
var hljsGrammar=(()=>{"use strict";return e=>{const a=e.regex;return{
name:"Diff",aliases:["patch"],contains:[{className:"meta",relevance:10,
match:a.either(/^@@ +-\d+,\d+ +\+\d+,\d+ +@@/,/^\*\*\* +\d+,\d+ +\*\*\*\*$/,/^--- +\d+,\d+ +----$/)
},{className:"comment",variants:[{
begin:a.either(/Index: /,/^index/,/={3,}/,/^-{3}/,/^\*{3} /,/^\+{3}/,/^diff --git/),
end:/$/},{match:/^\*{15}$/}]},{className:"addition",begin:/^\+/,end:/$/},{
className:"deletion",begin:/^-/,end:/$/},{className:"addition",begin:/^!/,
end:/$/}]}}})();export default hljsGrammar;
@@ -1,164 +0,0 @@
/*! `go` grammar compiled for Highlight.js 11.11.1 */
var hljsGrammar = (function () {
'use strict';
/*
Language: Go
Author: Stephan Kountso aka StepLg <steplg@gmail.com>
Contributors: Evgeny Stepanischev <imbolk@gmail.com>
Description: Google go language (golang). For info about language
Website: http://golang.org/
Category: common, system
*/
function go(hljs) {
const LITERALS = [
"true",
"false",
"iota",
"nil"
];
const BUILT_INS = [
"append",
"cap",
"close",
"complex",
"copy",
"imag",
"len",
"make",
"new",
"panic",
"print",
"println",
"real",
"recover",
"delete"
];
const TYPES = [
"bool",
"byte",
"complex64",
"complex128",
"error",
"float32",
"float64",
"int8",
"int16",
"int32",
"int64",
"string",
"uint8",
"uint16",
"uint32",
"uint64",
"int",
"uint",
"uintptr",
"rune"
];
const KWS = [
"break",
"case",
"chan",
"const",
"continue",
"default",
"defer",
"else",
"fallthrough",
"for",
"func",
"go",
"goto",
"if",
"import",
"interface",
"map",
"package",
"range",
"return",
"select",
"struct",
"switch",
"type",
"var",
];
const KEYWORDS = {
keyword: KWS,
type: TYPES,
literal: LITERALS,
built_in: BUILT_INS
};
return {
name: 'Go',
aliases: [ 'golang' ],
keywords: KEYWORDS,
illegal: '</',
contains: [
hljs.C_LINE_COMMENT_MODE,
hljs.C_BLOCK_COMMENT_MODE,
{
className: 'string',
variants: [
hljs.QUOTE_STRING_MODE,
hljs.APOS_STRING_MODE,
{
begin: '`',
end: '`'
}
]
},
{
className: 'number',
variants: [
{
match: /-?\b0[xX]\.[a-fA-F0-9](_?[a-fA-F0-9])*[pP][+-]?\d(_?\d)*i?/, // hex without a present digit before . (making a digit afterwards required)
relevance: 0
},
{
match: /-?\b0[xX](_?[a-fA-F0-9])+((\.([a-fA-F0-9](_?[a-fA-F0-9])*)?)?[pP][+-]?\d(_?\d)*)?i?/, // hex with a present digit before . (making a digit afterwards optional)
relevance: 0
},
{
match: /-?\b0[oO](_?[0-7])*i?/, // leading 0o octal
relevance: 0
},
{
match: /-?\.\d(_?\d)*([eE][+-]?\d(_?\d)*)?i?/, // decimal without a present digit before . (making a digit afterwards required)
relevance: 0
},
{
match: /-?\b\d(_?\d)*(\.(\d(_?\d)*)?)?([eE][+-]?\d(_?\d)*)?i?/, // decimal with a present digit before . (making a digit afterwards optional)
relevance: 0
}
]
},
{ begin: /:=/ // relevance booster
},
{
className: 'function',
beginKeywords: 'func',
end: '\\s*(\\{|$)',
excludeEnd: true,
contains: [
hljs.TITLE_MODE,
{
className: 'params',
begin: /\(/,
end: /\)/,
endsParent: true,
keywords: KEYWORDS,
illegal: /["']/
}
]
}
]
};
}
return go;
})();
;
export default hljsGrammar;
-19
View File
@@ -1,19 +0,0 @@
/*! `go` grammar compiled for Highlight.js 11.11.1 */
var hljsGrammar=(()=>{"use strict";return e=>{const a={
keyword:["break","case","chan","const","continue","default","defer","else","fallthrough","for","func","go","goto","if","import","interface","map","package","range","return","select","struct","switch","type","var"],
type:["bool","byte","complex64","complex128","error","float32","float64","int8","int16","int32","int64","string","uint8","uint16","uint32","uint64","int","uint","uintptr","rune"],
literal:["true","false","iota","nil"],
built_in:["append","cap","close","complex","copy","imag","len","make","new","panic","print","println","real","recover","delete"]
};return{name:"Go",aliases:["golang"],keywords:a,illegal:"</",
contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,{className:"string",
variants:[e.QUOTE_STRING_MODE,e.APOS_STRING_MODE,{begin:"`",end:"`"}]},{
className:"number",variants:[{
match:/-?\b0[xX]\.[a-fA-F0-9](_?[a-fA-F0-9])*[pP][+-]?\d(_?\d)*i?/,relevance:0
},{
match:/-?\b0[xX](_?[a-fA-F0-9])+((\.([a-fA-F0-9](_?[a-fA-F0-9])*)?)?[pP][+-]?\d(_?\d)*)?i?/,
relevance:0},{match:/-?\b0[oO](_?[0-7])*i?/,relevance:0},{
match:/-?\.\d(_?\d)*([eE][+-]?\d(_?\d)*)?i?/,relevance:0},{
match:/-?\b\d(_?\d)*(\.(\d(_?\d)*)?)?([eE][+-]?\d(_?\d)*)?i?/,relevance:0}]},{
begin:/:=/},{className:"function",beginKeywords:"func",end:"\\s*(\\{|$)",
excludeEnd:!0,contains:[e.TITLE_MODE,{className:"params",begin:/\(/,end:/\)/,
endsParent:!0,keywords:a,illegal:/["']/}]}]}}})();export default hljsGrammar;
@@ -1,86 +0,0 @@
/*! `graphql` grammar compiled for Highlight.js 11.11.1 */
var hljsGrammar = (function () {
'use strict';
/*
Language: GraphQL
Author: John Foster (GH jf990), and others
Description: GraphQL is a query language for APIs
Category: web, common
*/
/** @type LanguageFn */
function graphql(hljs) {
const regex = hljs.regex;
const GQL_NAME = /[_A-Za-z][_0-9A-Za-z]*/;
return {
name: "GraphQL",
aliases: [ "gql" ],
case_insensitive: true,
disableAutodetect: false,
keywords: {
keyword: [
"query",
"mutation",
"subscription",
"type",
"input",
"schema",
"directive",
"interface",
"union",
"scalar",
"fragment",
"enum",
"on"
],
literal: [
"true",
"false",
"null"
]
},
contains: [
hljs.HASH_COMMENT_MODE,
hljs.QUOTE_STRING_MODE,
hljs.NUMBER_MODE,
{
scope: "punctuation",
match: /[.]{3}/,
relevance: 0
},
{
scope: "punctuation",
begin: /[\!\(\)\:\=\[\]\{\|\}]{1}/,
relevance: 0
},
{
scope: "variable",
begin: /\$/,
end: /\W/,
excludeEnd: true,
relevance: 0
},
{
scope: "meta",
match: /@\w+/,
excludeEnd: true
},
{
scope: "symbol",
begin: regex.concat(GQL_NAME, regex.lookahead(/\s*:/)),
relevance: 0
}
],
illegal: [
/[;<']/,
/BEGIN/
]
};
}
return graphql;
})();
;
export default hljsGrammar;
-12
View File
@@ -1,12 +0,0 @@
/*! `graphql` grammar compiled for Highlight.js 11.11.1 */
var hljsGrammar=(()=>{"use strict";return e=>{const a=e.regex;return{
name:"GraphQL",aliases:["gql"],case_insensitive:!0,disableAutodetect:!1,
keywords:{
keyword:["query","mutation","subscription","type","input","schema","directive","interface","union","scalar","fragment","enum","on"],
literal:["true","false","null"]},
contains:[e.HASH_COMMENT_MODE,e.QUOTE_STRING_MODE,e.NUMBER_MODE,{
scope:"punctuation",match:/[.]{3}/,relevance:0},{scope:"punctuation",
begin:/[\!\(\)\:\=\[\]\{\|\}]{1}/,relevance:0},{scope:"variable",begin:/\$/,
end:/\W/,excludeEnd:!0,relevance:0},{scope:"meta",match:/@\w+/,excludeEnd:!0},{
scope:"symbol",begin:a.concat(/[_A-Za-z][_0-9A-Za-z]*/,a.lookahead(/\s*:/)),
relevance:0}],illegal:[/[;<']/,/BEGIN/]}}})();export default hljsGrammar;
@@ -1,129 +0,0 @@
/*! `ini` grammar compiled for Highlight.js 11.11.1 */
var hljsGrammar = (function () {
'use strict';
/*
Language: TOML, also INI
Description: TOML aims to be a minimal configuration file format that's easy to read due to obvious semantics.
Contributors: Guillaume Gomez <guillaume1.gomez@gmail.com>
Category: common, config
Website: https://github.com/toml-lang/toml
*/
function ini(hljs) {
const regex = hljs.regex;
const NUMBERS = {
className: 'number',
relevance: 0,
variants: [
{ begin: /([+-]+)?[\d]+_[\d_]+/ },
{ begin: hljs.NUMBER_RE }
]
};
const COMMENTS = hljs.COMMENT();
COMMENTS.variants = [
{
begin: /;/,
end: /$/
},
{
begin: /#/,
end: /$/
}
];
const VARIABLES = {
className: 'variable',
variants: [
{ begin: /\$[\w\d"][\w\d_]*/ },
{ begin: /\$\{(.*?)\}/ }
]
};
const LITERALS = {
className: 'literal',
begin: /\bon|off|true|false|yes|no\b/
};
const STRINGS = {
className: "string",
contains: [ hljs.BACKSLASH_ESCAPE ],
variants: [
{
begin: "'''",
end: "'''",
relevance: 10
},
{
begin: '"""',
end: '"""',
relevance: 10
},
{
begin: '"',
end: '"'
},
{
begin: "'",
end: "'"
}
]
};
const ARRAY = {
begin: /\[/,
end: /\]/,
contains: [
COMMENTS,
LITERALS,
VARIABLES,
STRINGS,
NUMBERS,
'self'
],
relevance: 0
};
const BARE_KEY = /[A-Za-z0-9_-]+/;
const QUOTED_KEY_DOUBLE_QUOTE = /"(\\"|[^"])*"/;
const QUOTED_KEY_SINGLE_QUOTE = /'[^']*'/;
const ANY_KEY = regex.either(
BARE_KEY, QUOTED_KEY_DOUBLE_QUOTE, QUOTED_KEY_SINGLE_QUOTE
);
const DOTTED_KEY = regex.concat(
ANY_KEY, '(\\s*\\.\\s*', ANY_KEY, ')*',
regex.lookahead(/\s*=\s*[^#\s]/)
);
return {
name: 'TOML, also INI',
aliases: [ 'toml' ],
case_insensitive: true,
illegal: /\S/,
contains: [
COMMENTS,
{
className: 'section',
begin: /\[+/,
end: /\]+/
},
{
begin: DOTTED_KEY,
className: 'attr',
starts: {
end: /$/,
contains: [
COMMENTS,
ARRAY,
LITERALS,
VARIABLES,
STRINGS,
NUMBERS
]
}
}
]
};
}
return ini;
})();
;
export default hljsGrammar;
-16
View File
@@ -1,16 +0,0 @@
/*! `ini` grammar compiled for Highlight.js 11.11.1 */
var hljsGrammar=(()=>{"use strict";return e=>{const n=e.regex,a={
className:"number",relevance:0,variants:[{begin:/([+-]+)?[\d]+_[\d_]+/},{
begin:e.NUMBER_RE}]},s=e.COMMENT();s.variants=[{begin:/;/,end:/$/},{begin:/#/,
end:/$/}];const i={className:"variable",variants:[{begin:/\$[\w\d"][\w\d_]*/},{
begin:/\$\{(.*?)\}/}]},r={className:"literal",
begin:/\bon|off|true|false|yes|no\b/},t={className:"string",
contains:[e.BACKSLASH_ESCAPE],variants:[{begin:"'''",end:"'''",relevance:10},{
begin:'"""',end:'"""',relevance:10},{begin:'"',end:'"'},{begin:"'",end:"'"}]
},l={begin:/\[/,end:/\]/,contains:[s,r,i,t,a,"self"],relevance:0
},c=n.either(/[A-Za-z0-9_-]+/,/"(\\"|[^"])*"/,/'[^']*'/);return{
name:"TOML, also INI",aliases:["toml"],case_insensitive:!0,illegal:/\S/,
contains:[s,{className:"section",begin:/\[+/,end:/\]+/},{
begin:n.concat(c,"(\\s*\\.\\s*",c,")*",n.lookahead(/\s*=\s*[^#\s]/)),
className:"attr",starts:{end:/$/,contains:[s,l,r,i,t,a]}}]}}})()
;export default hljsGrammar;
@@ -1,299 +0,0 @@
/*! `java` grammar compiled for Highlight.js 11.11.1 */
var hljsGrammar = (function () {
'use strict';
// https://docs.oracle.com/javase/specs/jls/se15/html/jls-3.html#jls-3.10
var decimalDigits = '[0-9](_*[0-9])*';
var frac = `\\.(${decimalDigits})`;
var hexDigits = '[0-9a-fA-F](_*[0-9a-fA-F])*';
var NUMERIC = {
className: 'number',
variants: [
// DecimalFloatingPointLiteral
// including ExponentPart
{ begin: `(\\b(${decimalDigits})((${frac})|\\.)?|(${frac}))` +
`[eE][+-]?(${decimalDigits})[fFdD]?\\b` },
// excluding ExponentPart
{ begin: `\\b(${decimalDigits})((${frac})[fFdD]?\\b|\\.([fFdD]\\b)?)` },
{ begin: `(${frac})[fFdD]?\\b` },
{ begin: `\\b(${decimalDigits})[fFdD]\\b` },
// HexadecimalFloatingPointLiteral
{ begin: `\\b0[xX]((${hexDigits})\\.?|(${hexDigits})?\\.(${hexDigits}))` +
`[pP][+-]?(${decimalDigits})[fFdD]?\\b` },
// DecimalIntegerLiteral
{ begin: '\\b(0|[1-9](_*[0-9])*)[lL]?\\b' },
// HexIntegerLiteral
{ begin: `\\b0[xX](${hexDigits})[lL]?\\b` },
// OctalIntegerLiteral
{ begin: '\\b0(_*[0-7])*[lL]?\\b' },
// BinaryIntegerLiteral
{ begin: '\\b0[bB][01](_*[01])*[lL]?\\b' },
],
relevance: 0
};
/*
Language: Java
Author: Vsevolod Solovyov <vsevolod.solovyov@gmail.com>
Category: common, enterprise
Website: https://www.java.com/
*/
/**
* Allows recursive regex expressions to a given depth
*
* ie: recurRegex("(abc~~~)", /~~~/g, 2) becomes:
* (abc(abc(abc)))
*
* @param {string} re
* @param {RegExp} substitution (should be a g mode regex)
* @param {number} depth
* @returns {string}``
*/
function recurRegex(re, substitution, depth) {
if (depth === -1) return "";
return re.replace(substitution, _ => {
return recurRegex(re, substitution, depth - 1);
});
}
/** @type LanguageFn */
function java(hljs) {
const regex = hljs.regex;
const JAVA_IDENT_RE = '[\u00C0-\u02B8a-zA-Z_$][\u00C0-\u02B8a-zA-Z_$0-9]*';
const GENERIC_IDENT_RE = JAVA_IDENT_RE
+ recurRegex('(?:<' + JAVA_IDENT_RE + '~~~(?:\\s*,\\s*' + JAVA_IDENT_RE + '~~~)*>)?', /~~~/g, 2);
const MAIN_KEYWORDS = [
'synchronized',
'abstract',
'private',
'var',
'static',
'if',
'const ',
'for',
'while',
'strictfp',
'finally',
'protected',
'import',
'native',
'final',
'void',
'enum',
'else',
'break',
'transient',
'catch',
'instanceof',
'volatile',
'case',
'assert',
'package',
'default',
'public',
'try',
'switch',
'continue',
'throws',
'protected',
'public',
'private',
'module',
'requires',
'exports',
'do',
'sealed',
'yield',
'permits',
'goto',
'when'
];
const BUILT_INS = [
'super',
'this'
];
const LITERALS = [
'false',
'true',
'null'
];
const TYPES = [
'char',
'boolean',
'long',
'float',
'int',
'byte',
'short',
'double'
];
const KEYWORDS = {
keyword: MAIN_KEYWORDS,
literal: LITERALS,
type: TYPES,
built_in: BUILT_INS
};
const ANNOTATION = {
className: 'meta',
begin: '@' + JAVA_IDENT_RE,
contains: [
{
begin: /\(/,
end: /\)/,
contains: [ "self" ] // allow nested () inside our annotation
}
]
};
const PARAMS = {
className: 'params',
begin: /\(/,
end: /\)/,
keywords: KEYWORDS,
relevance: 0,
contains: [ hljs.C_BLOCK_COMMENT_MODE ],
endsParent: true
};
return {
name: 'Java',
aliases: [ 'jsp' ],
keywords: KEYWORDS,
illegal: /<\/|#/,
contains: [
hljs.COMMENT(
'/\\*\\*',
'\\*/',
{
relevance: 0,
contains: [
{
// eat up @'s in emails to prevent them to be recognized as doctags
begin: /\w+@/,
relevance: 0
},
{
className: 'doctag',
begin: '@[A-Za-z]+'
}
]
}
),
// relevance boost
{
begin: /import java\.[a-z]+\./,
keywords: "import",
relevance: 2
},
hljs.C_LINE_COMMENT_MODE,
hljs.C_BLOCK_COMMENT_MODE,
{
begin: /"""/,
end: /"""/,
className: "string",
contains: [ hljs.BACKSLASH_ESCAPE ]
},
hljs.APOS_STRING_MODE,
hljs.QUOTE_STRING_MODE,
{
match: [
/\b(?:class|interface|enum|extends|implements|new)/,
/\s+/,
JAVA_IDENT_RE
],
className: {
1: "keyword",
3: "title.class"
}
},
{
// Exceptions for hyphenated keywords
match: /non-sealed/,
scope: "keyword"
},
{
begin: [
regex.concat(/(?!else)/, JAVA_IDENT_RE),
/\s+/,
JAVA_IDENT_RE,
/\s+/,
/=(?!=)/
],
className: {
1: "type",
3: "variable",
5: "operator"
}
},
{
begin: [
/record/,
/\s+/,
JAVA_IDENT_RE
],
className: {
1: "keyword",
3: "title.class"
},
contains: [
PARAMS,
hljs.C_LINE_COMMENT_MODE,
hljs.C_BLOCK_COMMENT_MODE
]
},
{
// Expression keywords prevent 'keyword Name(...)' from being
// recognized as a function definition
beginKeywords: 'new throw return else',
relevance: 0
},
{
begin: [
'(?:' + GENERIC_IDENT_RE + '\\s+)',
hljs.UNDERSCORE_IDENT_RE,
/\s*(?=\()/
],
className: { 2: "title.function" },
keywords: KEYWORDS,
contains: [
{
className: 'params',
begin: /\(/,
end: /\)/,
keywords: KEYWORDS,
relevance: 0,
contains: [
ANNOTATION,
hljs.APOS_STRING_MODE,
hljs.QUOTE_STRING_MODE,
NUMERIC,
hljs.C_BLOCK_COMMENT_MODE
]
},
hljs.C_LINE_COMMENT_MODE,
hljs.C_BLOCK_COMMENT_MODE
]
},
NUMERIC,
ANNOTATION
]
};
}
return java;
})();
;
export default hljsGrammar;
-38
View File
@@ -1,38 +0,0 @@
/*! `java` grammar compiled for Highlight.js 11.11.1 */
var hljsGrammar=(()=>{"use strict"
;var e="[0-9](_*[0-9])*",a=`\\.(${e})`,n="[0-9a-fA-F](_*[0-9a-fA-F])*",s={
className:"number",variants:[{
begin:`(\\b(${e})((${a})|\\.)?|(${a}))[eE][+-]?(${e})[fFdD]?\\b`},{
begin:`\\b(${e})((${a})[fFdD]?\\b|\\.([fFdD]\\b)?)`},{begin:`(${a})[fFdD]?\\b`
},{begin:`\\b(${e})[fFdD]\\b`},{
begin:`\\b0[xX]((${n})\\.?|(${n})?\\.(${n}))[pP][+-]?(${e})[fFdD]?\\b`},{
begin:"\\b(0|[1-9](_*[0-9])*)[lL]?\\b"},{begin:`\\b0[xX](${n})[lL]?\\b`},{
begin:"\\b0(_*[0-7])*[lL]?\\b"},{begin:"\\b0[bB][01](_*[01])*[lL]?\\b"}],
relevance:0};function t(e,a,n){return-1===n?"":e.replace(a,(s=>t(e,a,n-1)))}
return e=>{
const a=e.regex,n="[\xc0-\u02b8a-zA-Z_$][\xc0-\u02b8a-zA-Z_$0-9]*",r=n+t("(?:<"+n+"~~~(?:\\s*,\\s*"+n+"~~~)*>)?",/~~~/g,2),i={
keyword:["synchronized","abstract","private","var","static","if","const ","for","while","strictfp","finally","protected","import","native","final","void","enum","else","break","transient","catch","instanceof","volatile","case","assert","package","default","public","try","switch","continue","throws","protected","public","private","module","requires","exports","do","sealed","yield","permits","goto","when"],
literal:["false","true","null"],
type:["char","boolean","long","float","int","byte","short","double"],
built_in:["super","this"]},l={className:"meta",begin:"@"+n,contains:[{
begin:/\(/,end:/\)/,contains:["self"]}]},c={className:"params",begin:/\(/,
end:/\)/,keywords:i,relevance:0,contains:[e.C_BLOCK_COMMENT_MODE],endsParent:!0}
;return{name:"Java",aliases:["jsp"],keywords:i,illegal:/<\/|#/,
contains:[e.COMMENT("/\\*\\*","\\*/",{relevance:0,contains:[{begin:/\w+@/,
relevance:0},{className:"doctag",begin:"@[A-Za-z]+"}]}),{
begin:/import java\.[a-z]+\./,keywords:"import",relevance:2
},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,{begin:/"""/,end:/"""/,
className:"string",contains:[e.BACKSLASH_ESCAPE]
},e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,{
match:[/\b(?:class|interface|enum|extends|implements|new)/,/\s+/,n],className:{
1:"keyword",3:"title.class"}},{match:/non-sealed/,scope:"keyword"},{
begin:[a.concat(/(?!else)/,n),/\s+/,n,/\s+/,/=(?!=)/],className:{1:"type",
3:"variable",5:"operator"}},{begin:[/record/,/\s+/,n],className:{1:"keyword",
3:"title.class"},contains:[c,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{
beginKeywords:"new throw return else",relevance:0},{
begin:["(?:"+r+"\\s+)",e.UNDERSCORE_IDENT_RE,/\s*(?=\()/],className:{
2:"title.function"},keywords:i,contains:[{className:"params",begin:/\(/,
end:/\)/,keywords:i,relevance:0,
contains:[l,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,s,e.C_BLOCK_COMMENT_MODE]
},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},s,l]}}})()
;export default hljsGrammar;
@@ -1,777 +0,0 @@
/*! `javascript` grammar compiled for Highlight.js 11.11.1 */
var hljsGrammar = (function () {
'use strict';
const IDENT_RE = '[A-Za-z$_][0-9A-Za-z$_]*';
const KEYWORDS = [
"as", // for exports
"in",
"of",
"if",
"for",
"while",
"finally",
"var",
"new",
"function",
"do",
"return",
"void",
"else",
"break",
"catch",
"instanceof",
"with",
"throw",
"case",
"default",
"try",
"switch",
"continue",
"typeof",
"delete",
"let",
"yield",
"const",
"class",
// JS handles these with a special rule
// "get",
// "set",
"debugger",
"async",
"await",
"static",
"import",
"from",
"export",
"extends",
// It's reached stage 3, which is "recommended for implementation":
"using"
];
const LITERALS = [
"true",
"false",
"null",
"undefined",
"NaN",
"Infinity"
];
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects
const TYPES = [
// Fundamental objects
"Object",
"Function",
"Boolean",
"Symbol",
// numbers and dates
"Math",
"Date",
"Number",
"BigInt",
// text
"String",
"RegExp",
// Indexed collections
"Array",
"Float32Array",
"Float64Array",
"Int8Array",
"Uint8Array",
"Uint8ClampedArray",
"Int16Array",
"Int32Array",
"Uint16Array",
"Uint32Array",
"BigInt64Array",
"BigUint64Array",
// Keyed collections
"Set",
"Map",
"WeakSet",
"WeakMap",
// Structured data
"ArrayBuffer",
"SharedArrayBuffer",
"Atomics",
"DataView",
"JSON",
// Control abstraction objects
"Promise",
"Generator",
"GeneratorFunction",
"AsyncFunction",
// Reflection
"Reflect",
"Proxy",
// Internationalization
"Intl",
// WebAssembly
"WebAssembly"
];
const ERROR_TYPES = [
"Error",
"EvalError",
"InternalError",
"RangeError",
"ReferenceError",
"SyntaxError",
"TypeError",
"URIError"
];
const BUILT_IN_GLOBALS = [
"setInterval",
"setTimeout",
"clearInterval",
"clearTimeout",
"require",
"exports",
"eval",
"isFinite",
"isNaN",
"parseFloat",
"parseInt",
"decodeURI",
"decodeURIComponent",
"encodeURI",
"encodeURIComponent",
"escape",
"unescape"
];
const BUILT_IN_VARIABLES = [
"arguments",
"this",
"super",
"console",
"window",
"document",
"localStorage",
"sessionStorage",
"module",
"global" // Node.js
];
const BUILT_INS = [].concat(
BUILT_IN_GLOBALS,
TYPES,
ERROR_TYPES
);
/*
Language: JavaScript
Description: JavaScript (JS) is a lightweight, interpreted, or just-in-time compiled programming language with first-class functions.
Category: common, scripting, web
Website: https://developer.mozilla.org/en-US/docs/Web/JavaScript
*/
/** @type LanguageFn */
function javascript(hljs) {
const regex = hljs.regex;
/**
* Takes a string like "<Booger" and checks to see
* if we can find a matching "</Booger" later in the
* content.
* @param {RegExpMatchArray} match
* @param {{after:number}} param1
*/
const hasClosingTag = (match, { after }) => {
const tag = "</" + match[0].slice(1);
const pos = match.input.indexOf(tag, after);
return pos !== -1;
};
const IDENT_RE$1 = IDENT_RE;
const FRAGMENT = {
begin: '<>',
end: '</>'
};
// to avoid some special cases inside isTrulyOpeningTag
const XML_SELF_CLOSING = /<[A-Za-z0-9\\._:-]+\s*\/>/;
const XML_TAG = {
begin: /<[A-Za-z0-9\\._:-]+/,
end: /\/[A-Za-z0-9\\._:-]+>|\/>/,
/**
* @param {RegExpMatchArray} match
* @param {CallbackResponse} response
*/
isTrulyOpeningTag: (match, response) => {
const afterMatchIndex = match[0].length + match.index;
const nextChar = match.input[afterMatchIndex];
if (
// HTML should not include another raw `<` inside a tag
// nested type?
// `<Array<Array<number>>`, etc.
nextChar === "<" ||
// the , gives away that this is not HTML
// `<T, A extends keyof T, V>`
nextChar === ","
) {
response.ignoreMatch();
return;
}
// `<something>`
// Quite possibly a tag, lets look for a matching closing tag...
if (nextChar === ">") {
// if we cannot find a matching closing tag, then we
// will ignore it
if (!hasClosingTag(match, { after: afterMatchIndex })) {
response.ignoreMatch();
}
}
// `<blah />` (self-closing)
// handled by simpleSelfClosing rule
let m;
const afterMatch = match.input.substring(afterMatchIndex);
// some more template typing stuff
// <T = any>(key?: string) => Modify<
if ((m = afterMatch.match(/^\s*=/))) {
response.ignoreMatch();
return;
}
// `<From extends string>`
// technically this could be HTML, but it smells like a type
// NOTE: This is ugh, but added specifically for https://github.com/highlightjs/highlight.js/issues/3276
if ((m = afterMatch.match(/^\s+extends\s+/))) {
if (m.index === 0) {
response.ignoreMatch();
// eslint-disable-next-line no-useless-return
return;
}
}
}
};
const KEYWORDS$1 = {
$pattern: IDENT_RE,
keyword: KEYWORDS,
literal: LITERALS,
built_in: BUILT_INS,
"variable.language": BUILT_IN_VARIABLES
};
// https://tc39.es/ecma262/#sec-literals-numeric-literals
const decimalDigits = '[0-9](_?[0-9])*';
const frac = `\\.(${decimalDigits})`;
// DecimalIntegerLiteral, including Annex B NonOctalDecimalIntegerLiteral
// https://tc39.es/ecma262/#sec-additional-syntax-numeric-literals
const decimalInteger = `0|[1-9](_?[0-9])*|0[0-7]*[89][0-9]*`;
const NUMBER = {
className: 'number',
variants: [
// DecimalLiteral
{ begin: `(\\b(${decimalInteger})((${frac})|\\.)?|(${frac}))` +
`[eE][+-]?(${decimalDigits})\\b` },
{ begin: `\\b(${decimalInteger})\\b((${frac})\\b|\\.)?|(${frac})\\b` },
// DecimalBigIntegerLiteral
{ begin: `\\b(0|[1-9](_?[0-9])*)n\\b` },
// NonDecimalIntegerLiteral
{ begin: "\\b0[xX][0-9a-fA-F](_?[0-9a-fA-F])*n?\\b" },
{ begin: "\\b0[bB][0-1](_?[0-1])*n?\\b" },
{ begin: "\\b0[oO][0-7](_?[0-7])*n?\\b" },
// LegacyOctalIntegerLiteral (does not include underscore separators)
// https://tc39.es/ecma262/#sec-additional-syntax-numeric-literals
{ begin: "\\b0[0-7]+n?\\b" },
],
relevance: 0
};
const SUBST = {
className: 'subst',
begin: '\\$\\{',
end: '\\}',
keywords: KEYWORDS$1,
contains: [] // defined later
};
const HTML_TEMPLATE = {
begin: '\.?html`',
end: '',
starts: {
end: '`',
returnEnd: false,
contains: [
hljs.BACKSLASH_ESCAPE,
SUBST
],
subLanguage: 'xml'
}
};
const CSS_TEMPLATE = {
begin: '\.?css`',
end: '',
starts: {
end: '`',
returnEnd: false,
contains: [
hljs.BACKSLASH_ESCAPE,
SUBST
],
subLanguage: 'css'
}
};
const GRAPHQL_TEMPLATE = {
begin: '\.?gql`',
end: '',
starts: {
end: '`',
returnEnd: false,
contains: [
hljs.BACKSLASH_ESCAPE,
SUBST
],
subLanguage: 'graphql'
}
};
const TEMPLATE_STRING = {
className: 'string',
begin: '`',
end: '`',
contains: [
hljs.BACKSLASH_ESCAPE,
SUBST
]
};
const JSDOC_COMMENT = hljs.COMMENT(
/\/\*\*(?!\/)/,
'\\*/',
{
relevance: 0,
contains: [
{
begin: '(?=@[A-Za-z]+)',
relevance: 0,
contains: [
{
className: 'doctag',
begin: '@[A-Za-z]+'
},
{
className: 'type',
begin: '\\{',
end: '\\}',
excludeEnd: true,
excludeBegin: true,
relevance: 0
},
{
className: 'variable',
begin: IDENT_RE$1 + '(?=\\s*(-)|$)',
endsParent: true,
relevance: 0
},
// eat spaces (not newlines) so we can find
// types or variables
{
begin: /(?=[^\n])\s/,
relevance: 0
}
]
}
]
}
);
const COMMENT = {
className: "comment",
variants: [
JSDOC_COMMENT,
hljs.C_BLOCK_COMMENT_MODE,
hljs.C_LINE_COMMENT_MODE
]
};
const SUBST_INTERNALS = [
hljs.APOS_STRING_MODE,
hljs.QUOTE_STRING_MODE,
HTML_TEMPLATE,
CSS_TEMPLATE,
GRAPHQL_TEMPLATE,
TEMPLATE_STRING,
// Skip numbers when they are part of a variable name
{ match: /\$\d+/ },
NUMBER,
// This is intentional:
// See https://github.com/highlightjs/highlight.js/issues/3288
// hljs.REGEXP_MODE
];
SUBST.contains = SUBST_INTERNALS
.concat({
// we need to pair up {} inside our subst to prevent
// it from ending too early by matching another }
begin: /\{/,
end: /\}/,
keywords: KEYWORDS$1,
contains: [
"self"
].concat(SUBST_INTERNALS)
});
const SUBST_AND_COMMENTS = [].concat(COMMENT, SUBST.contains);
const PARAMS_CONTAINS = SUBST_AND_COMMENTS.concat([
// eat recursive parens in sub expressions
{
begin: /(\s*)\(/,
end: /\)/,
keywords: KEYWORDS$1,
contains: ["self"].concat(SUBST_AND_COMMENTS)
}
]);
const PARAMS = {
className: 'params',
// convert this to negative lookbehind in v12
begin: /(\s*)\(/, // to match the parms with
end: /\)/,
excludeBegin: true,
excludeEnd: true,
keywords: KEYWORDS$1,
contains: PARAMS_CONTAINS
};
// ES6 classes
const CLASS_OR_EXTENDS = {
variants: [
// class Car extends vehicle
{
match: [
/class/,
/\s+/,
IDENT_RE$1,
/\s+/,
/extends/,
/\s+/,
regex.concat(IDENT_RE$1, "(", regex.concat(/\./, IDENT_RE$1), ")*")
],
scope: {
1: "keyword",
3: "title.class",
5: "keyword",
7: "title.class.inherited"
}
},
// class Car
{
match: [
/class/,
/\s+/,
IDENT_RE$1
],
scope: {
1: "keyword",
3: "title.class"
}
},
]
};
const CLASS_REFERENCE = {
relevance: 0,
match:
regex.either(
// Hard coded exceptions
/\bJSON/,
// Float32Array, OutT
/\b[A-Z][a-z]+([A-Z][a-z]*|\d)*/,
// CSSFactory, CSSFactoryT
/\b[A-Z]{2,}([A-Z][a-z]+|\d)+([A-Z][a-z]*)*/,
// FPs, FPsT
/\b[A-Z]{2,}[a-z]+([A-Z][a-z]+|\d)*([A-Z][a-z]*)*/,
// P
// single letters are not highlighted
// BLAH
// this will be flagged as a UPPER_CASE_CONSTANT instead
),
className: "title.class",
keywords: {
_: [
// se we still get relevance credit for JS library classes
...TYPES,
...ERROR_TYPES
]
}
};
const USE_STRICT = {
label: "use_strict",
className: 'meta',
relevance: 10,
begin: /^\s*['"]use (strict|asm)['"]/
};
const FUNCTION_DEFINITION = {
variants: [
{
match: [
/function/,
/\s+/,
IDENT_RE$1,
/(?=\s*\()/
]
},
// anonymous function
{
match: [
/function/,
/\s*(?=\()/
]
}
],
className: {
1: "keyword",
3: "title.function"
},
label: "func.def",
contains: [ PARAMS ],
illegal: /%/
};
const UPPER_CASE_CONSTANT = {
relevance: 0,
match: /\b[A-Z][A-Z_0-9]+\b/,
className: "variable.constant"
};
function noneOf(list) {
return regex.concat("(?!", list.join("|"), ")");
}
const FUNCTION_CALL = {
match: regex.concat(
/\b/,
noneOf([
...BUILT_IN_GLOBALS,
"super",
"import"
].map(x => `${x}\\s*\\(`)),
IDENT_RE$1, regex.lookahead(/\s*\(/)),
className: "title.function",
relevance: 0
};
const PROPERTY_ACCESS = {
begin: regex.concat(/\./, regex.lookahead(
regex.concat(IDENT_RE$1, /(?![0-9A-Za-z$_(])/)
)),
end: IDENT_RE$1,
excludeBegin: true,
keywords: "prototype",
className: "property",
relevance: 0
};
const GETTER_OR_SETTER = {
match: [
/get|set/,
/\s+/,
IDENT_RE$1,
/(?=\()/
],
className: {
1: "keyword",
3: "title.function"
},
contains: [
{ // eat to avoid empty params
begin: /\(\)/
},
PARAMS
]
};
const FUNC_LEAD_IN_RE = '(\\(' +
'[^()]*(\\(' +
'[^()]*(\\(' +
'[^()]*' +
'\\)[^()]*)*' +
'\\)[^()]*)*' +
'\\)|' + hljs.UNDERSCORE_IDENT_RE + ')\\s*=>';
const FUNCTION_VARIABLE = {
match: [
/const|var|let/, /\s+/,
IDENT_RE$1, /\s*/,
/=\s*/,
/(async\s*)?/, // async is optional
regex.lookahead(FUNC_LEAD_IN_RE)
],
keywords: "async",
className: {
1: "keyword",
3: "title.function"
},
contains: [
PARAMS
]
};
return {
name: 'JavaScript',
aliases: ['js', 'jsx', 'mjs', 'cjs'],
keywords: KEYWORDS$1,
// this will be extended by TypeScript
exports: { PARAMS_CONTAINS, CLASS_REFERENCE },
illegal: /#(?![$_A-z])/,
contains: [
hljs.SHEBANG({
label: "shebang",
binary: "node",
relevance: 5
}),
USE_STRICT,
hljs.APOS_STRING_MODE,
hljs.QUOTE_STRING_MODE,
HTML_TEMPLATE,
CSS_TEMPLATE,
GRAPHQL_TEMPLATE,
TEMPLATE_STRING,
COMMENT,
// Skip numbers when they are part of a variable name
{ match: /\$\d+/ },
NUMBER,
CLASS_REFERENCE,
{
scope: 'attr',
match: IDENT_RE$1 + regex.lookahead(':'),
relevance: 0
},
FUNCTION_VARIABLE,
{ // "value" container
begin: '(' + hljs.RE_STARTERS_RE + '|\\b(case|return|throw)\\b)\\s*',
keywords: 'return throw case',
relevance: 0,
contains: [
COMMENT,
hljs.REGEXP_MODE,
{
className: 'function',
// we have to count the parens to make sure we actually have the
// correct bounding ( ) before the =>. There could be any number of
// sub-expressions inside also surrounded by parens.
begin: FUNC_LEAD_IN_RE,
returnBegin: true,
end: '\\s*=>',
contains: [
{
className: 'params',
variants: [
{
begin: hljs.UNDERSCORE_IDENT_RE,
relevance: 0
},
{
className: null,
begin: /\(\s*\)/,
skip: true
},
{
begin: /(\s*)\(/,
end: /\)/,
excludeBegin: true,
excludeEnd: true,
keywords: KEYWORDS$1,
contains: PARAMS_CONTAINS
}
]
}
]
},
{ // could be a comma delimited list of params to a function call
begin: /,/,
relevance: 0
},
{
match: /\s+/,
relevance: 0
},
{ // JSX
variants: [
{ begin: FRAGMENT.begin, end: FRAGMENT.end },
{ match: XML_SELF_CLOSING },
{
begin: XML_TAG.begin,
// we carefully check the opening tag to see if it truly
// is a tag and not a false positive
'on:begin': XML_TAG.isTrulyOpeningTag,
end: XML_TAG.end
}
],
subLanguage: 'xml',
contains: [
{
begin: XML_TAG.begin,
end: XML_TAG.end,
skip: true,
contains: ['self']
}
]
}
],
},
FUNCTION_DEFINITION,
{
// prevent this from getting swallowed up by function
// since they appear "function like"
beginKeywords: "while if switch catch for"
},
{
// we have to count the parens to make sure we actually have the correct
// bounding ( ). There could be any number of sub-expressions inside
// also surrounded by parens.
begin: '\\b(?!function)' + hljs.UNDERSCORE_IDENT_RE +
'\\(' + // first parens
'[^()]*(\\(' +
'[^()]*(\\(' +
'[^()]*' +
'\\)[^()]*)*' +
'\\)[^()]*)*' +
'\\)\\s*\\{', // end parens
returnBegin:true,
label: "func.def",
contains: [
PARAMS,
hljs.inherit(hljs.TITLE_MODE, { begin: IDENT_RE$1, className: "title.function" })
]
},
// catch ... so it won't trigger the property rule below
{
match: /\.\.\./,
relevance: 0
},
PROPERTY_ACCESS,
// hack: prevents detection of keywords in some circumstances
// .keyword()
// $keyword = x
{
match: '\\$' + IDENT_RE$1,
relevance: 0
},
{
match: [ /\bconstructor(?=\s*\()/ ],
className: { 1: "title.function" },
contains: [ PARAMS ]
},
FUNCTION_CALL,
UPPER_CASE_CONSTANT,
CLASS_OR_EXTENDS,
GETTER_OR_SETTER,
{
match: /\$[(.]/ // relevance booster for a pattern common to JS libs: `$(something)` and `$.something`
}
]
};
}
return javascript;
})();
;
export default hljsGrammar;
@@ -1,81 +0,0 @@
/*! `javascript` grammar compiled for Highlight.js 11.11.1 */
var hljsGrammar=(()=>{"use strict"
;const e="[A-Za-z$_][0-9A-Za-z$_]*",n=["as","in","of","if","for","while","finally","var","new","function","do","return","void","else","break","catch","instanceof","with","throw","case","default","try","switch","continue","typeof","delete","let","yield","const","class","debugger","async","await","static","import","from","export","extends","using"],a=["true","false","null","undefined","NaN","Infinity"],t=["Object","Function","Boolean","Symbol","Math","Date","Number","BigInt","String","RegExp","Array","Float32Array","Float64Array","Int8Array","Uint8Array","Uint8ClampedArray","Int16Array","Int32Array","Uint16Array","Uint32Array","BigInt64Array","BigUint64Array","Set","Map","WeakSet","WeakMap","ArrayBuffer","SharedArrayBuffer","Atomics","DataView","JSON","Promise","Generator","GeneratorFunction","AsyncFunction","Reflect","Proxy","Intl","WebAssembly"],s=["Error","EvalError","InternalError","RangeError","ReferenceError","SyntaxError","TypeError","URIError"],r=["setInterval","setTimeout","clearInterval","clearTimeout","require","exports","eval","isFinite","isNaN","parseFloat","parseInt","decodeURI","decodeURIComponent","encodeURI","encodeURIComponent","escape","unescape"],c=["arguments","this","super","console","window","document","localStorage","sessionStorage","module","global"],i=[].concat(r,t,s)
;return o=>{const l=o.regex,d=e,b={begin:/<[A-Za-z0-9\\._:-]+/,
end:/\/[A-Za-z0-9\\._:-]+>|\/>/,isTrulyOpeningTag:(e,n)=>{
const a=e[0].length+e.index,t=e.input[a]
;if("<"===t||","===t)return void n.ignoreMatch();let s
;">"===t&&(((e,{after:n})=>{const a="</"+e[0].slice(1)
;return-1!==e.input.indexOf(a,n)})(e,{after:a})||n.ignoreMatch())
;const r=e.input.substring(a)
;((s=r.match(/^\s*=/))||(s=r.match(/^\s+extends\s+/))&&0===s.index)&&n.ignoreMatch()
}},g={$pattern:e,keyword:n,literal:a,built_in:i,"variable.language":c
},u="[0-9](_?[0-9])*",m=`\\.(${u})`,E="0|[1-9](_?[0-9])*|0[0-7]*[89][0-9]*",A={
className:"number",variants:[{
begin:`(\\b(${E})((${m})|\\.)?|(${m}))[eE][+-]?(${u})\\b`},{
begin:`\\b(${E})\\b((${m})\\b|\\.)?|(${m})\\b`},{
begin:"\\b(0|[1-9](_?[0-9])*)n\\b"},{
begin:"\\b0[xX][0-9a-fA-F](_?[0-9a-fA-F])*n?\\b"},{
begin:"\\b0[bB][0-1](_?[0-1])*n?\\b"},{begin:"\\b0[oO][0-7](_?[0-7])*n?\\b"},{
begin:"\\b0[0-7]+n?\\b"}],relevance:0},y={className:"subst",begin:"\\$\\{",
end:"\\}",keywords:g,contains:[]},h={begin:".?html`",end:"",starts:{end:"`",
returnEnd:!1,contains:[o.BACKSLASH_ESCAPE,y],subLanguage:"xml"}},_={
begin:".?css`",end:"",starts:{end:"`",returnEnd:!1,
contains:[o.BACKSLASH_ESCAPE,y],subLanguage:"css"}},N={begin:".?gql`",end:"",
starts:{end:"`",returnEnd:!1,contains:[o.BACKSLASH_ESCAPE,y],
subLanguage:"graphql"}},f={className:"string",begin:"`",end:"`",
contains:[o.BACKSLASH_ESCAPE,y]},p={className:"comment",
variants:[o.COMMENT(/\/\*\*(?!\/)/,"\\*/",{relevance:0,contains:[{
begin:"(?=@[A-Za-z]+)",relevance:0,contains:[{className:"doctag",
begin:"@[A-Za-z]+"},{className:"type",begin:"\\{",end:"\\}",excludeEnd:!0,
excludeBegin:!0,relevance:0},{className:"variable",begin:d+"(?=\\s*(-)|$)",
endsParent:!0,relevance:0},{begin:/(?=[^\n])\s/,relevance:0}]}]
}),o.C_BLOCK_COMMENT_MODE,o.C_LINE_COMMENT_MODE]
},v=[o.APOS_STRING_MODE,o.QUOTE_STRING_MODE,h,_,N,f,{match:/\$\d+/},A]
;y.contains=v.concat({begin:/\{/,end:/\}/,keywords:g,contains:["self"].concat(v)
});const S=[].concat(p,y.contains),w=S.concat([{begin:/(\s*)\(/,end:/\)/,
keywords:g,contains:["self"].concat(S)}]),R={className:"params",begin:/(\s*)\(/,
end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:g,contains:w},O={variants:[{
match:[/class/,/\s+/,d,/\s+/,/extends/,/\s+/,l.concat(d,"(",l.concat(/\./,d),")*")],
scope:{1:"keyword",3:"title.class",5:"keyword",7:"title.class.inherited"}},{
match:[/class/,/\s+/,d],scope:{1:"keyword",3:"title.class"}}]},k={relevance:0,
match:l.either(/\bJSON/,/\b[A-Z][a-z]+([A-Z][a-z]*|\d)*/,/\b[A-Z]{2,}([A-Z][a-z]+|\d)+([A-Z][a-z]*)*/,/\b[A-Z]{2,}[a-z]+([A-Z][a-z]+|\d)*([A-Z][a-z]*)*/),
className:"title.class",keywords:{_:[...t,...s]}},I={variants:[{
match:[/function/,/\s+/,d,/(?=\s*\()/]},{match:[/function/,/\s*(?=\()/]}],
className:{1:"keyword",3:"title.function"},label:"func.def",contains:[R],
illegal:/%/},x={
match:l.concat(/\b/,(T=[...r,"super","import"].map((e=>e+"\\s*\\(")),
l.concat("(?!",T.join("|"),")")),d,l.lookahead(/\s*\(/)),
className:"title.function",relevance:0};var T;const C={
begin:l.concat(/\./,l.lookahead(l.concat(d,/(?![0-9A-Za-z$_(])/))),end:d,
excludeBegin:!0,keywords:"prototype",className:"property",relevance:0},M={
match:[/get|set/,/\s+/,d,/(?=\()/],className:{1:"keyword",3:"title.function"},
contains:[{begin:/\(\)/},R]
},B="(\\([^()]*(\\([^()]*(\\([^()]*\\)[^()]*)*\\)[^()]*)*\\)|"+o.UNDERSCORE_IDENT_RE+")\\s*=>",$={
match:[/const|var|let/,/\s+/,d,/\s*/,/=\s*/,/(async\s*)?/,l.lookahead(B)],
keywords:"async",className:{1:"keyword",3:"title.function"},contains:[R]}
;return{name:"JavaScript",aliases:["js","jsx","mjs","cjs"],keywords:g,exports:{
PARAMS_CONTAINS:w,CLASS_REFERENCE:k},illegal:/#(?![$_A-z])/,
contains:[o.SHEBANG({label:"shebang",binary:"node",relevance:5}),{
label:"use_strict",className:"meta",relevance:10,
begin:/^\s*['"]use (strict|asm)['"]/
},o.APOS_STRING_MODE,o.QUOTE_STRING_MODE,h,_,N,f,p,{match:/\$\d+/},A,k,{
scope:"attr",match:d+l.lookahead(":"),relevance:0},$,{
begin:"("+o.RE_STARTERS_RE+"|\\b(case|return|throw)\\b)\\s*",
keywords:"return throw case",relevance:0,contains:[p,o.REGEXP_MODE,{
className:"function",begin:B,returnBegin:!0,end:"\\s*=>",contains:[{
className:"params",variants:[{begin:o.UNDERSCORE_IDENT_RE,relevance:0},{
className:null,begin:/\(\s*\)/,skip:!0},{begin:/(\s*)\(/,end:/\)/,
excludeBegin:!0,excludeEnd:!0,keywords:g,contains:w}]}]},{begin:/,/,relevance:0
},{match:/\s+/,relevance:0},{variants:[{begin:"<>",end:"</>"},{
match:/<[A-Za-z0-9\\._:-]+\s*\/>/},{begin:b.begin,
"on:begin":b.isTrulyOpeningTag,end:b.end}],subLanguage:"xml",contains:[{
begin:b.begin,end:b.end,skip:!0,contains:["self"]}]}]},I,{
beginKeywords:"while if switch catch for"},{
begin:"\\b(?!function)"+o.UNDERSCORE_IDENT_RE+"\\([^()]*(\\([^()]*(\\([^()]*\\)[^()]*)*\\)[^()]*)*\\)\\s*\\{",
returnBegin:!0,label:"func.def",contains:[R,o.inherit(o.TITLE_MODE,{begin:d,
className:"title.function"})]},{match:/\.\.\./,relevance:0},C,{match:"\\$"+d,
relevance:0},{match:[/\bconstructor(?=\s*\()/],className:{1:"title.function"},
contains:[R]},x,{relevance:0,match:/\b[A-Z][A-Z_0-9]+\b/,
className:"variable.constant"},O,M,{match:/\$[(.]/}]}}})()
;export default hljsGrammar;
@@ -1,62 +0,0 @@
/*! `json` grammar compiled for Highlight.js 11.11.1 */
var hljsGrammar = (function () {
'use strict';
/*
Language: JSON
Description: JSON (JavaScript Object Notation) is a lightweight data-interchange format.
Author: Ivan Sagalaev <maniac@softwaremaniacs.org>
Website: http://www.json.org
Category: common, protocols, web
*/
function json(hljs) {
const ATTRIBUTE = {
className: 'attr',
begin: /"(\\.|[^\\"\r\n])*"(?=\s*:)/,
relevance: 1.01
};
const PUNCTUATION = {
match: /[{}[\],:]/,
className: "punctuation",
relevance: 0
};
const LITERALS = [
"true",
"false",
"null"
];
// NOTE: normally we would rely on `keywords` for this but using a mode here allows us
// - to use the very tight `illegal: \S` rule later to flag any other character
// - as illegal indicating that despite looking like JSON we do not truly have
// - JSON and thus improve false-positively greatly since JSON will try and claim
// - all sorts of JSON looking stuff
const LITERALS_MODE = {
scope: "literal",
beginKeywords: LITERALS.join(" "),
};
return {
name: 'JSON',
aliases: ['jsonc'],
keywords:{
literal: LITERALS,
},
contains: [
ATTRIBUTE,
PUNCTUATION,
hljs.QUOTE_STRING_MODE,
LITERALS_MODE,
hljs.C_NUMBER_MODE,
hljs.C_LINE_COMMENT_MODE,
hljs.C_BLOCK_COMMENT_MODE
],
illegal: '\\S'
};
}
return json;
})();
;
export default hljsGrammar;
-8
View File
@@ -1,8 +0,0 @@
/*! `json` grammar compiled for Highlight.js 11.11.1 */
var hljsGrammar=(()=>{"use strict";return e=>{
const a=["true","false","null"],r={scope:"literal",beginKeywords:a.join(" ")}
;return{name:"JSON",aliases:["jsonc"],keywords:{literal:a},contains:[{
className:"attr",begin:/"(\\.|[^\\"\r\n])*"(?=\s*:)/,relevance:1.01},{
match:/[{}[\],:]/,className:"punctuation",relevance:0
},e.QUOTE_STRING_MODE,r,e.C_NUMBER_MODE,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE],
illegal:"\\S"}}})();export default hljsGrammar;
@@ -1,294 +0,0 @@
/*! `kotlin` grammar compiled for Highlight.js 11.11.1 */
var hljsGrammar = (function () {
'use strict';
// https://docs.oracle.com/javase/specs/jls/se15/html/jls-3.html#jls-3.10
var decimalDigits = '[0-9](_*[0-9])*';
var frac = `\\.(${decimalDigits})`;
var hexDigits = '[0-9a-fA-F](_*[0-9a-fA-F])*';
var NUMERIC = {
className: 'number',
variants: [
// DecimalFloatingPointLiteral
// including ExponentPart
{ begin: `(\\b(${decimalDigits})((${frac})|\\.)?|(${frac}))` +
`[eE][+-]?(${decimalDigits})[fFdD]?\\b` },
// excluding ExponentPart
{ begin: `\\b(${decimalDigits})((${frac})[fFdD]?\\b|\\.([fFdD]\\b)?)` },
{ begin: `(${frac})[fFdD]?\\b` },
{ begin: `\\b(${decimalDigits})[fFdD]\\b` },
// HexadecimalFloatingPointLiteral
{ begin: `\\b0[xX]((${hexDigits})\\.?|(${hexDigits})?\\.(${hexDigits}))` +
`[pP][+-]?(${decimalDigits})[fFdD]?\\b` },
// DecimalIntegerLiteral
{ begin: '\\b(0|[1-9](_*[0-9])*)[lL]?\\b' },
// HexIntegerLiteral
{ begin: `\\b0[xX](${hexDigits})[lL]?\\b` },
// OctalIntegerLiteral
{ begin: '\\b0(_*[0-7])*[lL]?\\b' },
// BinaryIntegerLiteral
{ begin: '\\b0[bB][01](_*[01])*[lL]?\\b' },
],
relevance: 0
};
/*
Language: Kotlin
Description: Kotlin is an OSS statically typed programming language that targets the JVM, Android, JavaScript and Native.
Author: Sergey Mashkov <cy6erGn0m@gmail.com>
Website: https://kotlinlang.org
Category: common
*/
function kotlin(hljs) {
const KEYWORDS = {
keyword:
'abstract as val var vararg get set class object open private protected public noinline '
+ 'crossinline dynamic final enum if else do while for when throw try catch finally '
+ 'import package is in fun override companion reified inline lateinit init '
+ 'interface annotation data sealed internal infix operator out by constructor super '
+ 'tailrec where const inner suspend typealias external expect actual',
built_in:
'Byte Short Char Int Long Boolean Float Double Void Unit Nothing',
literal:
'true false null'
};
const KEYWORDS_WITH_LABEL = {
className: 'keyword',
begin: /\b(break|continue|return|this)\b/,
starts: { contains: [
{
className: 'symbol',
begin: /@\w+/
}
] }
};
const LABEL = {
className: 'symbol',
begin: hljs.UNDERSCORE_IDENT_RE + '@'
};
// for string templates
const SUBST = {
className: 'subst',
begin: /\$\{/,
end: /\}/,
contains: [ hljs.C_NUMBER_MODE ]
};
const VARIABLE = {
className: 'variable',
begin: '\\$' + hljs.UNDERSCORE_IDENT_RE
};
const STRING = {
className: 'string',
variants: [
{
begin: '"""',
end: '"""(?=[^"])',
contains: [
VARIABLE,
SUBST
]
},
// Can't use built-in modes easily, as we want to use STRING in the meta
// context as 'meta-string' and there's no syntax to remove explicitly set
// classNames in built-in modes.
{
begin: '\'',
end: '\'',
illegal: /\n/,
contains: [ hljs.BACKSLASH_ESCAPE ]
},
{
begin: '"',
end: '"',
illegal: /\n/,
contains: [
hljs.BACKSLASH_ESCAPE,
VARIABLE,
SUBST
]
}
]
};
SUBST.contains.push(STRING);
const ANNOTATION_USE_SITE = {
className: 'meta',
begin: '@(?:file|property|field|get|set|receiver|param|setparam|delegate)\\s*:(?:\\s*' + hljs.UNDERSCORE_IDENT_RE + ')?'
};
const ANNOTATION = {
className: 'meta',
begin: '@' + hljs.UNDERSCORE_IDENT_RE,
contains: [
{
begin: /\(/,
end: /\)/,
contains: [
hljs.inherit(STRING, { className: 'string' }),
"self"
]
}
]
};
// https://kotlinlang.org/docs/reference/whatsnew11.html#underscores-in-numeric-literals
// According to the doc above, the number mode of kotlin is the same as java 8,
// so the code below is copied from java.js
const KOTLIN_NUMBER_MODE = NUMERIC;
const KOTLIN_NESTED_COMMENT = hljs.COMMENT(
'/\\*', '\\*/',
{ contains: [ hljs.C_BLOCK_COMMENT_MODE ] }
);
const KOTLIN_PAREN_TYPE = { variants: [
{
className: 'type',
begin: hljs.UNDERSCORE_IDENT_RE
},
{
begin: /\(/,
end: /\)/,
contains: [] // defined later
}
] };
const KOTLIN_PAREN_TYPE2 = KOTLIN_PAREN_TYPE;
KOTLIN_PAREN_TYPE2.variants[1].contains = [ KOTLIN_PAREN_TYPE ];
KOTLIN_PAREN_TYPE.variants[1].contains = [ KOTLIN_PAREN_TYPE2 ];
return {
name: 'Kotlin',
aliases: [
'kt',
'kts'
],
keywords: KEYWORDS,
contains: [
hljs.COMMENT(
'/\\*\\*',
'\\*/',
{
relevance: 0,
contains: [
{
className: 'doctag',
begin: '@[A-Za-z]+'
}
]
}
),
hljs.C_LINE_COMMENT_MODE,
KOTLIN_NESTED_COMMENT,
KEYWORDS_WITH_LABEL,
LABEL,
ANNOTATION_USE_SITE,
ANNOTATION,
{
className: 'function',
beginKeywords: 'fun',
end: '[(]|$',
returnBegin: true,
excludeEnd: true,
keywords: KEYWORDS,
relevance: 5,
contains: [
{
begin: hljs.UNDERSCORE_IDENT_RE + '\\s*\\(',
returnBegin: true,
relevance: 0,
contains: [ hljs.UNDERSCORE_TITLE_MODE ]
},
{
className: 'type',
begin: /</,
end: />/,
keywords: 'reified',
relevance: 0
},
{
className: 'params',
begin: /\(/,
end: /\)/,
endsParent: true,
keywords: KEYWORDS,
relevance: 0,
contains: [
{
begin: /:/,
end: /[=,\/]/,
endsWithParent: true,
contains: [
KOTLIN_PAREN_TYPE,
hljs.C_LINE_COMMENT_MODE,
KOTLIN_NESTED_COMMENT
],
relevance: 0
},
hljs.C_LINE_COMMENT_MODE,
KOTLIN_NESTED_COMMENT,
ANNOTATION_USE_SITE,
ANNOTATION,
STRING,
hljs.C_NUMBER_MODE
]
},
KOTLIN_NESTED_COMMENT
]
},
{
begin: [
/class|interface|trait/,
/\s+/,
hljs.UNDERSCORE_IDENT_RE
],
beginScope: {
3: "title.class"
},
keywords: 'class interface trait',
end: /[:\{(]|$/,
excludeEnd: true,
illegal: 'extends implements',
contains: [
{ beginKeywords: 'public protected internal private constructor' },
hljs.UNDERSCORE_TITLE_MODE,
{
className: 'type',
begin: /</,
end: />/,
excludeBegin: true,
excludeEnd: true,
relevance: 0
},
{
className: 'type',
begin: /[,:]\s*/,
end: /[<\(,){\s]|$/,
excludeBegin: true,
returnEnd: true
},
ANNOTATION_USE_SITE,
ANNOTATION
]
},
STRING,
{
className: 'meta',
begin: "^#!/usr/bin/env",
end: '$',
illegal: '\n'
},
KOTLIN_NUMBER_MODE
]
};
}
return kotlin;
})();
;
export default hljsGrammar;
-46
View File
@@ -1,46 +0,0 @@
/*! `kotlin` grammar compiled for Highlight.js 11.11.1 */
var hljsGrammar=(()=>{"use strict"
;var e="[0-9](_*[0-9])*",n=`\\.(${e})`,a="[0-9a-fA-F](_*[0-9a-fA-F])*",i={
className:"number",variants:[{
begin:`(\\b(${e})((${n})|\\.)?|(${n}))[eE][+-]?(${e})[fFdD]?\\b`},{
begin:`\\b(${e})((${n})[fFdD]?\\b|\\.([fFdD]\\b)?)`},{begin:`(${n})[fFdD]?\\b`
},{begin:`\\b(${e})[fFdD]\\b`},{
begin:`\\b0[xX]((${a})\\.?|(${a})?\\.(${a}))[pP][+-]?(${e})[fFdD]?\\b`},{
begin:"\\b(0|[1-9](_*[0-9])*)[lL]?\\b"},{begin:`\\b0[xX](${a})[lL]?\\b`},{
begin:"\\b0(_*[0-7])*[lL]?\\b"},{begin:"\\b0[bB][01](_*[01])*[lL]?\\b"}],
relevance:0};return e=>{const n={
keyword:"abstract as val var vararg get set class object open private protected public noinline crossinline dynamic final enum if else do while for when throw try catch finally import package is in fun override companion reified inline lateinit init interface annotation data sealed internal infix operator out by constructor super tailrec where const inner suspend typealias external expect actual",
built_in:"Byte Short Char Int Long Boolean Float Double Void Unit Nothing",
literal:"true false null"},a={className:"symbol",begin:e.UNDERSCORE_IDENT_RE+"@"
},s={className:"subst",begin:/\$\{/,end:/\}/,contains:[e.C_NUMBER_MODE]},t={
className:"variable",begin:"\\$"+e.UNDERSCORE_IDENT_RE},r={className:"string",
variants:[{begin:'"""',end:'"""(?=[^"])',contains:[t,s]},{begin:"'",end:"'",
illegal:/\n/,contains:[e.BACKSLASH_ESCAPE]},{begin:'"',end:'"',illegal:/\n/,
contains:[e.BACKSLASH_ESCAPE,t,s]}]};s.contains.push(r);const l={
className:"meta",
begin:"@(?:file|property|field|get|set|receiver|param|setparam|delegate)\\s*:(?:\\s*"+e.UNDERSCORE_IDENT_RE+")?"
},c={className:"meta",begin:"@"+e.UNDERSCORE_IDENT_RE,contains:[{begin:/\(/,
end:/\)/,contains:[e.inherit(r,{className:"string"}),"self"]}]
},o=i,b=e.COMMENT("/\\*","\\*/",{contains:[e.C_BLOCK_COMMENT_MODE]}),E={
variants:[{className:"type",begin:e.UNDERSCORE_IDENT_RE},{begin:/\(/,end:/\)/,
contains:[]}]},d=E;return d.variants[1].contains=[E],E.variants[1].contains=[d],
{name:"Kotlin",aliases:["kt","kts"],keywords:n,
contains:[e.COMMENT("/\\*\\*","\\*/",{relevance:0,contains:[{className:"doctag",
begin:"@[A-Za-z]+"}]}),e.C_LINE_COMMENT_MODE,b,{className:"keyword",
begin:/\b(break|continue|return|this)\b/,starts:{contains:[{className:"symbol",
begin:/@\w+/}]}},a,l,c,{className:"function",beginKeywords:"fun",end:"[(]|$",
returnBegin:!0,excludeEnd:!0,keywords:n,relevance:5,contains:[{
begin:e.UNDERSCORE_IDENT_RE+"\\s*\\(",returnBegin:!0,relevance:0,
contains:[e.UNDERSCORE_TITLE_MODE]},{className:"type",begin:/</,end:/>/,
keywords:"reified",relevance:0},{className:"params",begin:/\(/,end:/\)/,
endsParent:!0,keywords:n,relevance:0,contains:[{begin:/:/,end:/[=,\/]/,
endsWithParent:!0,contains:[E,e.C_LINE_COMMENT_MODE,b],relevance:0
},e.C_LINE_COMMENT_MODE,b,l,c,r,e.C_NUMBER_MODE]},b]},{
begin:[/class|interface|trait/,/\s+/,e.UNDERSCORE_IDENT_RE],beginScope:{
3:"title.class"},keywords:"class interface trait",end:/[:\{(]|$/,excludeEnd:!0,
illegal:"extends implements",contains:[{
beginKeywords:"public protected internal private constructor"
},e.UNDERSCORE_TITLE_MODE,{className:"type",begin:/</,end:/>/,excludeBegin:!0,
excludeEnd:!0,relevance:0},{className:"type",begin:/[,:]\s*/,end:/[<\(,){\s]|$/,
excludeBegin:!0,returnEnd:!0},l,c]},r,{className:"meta",begin:"^#!/usr/bin/env",
end:"$",illegal:"\n"},o]}}})();export default hljsGrammar;
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
@@ -1,89 +0,0 @@
/*! `lua` grammar compiled for Highlight.js 11.11.1 */
var hljsGrammar = (function () {
'use strict';
/*
Language: Lua
Description: Lua is a powerful, efficient, lightweight, embeddable scripting language.
Author: Andrew Fedorov <dmmdrs@mail.ru>
Category: common, gaming, scripting
Website: https://www.lua.org
*/
function lua(hljs) {
const OPENING_LONG_BRACKET = '\\[=*\\[';
const CLOSING_LONG_BRACKET = '\\]=*\\]';
const LONG_BRACKETS = {
begin: OPENING_LONG_BRACKET,
end: CLOSING_LONG_BRACKET,
contains: [ 'self' ]
};
const COMMENTS = [
hljs.COMMENT('--(?!' + OPENING_LONG_BRACKET + ')', '$'),
hljs.COMMENT(
'--' + OPENING_LONG_BRACKET,
CLOSING_LONG_BRACKET,
{
contains: [ LONG_BRACKETS ],
relevance: 10
}
)
];
return {
name: 'Lua',
aliases: ['pluto'],
keywords: {
$pattern: hljs.UNDERSCORE_IDENT_RE,
literal: "true false nil",
keyword: "and break do else elseif end for goto if in local not or repeat return then until while",
built_in:
// Metatags and globals:
'_G _ENV _VERSION __index __newindex __mode __call __metatable __tostring __len '
+ '__gc __add __sub __mul __div __mod __pow __concat __unm __eq __lt __le assert '
// Standard methods and properties:
+ 'collectgarbage dofile error getfenv getmetatable ipairs load loadfile loadstring '
+ 'module next pairs pcall print rawequal rawget rawset require select setfenv '
+ 'setmetatable tonumber tostring type unpack xpcall arg self '
// Library methods and properties (one line per library):
+ 'coroutine resume yield status wrap create running debug getupvalue '
+ 'debug sethook getmetatable gethook setmetatable setlocal traceback setfenv getinfo setupvalue getlocal getregistry getfenv '
+ 'io lines write close flush open output type read stderr stdin input stdout popen tmpfile '
+ 'math log max acos huge ldexp pi cos tanh pow deg tan cosh sinh random randomseed frexp ceil floor rad abs sqrt modf asin min mod fmod log10 atan2 exp sin atan '
+ 'os exit setlocale date getenv difftime remove time clock tmpname rename execute package preload loadlib loaded loaders cpath config path seeall '
+ 'string sub upper len gfind rep find match char dump gmatch reverse byte format gsub lower '
+ 'table setn insert getn foreachi maxn foreach concat sort remove'
},
contains: COMMENTS.concat([
{
className: 'function',
beginKeywords: 'function',
end: '\\)',
contains: [
hljs.inherit(hljs.TITLE_MODE, { begin: '([_a-zA-Z]\\w*\\.)*([_a-zA-Z]\\w*:)?[_a-zA-Z]\\w*' }),
{
className: 'params',
begin: '\\(',
endsWithParent: true,
contains: COMMENTS
}
].concat(COMMENTS)
},
hljs.C_NUMBER_MODE,
hljs.APOS_STRING_MODE,
hljs.QUOTE_STRING_MODE,
{
className: 'string',
begin: OPENING_LONG_BRACKET,
end: CLOSING_LONG_BRACKET,
contains: [ LONG_BRACKETS ],
relevance: 5
}
])
};
}
return lua;
})();
;
export default hljsGrammar;
-14
View File
@@ -1,14 +0,0 @@
/*! `lua` grammar compiled for Highlight.js 11.11.1 */
var hljsGrammar=(()=>{"use strict";return e=>{
const t="\\[=*\\[",a="\\]=*\\]",n={begin:t,end:a,contains:["self"]
},r=[e.COMMENT("--(?!"+t+")","$"),e.COMMENT("--"+t,a,{contains:[n],relevance:10
})];return{name:"Lua",aliases:["pluto"],keywords:{
$pattern:e.UNDERSCORE_IDENT_RE,literal:"true false nil",
keyword:"and break do else elseif end for goto if in local not or repeat return then until while",
built_in:"_G _ENV _VERSION __index __newindex __mode __call __metatable __tostring __len __gc __add __sub __mul __div __mod __pow __concat __unm __eq __lt __le assert collectgarbage dofile error getfenv getmetatable ipairs load loadfile loadstring module next pairs pcall print rawequal rawget rawset require select setfenv setmetatable tonumber tostring type unpack xpcall arg self coroutine resume yield status wrap create running debug getupvalue debug sethook getmetatable gethook setmetatable setlocal traceback setfenv getinfo setupvalue getlocal getregistry getfenv io lines write close flush open output type read stderr stdin input stdout popen tmpfile math log max acos huge ldexp pi cos tanh pow deg tan cosh sinh random randomseed frexp ceil floor rad abs sqrt modf asin min mod fmod log10 atan2 exp sin atan os exit setlocale date getenv difftime remove time clock tmpname rename execute package preload loadlib loaded loaders cpath config path seeall string sub upper len gfind rep find match char dump gmatch reverse byte format gsub lower table setn insert getn foreachi maxn foreach concat sort remove"
},contains:r.concat([{className:"function",beginKeywords:"function",end:"\\)",
contains:[e.inherit(e.TITLE_MODE,{
begin:"([_a-zA-Z]\\w*\\.)*([_a-zA-Z]\\w*:)?[_a-zA-Z]\\w*"}),{className:"params",
begin:"\\(",endsWithParent:!0,contains:r}].concat(r)
},e.C_NUMBER_MODE,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,{className:"string",
begin:t,end:a,contains:[n],relevance:5}])}}})();export default hljsGrammar;
@@ -1,97 +0,0 @@
/*! `makefile` grammar compiled for Highlight.js 11.11.1 */
var hljsGrammar = (function () {
'use strict';
/*
Language: Makefile
Author: Ivan Sagalaev <maniac@softwaremaniacs.org>
Contributors: Joël Porquet <joel@porquet.org>
Website: https://www.gnu.org/software/make/manual/html_node/Introduction.html
Category: common, build-system
*/
function makefile(hljs) {
/* Variables: simple (eg $(var)) and special (eg $@) */
const VARIABLE = {
className: 'variable',
variants: [
{
begin: '\\$\\(' + hljs.UNDERSCORE_IDENT_RE + '\\)',
contains: [ hljs.BACKSLASH_ESCAPE ]
},
{ begin: /\$[@%<?\^\+\*]/ }
]
};
/* Quoted string with variables inside */
const QUOTE_STRING = {
className: 'string',
begin: /"/,
end: /"/,
contains: [
hljs.BACKSLASH_ESCAPE,
VARIABLE
]
};
/* Function: $(func arg,...) */
const FUNC = {
className: 'variable',
begin: /\$\([\w-]+\s/,
end: /\)/,
keywords: { built_in:
'subst patsubst strip findstring filter filter-out sort '
+ 'word wordlist firstword lastword dir notdir suffix basename '
+ 'addsuffix addprefix join wildcard realpath abspath error warning '
+ 'shell origin flavor foreach if or and call eval file value' },
contains: [
VARIABLE,
QUOTE_STRING // Added QUOTE_STRING as they can be a part of functions
]
};
/* Variable assignment */
const ASSIGNMENT = { begin: '^' + hljs.UNDERSCORE_IDENT_RE + '\\s*(?=[:+?]?=)' };
/* Meta targets (.PHONY) */
const META = {
className: 'meta',
begin: /^\.PHONY:/,
end: /$/,
keywords: {
$pattern: /[\.\w]+/,
keyword: '.PHONY'
}
};
/* Targets */
const TARGET = {
className: 'section',
begin: /^[^\s]+:/,
end: /$/,
contains: [ VARIABLE ]
};
return {
name: 'Makefile',
aliases: [
'mk',
'mak',
'make',
],
keywords: {
$pattern: /[\w-]+/,
keyword: 'define endef undefine ifdef ifndef ifeq ifneq else endif '
+ 'include -include sinclude override export unexport private vpath'
},
contains: [
hljs.HASH_COMMENT_MODE,
VARIABLE,
QUOTE_STRING,
FUNC,
ASSIGNMENT,
META,
TARGET
]
};
}
return makefile;
})();
;
export default hljsGrammar;
@@ -1,14 +0,0 @@
/*! `makefile` grammar compiled for Highlight.js 11.11.1 */
var hljsGrammar=(()=>{"use strict";return e=>{const a={className:"variable",
variants:[{begin:"\\$\\("+e.UNDERSCORE_IDENT_RE+"\\)",
contains:[e.BACKSLASH_ESCAPE]},{begin:/\$[@%<?\^\+\*]/}]},i={className:"string",
begin:/"/,end:/"/,contains:[e.BACKSLASH_ESCAPE,a]},n={className:"variable",
begin:/\$\([\w-]+\s/,end:/\)/,keywords:{
built_in:"subst patsubst strip findstring filter filter-out sort word wordlist firstword lastword dir notdir suffix basename addsuffix addprefix join wildcard realpath abspath error warning shell origin flavor foreach if or and call eval file value"
},contains:[a,i]},r={begin:"^"+e.UNDERSCORE_IDENT_RE+"\\s*(?=[:+?]?=)"},s={
className:"section",begin:/^[^\s]+:/,end:/$/,contains:[a]};return{
name:"Makefile",aliases:["mk","mak","make"],keywords:{$pattern:/[\w-]+/,
keyword:"define endef undefine ifdef ifndef ifeq ifneq else endif include -include sinclude override export unexport private vpath"
},contains:[e.HASH_COMMENT_MODE,a,i,n,r,{className:"meta",begin:/^\.PHONY:/,
end:/$/,keywords:{$pattern:/[\.\w]+/,keyword:".PHONY"}},s]}}})()
;export default hljsGrammar;
@@ -1,256 +0,0 @@
/*! `markdown` grammar compiled for Highlight.js 11.11.1 */
var hljsGrammar = (function () {
'use strict';
/*
Language: Markdown
Requires: xml.js
Author: John Crepezzi <john.crepezzi@gmail.com>
Website: https://daringfireball.net/projects/markdown/
Category: common, markup
*/
function markdown(hljs) {
const regex = hljs.regex;
const INLINE_HTML = {
begin: /<\/?[A-Za-z_]/,
end: '>',
subLanguage: 'xml',
relevance: 0
};
const HORIZONTAL_RULE = {
begin: '^[-\\*]{3,}',
end: '$'
};
const CODE = {
className: 'code',
variants: [
// TODO: fix to allow these to work with sublanguage also
{ begin: '(`{3,})[^`](.|\\n)*?\\1`*[ ]*' },
{ begin: '(~{3,})[^~](.|\\n)*?\\1~*[ ]*' },
// needed to allow markdown as a sublanguage to work
{
begin: '```',
end: '```+[ ]*$'
},
{
begin: '~~~',
end: '~~~+[ ]*$'
},
{ begin: '`.+?`' },
{
begin: '(?=^( {4}|\\t))',
// use contains to gobble up multiple lines to allow the block to be whatever size
// but only have a single open/close tag vs one per line
contains: [
{
begin: '^( {4}|\\t)',
end: '(\\n)$'
}
],
relevance: 0
}
]
};
const LIST = {
className: 'bullet',
begin: '^[ \t]*([*+-]|(\\d+\\.))(?=\\s+)',
end: '\\s+',
excludeEnd: true
};
const LINK_REFERENCE = {
begin: /^\[[^\n]+\]:/,
returnBegin: true,
contains: [
{
className: 'symbol',
begin: /\[/,
end: /\]/,
excludeBegin: true,
excludeEnd: true
},
{
className: 'link',
begin: /:\s*/,
end: /$/,
excludeBegin: true
}
]
};
const URL_SCHEME = /[A-Za-z][A-Za-z0-9+.-]*/;
const LINK = {
variants: [
// too much like nested array access in so many languages
// to have any real relevance
{
begin: /\[.+?\]\[.*?\]/,
relevance: 0
},
// popular internet URLs
{
begin: /\[.+?\]\(((data|javascript|mailto):|(?:http|ftp)s?:\/\/).*?\)/,
relevance: 2
},
{
begin: regex.concat(/\[.+?\]\(/, URL_SCHEME, /:\/\/.*?\)/),
relevance: 2
},
// relative urls
{
begin: /\[.+?\]\([./?&#].*?\)/,
relevance: 1
},
// whatever else, lower relevance (might not be a link at all)
{
begin: /\[.*?\]\(.*?\)/,
relevance: 0
}
],
returnBegin: true,
contains: [
{
// empty strings for alt or link text
match: /\[(?=\])/ },
{
className: 'string',
relevance: 0,
begin: '\\[',
end: '\\]',
excludeBegin: true,
returnEnd: true
},
{
className: 'link',
relevance: 0,
begin: '\\]\\(',
end: '\\)',
excludeBegin: true,
excludeEnd: true
},
{
className: 'symbol',
relevance: 0,
begin: '\\]\\[',
end: '\\]',
excludeBegin: true,
excludeEnd: true
}
]
};
const BOLD = {
className: 'strong',
contains: [], // defined later
variants: [
{
begin: /_{2}(?!\s)/,
end: /_{2}/
},
{
begin: /\*{2}(?!\s)/,
end: /\*{2}/
}
]
};
const ITALIC = {
className: 'emphasis',
contains: [], // defined later
variants: [
{
begin: /\*(?![*\s])/,
end: /\*/
},
{
begin: /_(?![_\s])/,
end: /_/,
relevance: 0
}
]
};
// 3 level deep nesting is not allowed because it would create confusion
// in cases like `***testing***` because where we don't know if the last
// `***` is starting a new bold/italic or finishing the last one
const BOLD_WITHOUT_ITALIC = hljs.inherit(BOLD, { contains: [] });
const ITALIC_WITHOUT_BOLD = hljs.inherit(ITALIC, { contains: [] });
BOLD.contains.push(ITALIC_WITHOUT_BOLD);
ITALIC.contains.push(BOLD_WITHOUT_ITALIC);
let CONTAINABLE = [
INLINE_HTML,
LINK
];
[
BOLD,
ITALIC,
BOLD_WITHOUT_ITALIC,
ITALIC_WITHOUT_BOLD
].forEach(m => {
m.contains = m.contains.concat(CONTAINABLE);
});
CONTAINABLE = CONTAINABLE.concat(BOLD, ITALIC);
const HEADER = {
className: 'section',
variants: [
{
begin: '^#{1,6}',
end: '$',
contains: CONTAINABLE
},
{
begin: '(?=^.+?\\n[=-]{2,}$)',
contains: [
{ begin: '^[=-]*$' },
{
begin: '^',
end: "\\n",
contains: CONTAINABLE
}
]
}
]
};
const BLOCKQUOTE = {
className: 'quote',
begin: '^>\\s+',
contains: CONTAINABLE,
end: '$'
};
const ENTITY = {
//https://spec.commonmark.org/0.31.2/#entity-references
scope: 'literal',
match: /&([a-zA-Z0-9]+|#[0-9]{1,7}|#[Xx][0-9a-fA-F]{1,6});/
};
return {
name: 'Markdown',
aliases: [
'md',
'mkdown',
'mkd'
],
contains: [
HEADER,
INLINE_HTML,
LIST,
BOLD,
ITALIC,
BLOCKQUOTE,
CODE,
HORIZONTAL_RULE,
LINK,
LINK_REFERENCE,
ENTITY
]
};
}
return markdown;
})();
;
export default hljsGrammar;
@@ -1,32 +0,0 @@
/*! `markdown` grammar compiled for Highlight.js 11.11.1 */
var hljsGrammar=(()=>{"use strict";return e=>{const n={begin:/<\/?[A-Za-z_]/,
end:">",subLanguage:"xml",relevance:0},a={variants:[{begin:/\[.+?\]\[.*?\]/,
relevance:0},{
begin:/\[.+?\]\(((data|javascript|mailto):|(?:http|ftp)s?:\/\/).*?\)/,
relevance:2},{
begin:e.regex.concat(/\[.+?\]\(/,/[A-Za-z][A-Za-z0-9+.-]*/,/:\/\/.*?\)/),
relevance:2},{begin:/\[.+?\]\([./?&#].*?\)/,relevance:1},{
begin:/\[.*?\]\(.*?\)/,relevance:0}],returnBegin:!0,contains:[{match:/\[(?=\])/
},{className:"string",relevance:0,begin:"\\[",end:"\\]",excludeBegin:!0,
returnEnd:!0},{className:"link",relevance:0,begin:"\\]\\(",end:"\\)",
excludeBegin:!0,excludeEnd:!0},{className:"symbol",relevance:0,begin:"\\]\\[",
end:"\\]",excludeBegin:!0,excludeEnd:!0}]},i={className:"strong",contains:[],
variants:[{begin:/_{2}(?!\s)/,end:/_{2}/},{begin:/\*{2}(?!\s)/,end:/\*{2}/}]
},s={className:"emphasis",contains:[],variants:[{begin:/\*(?![*\s])/,end:/\*/},{
begin:/_(?![_\s])/,end:/_/,relevance:0}]},c=e.inherit(i,{contains:[]
}),t=e.inherit(s,{contains:[]});i.contains.push(t),s.contains.push(c)
;let l=[n,a];return[i,s,c,t].forEach((e=>{e.contains=e.contains.concat(l)
})),l=l.concat(i,s),{name:"Markdown",aliases:["md","mkdown","mkd"],contains:[{
className:"section",variants:[{begin:"^#{1,6}",end:"$",contains:l},{
begin:"(?=^.+?\\n[=-]{2,}$)",contains:[{begin:"^[=-]*$"},{begin:"^",end:"\\n",
contains:l}]}]},n,{className:"bullet",begin:"^[ \t]*([*+-]|(\\d+\\.))(?=\\s+)",
end:"\\s+",excludeEnd:!0},i,s,{className:"quote",begin:"^>\\s+",contains:l,
end:"$"},{className:"code",variants:[{begin:"(`{3,})[^`](.|\\n)*?\\1`*[ ]*"},{
begin:"(~{3,})[^~](.|\\n)*?\\1~*[ ]*"},{begin:"```",end:"```+[ ]*$"},{
begin:"~~~",end:"~~~+[ ]*$"},{begin:"`.+?`"},{begin:"(?=^( {4}|\\t))",
contains:[{begin:"^( {4}|\\t)",end:"(\\n)$"}],relevance:0}]},{
begin:"^[-\\*]{3,}",end:"$"},a,{begin:/^\[[^\n]+\]:/,returnBegin:!0,contains:[{
className:"symbol",begin:/\[/,end:/\]/,excludeBegin:!0,excludeEnd:!0},{
className:"link",begin:/:\s*/,end:/$/,excludeBegin:!0}]},{scope:"literal",
match:/&([a-zA-Z0-9]+|#[0-9]{1,7}|#[Xx][0-9a-fA-F]{1,6});/}]}}})()
;export default hljsGrammar;
@@ -1,261 +0,0 @@
/*! `objectivec` grammar compiled for Highlight.js 11.11.1 */
var hljsGrammar = (function () {
'use strict';
/*
Language: Objective-C
Author: Valerii Hiora <valerii.hiora@gmail.com>
Contributors: Angel G. Olloqui <angelgarcia.mail@gmail.com>, Matt Diephouse <matt@diephouse.com>, Andrew Farmer <ahfarmer@gmail.com>, Minh Nguyễn <mxn@1ec5.org>
Website: https://developer.apple.com/documentation/objectivec
Category: common
*/
function objectivec(hljs) {
const API_CLASS = {
className: 'built_in',
begin: '\\b(AV|CA|CF|CG|CI|CL|CM|CN|CT|MK|MP|MTK|MTL|NS|SCN|SK|UI|WK|XC)\\w+'
};
const IDENTIFIER_RE = /[a-zA-Z@][a-zA-Z0-9_]*/;
const TYPES = [
"int",
"float",
"char",
"unsigned",
"signed",
"short",
"long",
"double",
"wchar_t",
"unichar",
"void",
"bool",
"BOOL",
"id|0",
"_Bool"
];
const KWS = [
"while",
"export",
"sizeof",
"typedef",
"const",
"struct",
"for",
"union",
"volatile",
"static",
"mutable",
"if",
"do",
"return",
"goto",
"enum",
"else",
"break",
"extern",
"asm",
"case",
"default",
"register",
"explicit",
"typename",
"switch",
"continue",
"inline",
"readonly",
"assign",
"readwrite",
"self",
"@synchronized",
"id",
"typeof",
"nonatomic",
"IBOutlet",
"IBAction",
"strong",
"weak",
"copy",
"in",
"out",
"inout",
"bycopy",
"byref",
"oneway",
"__strong",
"__weak",
"__block",
"__autoreleasing",
"@private",
"@protected",
"@public",
"@try",
"@property",
"@end",
"@throw",
"@catch",
"@finally",
"@autoreleasepool",
"@synthesize",
"@dynamic",
"@selector",
"@optional",
"@required",
"@encode",
"@package",
"@import",
"@defs",
"@compatibility_alias",
"__bridge",
"__bridge_transfer",
"__bridge_retained",
"__bridge_retain",
"__covariant",
"__contravariant",
"__kindof",
"_Nonnull",
"_Nullable",
"_Null_unspecified",
"__FUNCTION__",
"__PRETTY_FUNCTION__",
"__attribute__",
"getter",
"setter",
"retain",
"unsafe_unretained",
"nonnull",
"nullable",
"null_unspecified",
"null_resettable",
"class",
"instancetype",
"NS_DESIGNATED_INITIALIZER",
"NS_UNAVAILABLE",
"NS_REQUIRES_SUPER",
"NS_RETURNS_INNER_POINTER",
"NS_INLINE",
"NS_AVAILABLE",
"NS_DEPRECATED",
"NS_ENUM",
"NS_OPTIONS",
"NS_SWIFT_UNAVAILABLE",
"NS_ASSUME_NONNULL_BEGIN",
"NS_ASSUME_NONNULL_END",
"NS_REFINED_FOR_SWIFT",
"NS_SWIFT_NAME",
"NS_SWIFT_NOTHROW",
"NS_DURING",
"NS_HANDLER",
"NS_ENDHANDLER",
"NS_VALUERETURN",
"NS_VOIDRETURN"
];
const LITERALS = [
"false",
"true",
"FALSE",
"TRUE",
"nil",
"YES",
"NO",
"NULL"
];
const BUILT_INS = [
"dispatch_once_t",
"dispatch_queue_t",
"dispatch_sync",
"dispatch_async",
"dispatch_once"
];
const KEYWORDS = {
"variable.language": [
"this",
"super"
],
$pattern: IDENTIFIER_RE,
keyword: KWS,
literal: LITERALS,
built_in: BUILT_INS,
type: TYPES
};
const CLASS_KEYWORDS = {
$pattern: IDENTIFIER_RE,
keyword: [
"@interface",
"@class",
"@protocol",
"@implementation"
]
};
return {
name: 'Objective-C',
aliases: [
'mm',
'objc',
'obj-c',
'obj-c++',
'objective-c++'
],
keywords: KEYWORDS,
illegal: '</',
contains: [
API_CLASS,
hljs.C_LINE_COMMENT_MODE,
hljs.C_BLOCK_COMMENT_MODE,
hljs.C_NUMBER_MODE,
hljs.QUOTE_STRING_MODE,
hljs.APOS_STRING_MODE,
{
className: 'string',
variants: [
{
begin: '@"',
end: '"',
illegal: '\\n',
contains: [ hljs.BACKSLASH_ESCAPE ]
}
]
},
{
className: 'meta',
begin: /#\s*[a-z]+\b/,
end: /$/,
keywords: { keyword:
'if else elif endif define undef warning error line '
+ 'pragma ifdef ifndef include' },
contains: [
{
begin: /\\\n/,
relevance: 0
},
hljs.inherit(hljs.QUOTE_STRING_MODE, { className: 'string' }),
{
className: 'string',
begin: /<.*?>/,
end: /$/,
illegal: '\\n'
},
hljs.C_LINE_COMMENT_MODE,
hljs.C_BLOCK_COMMENT_MODE
]
},
{
className: 'class',
begin: '(' + CLASS_KEYWORDS.keyword.join('|') + ')\\b',
end: /(\{|$)/,
excludeEnd: true,
keywords: CLASS_KEYWORDS,
contains: [ hljs.UNDERSCORE_TITLE_MODE ]
},
{
begin: '\\.' + hljs.UNDERSCORE_IDENT_RE,
relevance: 0
}
]
};
}
return objectivec;
})();
;
export default hljsGrammar;

Some files were not shown because too many files have changed in this diff Show More