first commit

This commit is contained in:
Reid 2023-07-18 22:22:52 -07:00
commit 5302ecc6cc
43 changed files with 2530 additions and 0 deletions

48
.eslintrc Normal file
View file

@ -0,0 +1,48 @@
{
"parser": "@typescript-eslint/parser",
"parserOptions": {
"jsx": true,
"useJSXTextNode": true,
"ecmaVersion": 2018,
"sourceType": "module",
"project": "./tsconfig.json"
},
"ignorePatterns": [
"/out"
],
"plugins": [
"@typescript-eslint",
"roblox-ts"
],
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:roblox-ts/recommended"
],
"rules": {
"@typescript-eslint/ban-types": "error",
"@typescript-eslint/explicit-function-return-type": "warn",
"@typescript-eslint/explicit-module-boundary-types": "warn",
"@typescript-eslint/no-array-constructor": "error",
"@typescript-eslint/no-empty-function": "error",
"@typescript-eslint/no-empty-interface": "error",
"@typescript-eslint/no-namespace": "error",
"@typescript-eslint/no-non-null-assertion": "warn",
"@typescript-eslint/no-unused-vars": [
"warn",
{
"varsIgnorePattern": "^_",
"argsIgnorePattern": "^_"
}
],
"@typescript-eslint/no-var-requires": "error",
"@typescript-eslint/semi": [
"error",
"never"
],
"@typescript-eslint/comma-dangle": [
"error",
"never"
]
}
}

12
.gitignore vendored Normal file
View file

@ -0,0 +1,12 @@
# builds
/out
build.rbxl
*.tsbuildinfo
# deps
/node_modules
/include
# mac users.. stop making these files or im gonna get mad 😡😡😡
.DS_Store
/__MACOSX

7
.vscode/extensions.json vendored Normal file
View file

@ -0,0 +1,7 @@
{
"recommendations": [
"roblox-ts.vscode-roblox-ts",
"dbaeumer.vscode-eslint",
"evaera.vscode-rojo"
]
}

14
.vscode/settings.json vendored Normal file
View file

@ -0,0 +1,14 @@
{
"typescript.tsdk": "node_modules/typescript/lib",
"files.eol": "\n",
"[typescript]": {
"editor.defaultFormatter": "dbaeumer.vscode-eslint",
"editor.formatOnSave": true
},
"[typescriptreact]": {
"editor.defaultFormatter": "dbaeumer.vscode-eslint",
"editor.formatOnSave": true
},
"eslint.run": "onType",
"eslint.format.enable": true
}

7
aftman.toml Normal file
View file

@ -0,0 +1,7 @@
# This file lists tools managed by Aftman, a cross-platform toolchain manager.
# For more information, see https://github.com/LPGhatguy/aftman
# To add a new tool, add an entry to this table.
[tools]
rojo = "rojo-rbx/rojo@7.3.0"
run-in-roblox = "rojo-rbx/run-in-roblox@0.3.0"

65
default.project.json Normal file
View file

@ -0,0 +1,65 @@
{
"name": "roblox-ts-game",
"globIgnorePaths": [
"**/package.json",
"**/tsconfig.json"
],
"tree": {
"$className": "DataModel",
"ServerScriptService": {
"$className": "ServerScriptService",
"goopler": {
"$path": "out/src/ServerScriptService"
}
},
"ReplicatedStorage": {
"$className": "ReplicatedStorage",
"rbxts_include": {
"$path": "include",
"node_modules": {
"$className": "Folder",
"@rbxts": {
"$path": "node_modules/@rbxts"
}
}
},
"goopler": {
"$path": "out/src/ReplicatedStorage"
},
"tests": {
"$path": "out/tests"
}
},
"StarterPlayer": {
"$className": "StarterPlayer",
"StarterPlayerScripts": {
"$className": "StarterPlayerScripts",
"goopler": {
"$path": "out/src/StarterPlayer/StarterPlayerScripts"
}
},
"StarterCharacterScripts": {
"$className": "StarterCharacterScripts",
"$path": "out/src/StarterPlayer/StarterCharacterScripts"
}
},
"Workspace": {
"$className": "Workspace",
"$properties": {
"FilteringEnabled": true
}
},
"HttpService": {
"$className": "HttpService",
"$properties": {
"HttpEnabled": true
}
},
"SoundService": {
"$className": "SoundService",
"$properties": {
"RespectFilteringEnabled": true
}
}
}
}

34
package.json Normal file
View file

@ -0,0 +1,34 @@
{
"name": "goopler",
"description": "An in-dev game that I plan to make a shooter game out of.",
"keywords": ["roblox", "roblox-ts", "rojo", "matter", "roblox-matter", "ecs"],
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"author": {
"name": "reidlab"
},
"scripts": {
"build": "rbxtsc --rojo default.project.json --verbose && rojo build --output build.rbxl default.project.json",
"watch": "rbxtsc -w --rojo default.project.json --verbose",
"lint": "eslint src tests --max-warnings 0",
"serve": "rojo serve default.project.json",
"test": "yarn run build && run-in-roblox --place build.rbxl --script out/tests/runners/run.server.lua"
},
"devDependencies": {
"@rbxts/compiler-types": "^2.0.4-types.1",
"@rbxts/types": "^1.0.689",
"@typescript-eslint/eslint-plugin": "^5.59.11",
"@typescript-eslint/parser": "^5.59.11",
"eslint": "^8.42.0",
"eslint-plugin-roblox-ts": "^0.0.35",
"typescript": "^5.1.3"
},
"dependencies": {
"@rbxts/matter": "^0.6.2-ts.6",
"@rbxts/plasma": "^0.4.1-ts.1",
"@rbxts/rewire": "^0.3.0",
"@rbxts/services": "^1.5.1",
"@rbxts/testez": "^0.4.2-ts.0"
}
}

27
readme.md Normal file
View file

@ -0,0 +1,27 @@
# Goopler
An in-dev game that I plan to make a shooter game out of.
---
> For goop we live, for goop we die.
— reidlab
# Hacks
* I get a strange error about private identifiers in [`./src/ReplicatedStorage/ecs/state.ts:7`](./src/ReplicatedStorage/ecs/state.ts)
* I decided to omit the "TS" folder from [`./default.project.json:40`](./default.project.json) due to the script override not working in Health.server.ts in StarterCharacterScripts.
# Todo
### High priority
* Input mapping
#### Medium priority
* Sprinting (post-input-mapping)
* Add tests
##### Low priority
* Add the bound tags in [`./src/ReplicatedStorage/ecs/boundTags.ts`](./src/ReplicatedStorage/ecs/boundTags.ts)
# Fixes
### High Priority
* Currently, when resetting, sometimes your health goes back up. This is due to the reconciliation of health. Simply put, your health is not being set to zero inside of our entity component system, due to us not having the reset event currently like that. See it here: [StarterGui.SetCore](https://create.roblox.com/docs/reference/engine/classes/StarterGui#SetCore) It uses BindableEvents and stuff idk
#### Medium priority
##### Low priority

View file

@ -0,0 +1,8 @@
import { Test } from "./components"
/**
* A map of tags to their bound components.
*/
export const tags = new ReadonlyMap([
["Example", Test]
])

View file

@ -0,0 +1,9 @@
import { Transform } from "./types"
/**
* The default value created when no data is provided to a {@link Transform}
* component.
*/
export const transform: Transform = {
cframe: CFrame.identity
}

View file

@ -0,0 +1,64 @@
import { Component, component } from "@rbxts/matter"
import { transform } from "./defaults"
import type {
Model as ModelComponent,
Transform as TransformComponent,
Health as HealthComponent,
Damage as DamageComponent,
PlayerCharacter as PlayerCharacterComponent,
Lifetime as LifetimeComponent,
Input as InputComponent
} from "./types"
export type GooplerComponentType =
| ModelComponent
| TransformComponent
| HealthComponent
| DamageComponent
| PlayerCharacterComponent
| LifetimeComponent
| InputComponent
export type GooplerComponent = Component<GooplerComponentType>
/**
* The {@link ModelComponent | Model} component constructor.
*/
export const Model = component<ModelComponent>("Model")
/**
* The {@link TransformComponent | Transform} component constructor.
*/
export const Transform = component<TransformComponent>("Transform", transform)
/**
* The {@link HealthComponent | Health} component constructor.
*/
export const Health = component<HealthComponent>("Health")
/**
* The {@link DamageComponent | Damage} component constructor.
*/
export const Damage = component<DamageComponent>("Damage")
/**
* The {@link PlayerCharacterComponent | PlayerCharacter} component constructor.
*/
export const PlayerCharacter = component<PlayerCharacterComponent>("PlayerCharacter")
/**
* The {@link LifetimeComponent | Lifetime} component constructor.
*/
export const Lifetime = component<LifetimeComponent>("Lifetime")
/**
* The {@link InputComponent | Input} component constructor.
*/
export const Input = component<InputComponent>("Input")
/**
* This is a test component constructor.
*
* It shouldn't be used and should be removed at some point.
*/
export const Test = component("Test")

View file

@ -0,0 +1,72 @@
/**
* The Model component.
*
* Provides a reference to the {@link PVInstance} that represents the attached
* entity.
*/
export interface Model {
model?: PVInstance
}
/**
* The Transform component.
*
* Provides a reference {@link CFrame} that represents the world transform of
* the attached entity.
*/
export interface Transform {
cframe: CFrame,
_doNotReconcile?: true
}
/**
* The Health component.
*
* Holds health information including health and regeneration.
* Regen is health restored per second.
*/
export interface Health {
health: number,
maxHealth: number,
regeneration: number
}
/**
* The Damage component.
*
* Holds health-reduction information.
*/
export interface Damage {
damage: number
}
/**
* The PlayerCharacter component.
*
* Holds the Humanoid and Player.
*/
export interface PlayerCharacter {
humanoid: Humanoid,
player: Player
}
/**
* The Lifetime component.
*
* Holds the time it was spawned at, how long it should last, and the time elapsed.
*/
export interface Lifetime {
spawnedAt: number,
length: number,
elapsed: number
}
/**
* The input component.
*
* Holds @todo
*/
export interface Input {
test: number
}

View file

@ -0,0 +1,89 @@
import { World, AnyEntity, Loop, Debugger } from "@rbxts/matter"
import Plasma from "@rbxts/plasma"
import { Players, ReplicatedStorage, RunService, UserInputService } from "@rbxts/services"
import { Host } from "ReplicatedStorage/hosts"
import { tags } from "./boundTags"
import { Model } from "./components"
import { start as startReplication, stop as stopReplication } from "./replication"
import { State } from "./state"
import { start as startSystems, stop as stopSystems } from "./systems"
import { start as startTags, stop as stopTags } from "./tags"
const MAX_DISPLAY_ORDER = 2147483647
function authorize(player: Player): boolean {
return RunService.IsStudio() || game.CreatorId === player.UserId
}
let connections:
| {
[index: string]: RBXScriptConnection
}
| undefined
export function start(host: Host): [World, State] {
if (connections) throw "ECS already running."
const state: State = new State()
const world = new World()
const debug = new Debugger(Plasma)
debug.authorize = authorize
debug.findInstanceFromEntity = (id: AnyEntity): Instance | undefined => {
if (!world.contains(id)) return
const model = world.get(id, Model)
return model?.model
}
const loop = new Loop(world, state, debug.getWidgets())
startSystems(host, loop, debug)
debug.autoInitialize(loop)
connections = loop.begin({
default: RunService.Heartbeat,
Stepped: RunService.Stepped
})
if (host === Host.All || host === Host.Server) {
startTags(world, tags)
}
if (host === Host.All || host === Host.Client) {
startReplication(world, state)
const serverDebugger = ReplicatedStorage.FindFirstChild("MatterDebugger")
if (serverDebugger && serverDebugger.IsA("ScreenGui")) {
serverDebugger.DisplayOrder = MAX_DISPLAY_ORDER
}
const clientDebugger = Players.LocalPlayer.FindFirstChild("MatterDebugger")
if (clientDebugger && clientDebugger.IsA("ScreenGui")) {
clientDebugger.DisplayOrder = MAX_DISPLAY_ORDER
}
UserInputService.InputBegan.Connect((input) => {
if (input.KeyCode === Enum.KeyCode.F4 && authorize(Players.LocalPlayer)) {
debug.toggle()
state.debugEnabled = debug.enabled
}
})
}
return [world, state]
}
/**
* Stops the ECS.
*/
export function stop(): void {
if (!connections) return
for (const [_, connection] of pairs(connections)) {
connection.Disconnect()
}
connections = undefined
stopTags()
stopReplication()
stopSystems()
ReplicatedStorage.FindFirstChild("MatterDebuggerRemote")?.Destroy()
}

View file

@ -0,0 +1,104 @@
import { AnyEntity, World } from "@rbxts/matter"
import { waitForEvent } from "ReplicatedStorage/remotes"
import * as Components from "./components"
import { State } from "./state"
type ComponentNames = keyof typeof Components
type ComponentConstructors = (typeof Components)[ComponentNames]
const DEBUG_SPAWN = "Spawn %ds%d with %s"
const DEBUG_DESPAWN = "Despawn %ds%d"
const DEBUG_MODIFY = "Modify %ds%d adding %s, removing %s"
let connection: RBXScriptConnection | undefined
/**
* Starts the replication receiver.
*
* @param world - The world to replicate components in
* @param state - The global state for the ECS
*/
export function start(world: World, state: State): void {
if (connection) return
function debugPrint(message: string, args: () => (string | number)[]): void {
if (state.debugEnabled) {
print("ECS Replication>", string.format(message, ...args()))
}
}
const replicationEvent = waitForEvent("EcsReplication")
const serverToClientEntity = new Map<string, AnyEntity>()
connection = replicationEvent.OnClientEvent.Connect(
(entities: Map<string, Map<ComponentNames, { data?: Components.GooplerComponentType }>>) => {
for (const [serverId, componentMap] of entities) {
const clientId = serverToClientEntity.get(serverId)
if (clientId !== undefined && next(componentMap)[0] === undefined) {
world.despawn(clientId)
serverToClientEntity.delete(serverId)
debugPrint(DEBUG_DESPAWN, () => [clientId, serverId])
continue
}
const componentsToInsert: Components.GooplerComponent[] = []
const componentsToRemove: ComponentConstructors[] = []
const insertNames: ComponentNames[] = []
const removeNames: ComponentNames[] = []
for (const [name, container] of componentMap) {
const component = Components[name]
if (container.data) {
componentsToInsert.push(
// The type of component above is an intersection of all possible
// component types since it can't know which specific component is
// associated with the name. Therefore here, we must cast to an
// intersection so that the data can be used.
//
// This is okay because the data must be associated with the name
// it was created with, but the type checker can't verify this for
// us. To solve this the type must somehow be associated with the
// name in the type system. For now, this cast works fine.
component(container.data as UnionToIntersection<Components.GooplerComponentType>)
)
insertNames.push(name)
} else {
componentsToRemove.push(component)
removeNames.push(name)
}
}
if (clientId === undefined) {
const clientId = world.spawn(...componentsToInsert)
serverToClientEntity.set(serverId, clientId)
debugPrint(DEBUG_SPAWN, () => [clientId, serverId, insertNames.join(",")])
} else {
if (componentsToInsert.size() > 0) {
world.insert(clientId, ...componentsToInsert)
}
if (componentsToRemove.size() > 0) {
world.remove(clientId, ...componentsToRemove)
}
debugPrint(DEBUG_MODIFY, () => [
clientId,
serverId,
insertNames.size() > 0 ? insertNames.join(", ") : "nothing",
removeNames.size() > 0 ? removeNames.join(", ") : "nothing"
])
}
}
}
)
}
/**
* Stops receiving replication.
*/
export function stop(): void {
if (!connection) return
connection.Disconnect()
connection = undefined
}

View file

@ -0,0 +1,8 @@
/**
* The global ECS state.
*/
export class State {
[index: string]: unknown,
// eslint-disable-next-line roblox-ts/no-private-identifier
debugEnabled = false
}

View file

@ -0,0 +1,8 @@
/**
* A test system that does nothing.
*/
function test(): void {
// A test system.
}
export = test

View file

@ -0,0 +1,108 @@
import { AnySystem, Debugger, Loop } from "@rbxts/matter"
import { Context, HotReloader } from "@rbxts/rewire"
import { ServerScriptService } from "@rbxts/services"
import { Host } from "ReplicatedStorage/hosts"
const ERROR_CONTAINER = "%s container not found"
const shared = script.FindFirstChild("shared")
const client = script.FindFirstChild("client")
const server = ServerScriptService.FindFirstChild("goopler")
?.FindFirstChild("ecs")
?.FindFirstChild("systems")
?.FindFirstChild("server")
let firstRunSystems: AnySystem[] | undefined = []
let hotReloader: HotReloader | undefined
/**
* Starts the system loader.
*
* Loads systems for the specified container into the provided loop and
* debugger. Systems are hot reloaded as they are changed.
*
* @param container - The container to load
* @param loop - The ECS loop to load systems into
* @param debug - The debugger to load systems into
*
* @throws "[container] container not found"
* This is thrown when a container necessary for the provided host doesn't
* exist.
*/
export function start<T extends unknown[]>(container: Host, loop: Loop<T>, debug: Debugger): void {
if (!firstRunSystems) return
const containers: Instance[] = []
if (!shared) throw string.format(ERROR_CONTAINER, "Shared")
containers.push(shared)
if (container === Host.All || container === Host.Client) {
if (!client) throw string.format(ERROR_CONTAINER, "Client")
containers.push(client)
}
if (container === Host.All || container === Host.Server) {
if (!server) throw string.format(ERROR_CONTAINER, "Server")
containers.push(server)
}
const systemsByModule: Map<ModuleScript, AnySystem> = new Map()
function load(module: ModuleScript, context: Context): void {
if (
module.Name.match("%.spec$")[0] !== undefined ||
module.Name.match("%.dev$")[0] !== undefined
)
return
const original = context.originalModule
const previous = systemsByModule.get(original)
const [ok, required] = pcall(require, module)
if (!ok) {
warn("Error when hot-reloading system", module.Name, required)
return
}
// Here we don't know that this is necessarily a system, but we let matter
// handle this at runtime.
const system = required as AnySystem
if (firstRunSystems) {
firstRunSystems.push(system)
} else if (previous) {
loop.replaceSystem(previous, system)
debug.replaceSystem(previous, system)
} else {
loop.scheduleSystem(system)
}
systemsByModule.set(original, system)
}
function unload(_: ModuleScript, context: Context): void {
if (context.isReloading) return
const original = context.originalModule
const previous = systemsByModule.get(original)
if (previous) {
loop.evictSystem(previous)
systemsByModule.delete(original)
}
}
hotReloader = new HotReloader()
for (const container of containers) {
hotReloader.scan(container, load, unload)
}
loop.scheduleSystems(firstRunSystems)
firstRunSystems = undefined
}
/**
* Stops loading systems.
*/
export function stop(): void {
if (firstRunSystems) return
firstRunSystems = []
hotReloader?.destroy()
}

View file

@ -0,0 +1,19 @@
import { World, useDeltaTime } from "@rbxts/matter"
import { Lifetime } from "ReplicatedStorage/ecs/components"
/**
* @todo
*/
function updateIdAttribute(world: World): void {
for (const [id, lifetime] of world.query(Lifetime)) {
const newLifetime = lifetime.patch({ elapsed: lifetime.elapsed + useDeltaTime() })
if (os.clock() > lifetime.spawnedAt + lifetime.length) {
world.despawn(id)
} else {
world.insert(id, newLifetime)
}
}
}
export = updateIdAttribute

View file

@ -0,0 +1,25 @@
import { DebugWidgets, World } from "@rbxts/matter"
import { Stats } from "@rbxts/services"
const startInstanceCount = Stats.InstanceCount
const startMemory = Stats.GetTotalMemoryUsageMb()
const startTime = os.clock()
function trackMemory(world: World, state: object, ui: DebugWidgets): void {
const currentInstanceCount = Stats.InstanceCount
const currentMemory = Stats.GetTotalMemoryUsageMb()
ui.window("Memory Stats", () => {
ui.label(`Instances: ${currentInstanceCount}`)
ui.label(`Gained Instances: ${currentInstanceCount - startInstanceCount}`)
ui.label(`Memory: ${string.format("%.1f", currentMemory)}`)
ui.label(`Gained Memory: ${string.format("%.1f", currentMemory - startMemory)}`)
ui.label(`Time: ${string.format("%.1f", os.clock() - startTime)}`)
})
}
export = trackMemory

View file

@ -0,0 +1,16 @@
import { World } from "@rbxts/matter"
import { Model } from "ReplicatedStorage/ecs/components"
import { getIdAttribute } from "ReplicatedStorage/idAttribute"
/**
* A system that updates the ID of {@link Model | Models}.
*
* @param world - The {@link World} the system operates on
*/
function updateIdAttribute(world: World): void {
for (const [id, record] of world.queryChanged(Model)) {
record.new?.model?.SetAttribute(getIdAttribute(), id)
}
}
export = updateIdAttribute

View file

@ -0,0 +1,81 @@
import { AnyEntity, Component, World } from "@rbxts/matter"
import { CollectionService } from "@rbxts/services"
import { getIdAttribute } from "ReplicatedStorage/idAttribute"
import { Model, Transform } from "./components"
export type ComponentConstructor<T extends object> = () => Component<T>
const connections: RBXScriptConnection[] = []
/**
* Starts spawning bound tags.
*
* @param world - The world to spawn components in
* @param bound - A map of bound tags
*/
export function start(
world: World,
bound: ReadonlyMap<string, ComponentConstructor<object>>
): void {
function spawnBound<T extends object>(
instance: Instance,
component: ComponentConstructor<T>
): void {
let primaryPart: BasePart
if (instance.IsA("Model")) {
if (instance.PrimaryPart) {
primaryPart = instance.PrimaryPart
} else {
warn("Attempted to tag a model that has no primary part:", instance)
return
}
} else if (instance.IsA("BasePart")) {
primaryPart = instance
} else {
warn("Attempted to tag an instance that is not a Model or BasePart:", instance)
return
}
const id = world.spawn(
component(),
Model({
model: instance
}),
Transform({
cframe: primaryPart.CFrame
})
)
instance.SetAttribute(getIdAttribute(), id)
}
for (const [tag, component] of bound) {
for (const instance of CollectionService.GetTagged(tag)) {
spawnBound(instance, component)
}
connections.push(
CollectionService.GetInstanceAddedSignal(tag).Connect((instance: Instance): void => {
spawnBound(instance, component)
})
)
connections.push(
CollectionService.GetInstanceRemovedSignal(tag).Connect((instance: Instance): void => {
const id = instance.GetAttribute(getIdAttribute())
if (typeIs(id, "number")) {
world.despawn(id as AnyEntity)
}
})
)
}
}
/**
* Stops spawning bound tags.
*/
export function stop(): void {
for (const connection of connections) {
connection.Disconnect()
}
connections.clear()
}

View file

@ -0,0 +1,24 @@
/**
* Represents a particular host configuration.
*/
export enum Host {
/**
* Represents properties of no particular host.
*/
None,
/**
* Represents properties of the client.
*/
Client,
/**
* Represents properties of the server.
*/
Server,
/**
* Represents properties of all hosts.
*/
All
}

View file

@ -0,0 +1,47 @@
import { Host } from "ReplicatedStorage/hosts"
/**
* A string that represents the default ID attribute when the environment is
* not client or server.
*/
export const unknownIdAttribute = "unknownEntityId"
/**
* A string that represents the ID attribute when the environment is the server.
*/
export const serverIdAttribute = "serverEntityId"
/**
* A string that represents the ID attribute when the environment is the client.
*/
export const clientIdAttribute = "clientEntityId"
let idAttribute = unknownIdAttribute
/**
* Gets a string that represents the current ID attribute being used. This value
* defaults to {@link unknownIdAttribute}.
*
* @return the ID attribute
*/
export function getIdAttribute(): string {
return idAttribute
}
/**
* Sets the `idAttribute` variable based on the provided environment.
*
* @param environment - The environment to set the ID attribute for
*/
export function setEnvironment(environment: Host): void {
switch (environment) {
case Host.Server:
idAttribute = serverIdAttribute
break
case Host.Client:
idAttribute = clientIdAttribute
break
default:
idAttribute = unknownIdAttribute
}
}

View file

@ -0,0 +1,196 @@
const ERROR_MISSING = "%s '%s' was requested, but no such %s exists."
const ERROR_MISSING_EVENT = ERROR_MISSING.format("Event", "%s", "remote event")
const ERROR_MISSING_FUNCTION = ERROR_MISSING.format("Function", "%s", "remote function")
const ERROR_INVALID = "%s '%s' was requested, but was not a %s."
const ERROR_INVALID_EVENT = ERROR_INVALID.format("Event", "%s", "remote event")
const ERROR_INVALID_FUNCTION = ERROR_INVALID.format("Function", "%s", "remote function")
const events = new Map<string, RemoteEvent>()
const functions = new Map<string, RemoteFunction>()
/**
* Gets a remote event by name. If the event doesn't exist it is created.
*
* @param name - The name of the event
* @returns The remote event associated with the name
*/
export function getEvent(name: string): RemoteEvent {
let event = events.get(name)
if (!event) {
const instance = script.FindFirstChild(name)
if (instance && instance.IsA("RemoteEvent")) {
event = instance
} else {
event = new Instance("RemoteEvent")
event.Name = name
event.Parent = script
}
events.set(name, event)
}
return event
}
/**
* Gets a remote event by name.
*
* @param name - The name of the event
* @returns The remote event associated with the name
*
* @throws "Event '[name]' was requested, but no such remote event exists."
* This is thrown when an event name is provided that doesn't exist. If this is
* not desired, see {@link getEvent} and {@link waitForEvent} instead.
*
* @throws "Event '[name]' was requested, but was not a remote event."
* This is thrown when an event name provided exists, but is not an event.
* Usually this is because it's a function instead.
*/
export function getEventOrFail(name: string): RemoteEvent {
let event = events.get(name)
if (!event) {
const instance = script.FindFirstChild(name)
if (!instance) {
throw ERROR_MISSING_EVENT.format(name)
}
if (!instance.IsA("RemoteEvent")) {
throw ERROR_INVALID_EVENT.format(name)
}
event = instance
events.set(name, event)
}
return event
}
/**
* Gets a remote event by name, waiting for it if it doesn't exist.
*
* @param name - The name of the event
* @param timeout - The time to wait for the event
* @returns The remote event associated with the name
*
* @throws "Event '[name]' was requested, but was not a remote event."
* This is thrown when an event name provided exists, but is not an event.
* Usually this is because it's a function instead.
*/
export function waitForEvent(name: string): RemoteEvent
export function waitForEvent(name: string, timeout: number): RemoteEvent | undefined
export function waitForEvent(name: string, timeout?: number): RemoteEvent | undefined {
let event = events.get(name)
if (!event) {
const instance =
timeout !== undefined ? script.WaitForChild(name, timeout) : script.WaitForChild(name)
if (!instance) return
if (!instance.IsA("RemoteEvent")) {
throw ERROR_INVALID_EVENT.format(name)
}
event = instance
events.set(name, event)
}
return event
}
/**
* Destroys the event associated with a name.
*
* @param name - The name of the event
*/
export function destroyEvent(name: string): void {
const event = events.get(name)
if (event) {
event.Destroy()
events.delete(name)
}
}
/**
* Gets a remote function by name. If the function doesn't exist it is created.
*
* @param name - The name of the function
* @returns The remote function associated with the name
*/
export function getFunction(name: string): RemoteFunction {
let fn = functions.get(name)
if (!fn) {
const instance = script.FindFirstChild(name)
if (instance && instance.IsA("RemoteFunction")) {
fn = instance
} else {
fn = new Instance("RemoteFunction")
fn.Name = name
fn.Parent = script
}
functions.set(name, fn)
}
return fn
}
/**
* Gets a remote function by name.
*
* @param name - The name of the function
* @returns The remote function associated with the name
*
* @throws "Function '[name]' was requested, but no such remote function exists."
* This is thrown when a function name is provided that doesn't exist. If this
* is not desired, see {@link getFunction} and {@link waitForFunction} instead.
*
* @throws "Function '[name]' was requested, but was not a remote function."
* This is thrown when a function name provided exists, but is not a function.
* Usually this is because it's an event instead.
*/
export function getFunctionOrFail(name: string): RemoteFunction {
let fn = functions.get(name)
if (!fn) {
const instance = script.FindFirstChild(name)
if (!instance) {
throw ERROR_MISSING_FUNCTION.format(name)
}
if (!instance.IsA("RemoteFunction")) {
throw ERROR_INVALID_FUNCTION.format(name)
}
fn = instance
functions.set(name, fn)
}
return fn
}
/**
* Gets a remote function by name, waiting for it if it doesn't exist.
*
* @param name - The name of the function
* @param timeout - The time to wait for the function
* @returns The remote function associated with the name
*
* @throws "Function '[name]' was requested, but was not a remote function."
* This is thrown when a function name provided exists, but is not a function.
* Usually this is because it's an event instead.
*/
export function waitForFunction(name: string): RemoteFunction
export function waitForFunction(name: string, timeout: number): RemoteFunction | undefined
export function waitForFunction(name: string, timeout?: number): RemoteFunction | undefined {
let fn = functions.get(name)
if (!fn) {
const instance =
timeout !== undefined ? script.WaitForChild(name, timeout) : script.WaitForChild(name)
if (!instance) return
if (!instance.IsA("RemoteFunction")) {
throw ERROR_INVALID_FUNCTION.format(name)
}
fn = instance
functions.set(name, fn)
}
return fn
}
/**
* Destroys the function associated with a name.
*
* @param name - The name of the function
*/
export function destroyFunction(name: string): void {
const fn = functions.get(name)
if (fn) {
fn.Destroy()
functions.delete(name)
}
}

View file

@ -0,0 +1,21 @@
import { World } from "@rbxts/matter"
import { Damage, Health } from "ReplicatedStorage/ecs/components"
/**
* A system that reduces health when Damage components are applied.
*
* This only adjusts any attached Health component.
*/
function damageHurts(world: World): void {
for (const [id, health, damage] of world.query(Health, Damage)) {
world.insert(
id,
health.patch({
health: health.health - damage.damage
})
)
world.remove(id, Damage)
}
}
export = damageHurts

View file

@ -0,0 +1,37 @@
import { World } from "@rbxts/matter"
import { Health, Model } from "ReplicatedStorage/ecs/components"
/**
* A system that mirrors health to Humanoids.
*
* If a health component has an attached model that contains a humanoid. This
* will reflect the changes in health to that humanoid.
*
* If the health is out of bounds between 0 and the max health it is clamped
* between these values.
*/
function healthKills(world: World): void {
for (const [id, record] of world.queryChanged(Health)) {
if (!record.new) continue
const health = math.clamp(record.new.health, 0, record.new.maxHealth)
if (health !== record.new.health) {
world.insert(
id,
record.new.patch({
health: health
})
)
}
const model = world.get(id, Model)
if (!model) continue
const humanoid = model.model?.FindFirstChildOfClass("Humanoid")
if (humanoid) {
humanoid.MaxHealth = record.new.maxHealth
humanoid.Health = health
}
}
}
export = healthKills

View file

@ -0,0 +1,24 @@
import { useThrottle, World } from "@rbxts/matter"
import { Health } from "ReplicatedStorage/ecs/components"
/**
* @todo
*/
function healthRegenerates(world: World): void {
for (const [id, health] of world.query(Health)) {
if (health.health <= 0) continue
const newHealth = math.clamp(health.health + health.regeneration, 0, health.maxHealth)
if (useThrottle(1)) {
world.insert(
id,
health.patch({
health: newHealth
})
)
}
}
}
export = healthRegenerates

View file

@ -0,0 +1,33 @@
import { Players } from "@rbxts/services"
import { World, useEvent } from "@rbxts/matter"
import { Health, Model, PlayerCharacter } from "ReplicatedStorage/ecs/components"
/**
* @todo
*/
function playersArePlayerCharacters(world: World): void {
Players.GetPlayers().forEach((player, _) => {
for (const [_, character] of useEvent(player, "CharacterAdded")) {
world.spawn(
Model({
model: character
}),
PlayerCharacter({
player: Players.GetPlayerFromCharacter(character) as Player,
humanoid: character.WaitForChild("Humanoid") as Humanoid
}),
Health({
health: 80,
maxHealth: 100,
regeneration: 0.25
})
)
}
})
for (const [id] of world.query(PlayerCharacter).without(Model)) {
world.despawn(id)
}
}
export = playersArePlayerCharacters

View file

@ -0,0 +1,41 @@
import { World, useEvent } from "@rbxts/matter"
import { Model, PlayerCharacter } from "ReplicatedStorage/ecs/components"
/**
* @todo
*/
function playersRagdollOnDeath(world: World): void {
for (const [_, playerCharacter, model] of world.query(PlayerCharacter, Model)) {
if (!model.model) continue
playerCharacter.humanoid.BreakJointsOnDeath = false
for (const [_] of useEvent(playerCharacter.humanoid, "Died")) {
model.model.GetDescendants().forEach((v, _) => {
if (v.IsA("Motor6D")) {
const attachment0 = new Instance("Attachment")
const attachment1 = new Instance("Attachment")
attachment0.CFrame = v.C0
attachment1.CFrame = v.C1
attachment0.Parent = v.Part0
attachment1.Parent = v.Part1
const ballSocketConstraint = new Instance("BallSocketConstraint")
ballSocketConstraint.Attachment0 = attachment0
ballSocketConstraint.Attachment1 = attachment1
ballSocketConstraint.LimitsEnabled = true
ballSocketConstraint.TwistLimitsEnabled = true
ballSocketConstraint.Parent = v.Parent
v.Destroy()
}
})
}
}
for (const [id] of world.query(PlayerCharacter).without(Model)) {
world.despawn(id)
}
}
export = playersRagdollOnDeath

View file

@ -0,0 +1,30 @@
import { useEvent, World } from "@rbxts/matter"
import { Model } from "ReplicatedStorage/ecs/components"
/**
* A system that removes missing {@link Model | Models}.
*
* If a model is removed from the game, this system will remove the
* corresponding model from the world.
*
* If a model is removed from the world, this system will remove the
* corresponding model from the game.
*/
function removeMissingModels(world: World): void {
for (const [id, model] of world.query(Model)) {
if (!model.model) continue
for (const _ of useEvent(model.model, "AncestryChanged")) {
if (!model.model.IsDescendantOf(game)) {
world.remove(id, Model)
break
}
}
}
for (const [_, record] of world.queryChanged(Model)) {
if (record.new) continue
record.old?.model?.Destroy()
}
}
export = removeMissingModels

View file

@ -0,0 +1,83 @@
import { useEvent, World } from "@rbxts/matter"
import { Players } from "@rbxts/services"
import * as Components from "ReplicatedStorage/ecs/components"
import { getEvent } from "ReplicatedStorage/remotes"
type ComponentName = keyof typeof Components
type ComponentConstructor = (typeof Components)[ComponentName]
const REPLICATED_COMPONENT_NAMES: readonly ComponentName[] = ["Model", "Health"]
const replicatedComponents: ReadonlySet<ComponentConstructor> = REPLICATED_COMPONENT_NAMES.reduce(
(set: Set<ComponentConstructor>, name: ComponentName) => {
return set.add(Components[name])
},
new Set()
)
getEvent("EcsReplication")
function replication(world: World): void {
const replicationEvent = getEvent("EcsReplication")
let payload: Map<string, Map<ComponentName, { data?: Components.GooplerComponent }>> | undefined
for (const [_, player] of useEvent(Players, "PlayerAdded")) {
if (!payload) {
payload = new Map()
for (const [id, entityData] of world) {
const entityPayload: Map<ComponentName, { data?: Components.GooplerComponent }> =
new Map()
payload.set(tostring(id), entityPayload)
for (const [component, componentData] of entityData) {
if (replicatedComponents.has(component)) {
// Here we are certain that the component has the name of one of our
// components because it exists in our set of components.
entityPayload.set(tostring(component) as ComponentName, { data: componentData })
}
}
}
}
print("Sending initial payload to", player)
replicationEvent.FireClient(player, payload)
}
const changes: Map<
string,
Map<ComponentName, { data?: Components.GooplerComponent }>
> = new Map()
for (const component of replicatedComponents) {
// Here we are certain that the component has the name of one of our
// components since it came from our set.
const name = tostring(component) as ComponentName
for (const [id, record] of world.queryChanged(component)) {
const key = tostring(id)
if (!changes.has(key)) {
changes.set(key, new Map())
}
if (world.contains(id)) {
changes.get(key)?.set(name, { data: record.new })
}
}
}
if (!changes.isEmpty()) {
replicationEvent.FireAllClients(changes)
}
}
/**
* A system that replicates all replicated components to the client.
*
* This system runs after after all other systems to ensure any changes made are
* included.
*/
export = {
system: replication,
priority: math.huge
}

View file

@ -0,0 +1,71 @@
import { World } from "@rbxts/matter"
import { Workspace } from "@rbxts/services"
import { Model, Transform } from "ReplicatedStorage/ecs/components"
import removeMissingModels from "./removeMissingModels"
function updateTransforms(world: World): void {
for (const [id, record] of world.queryChanged(Transform)) {
if (!world.contains(id)) continue
const model = world.get(id, Model)
if (!model || !record.new || record.new._doNotReconcile) continue
model.model?.PivotTo(record.new.cframe)
}
for (const [id, record] of world.queryChanged(Model)) {
if (!world.contains(id)) continue
const transform = world.get(id, Transform)
if (!transform) continue
record.new?.model?.PivotTo(transform.cframe)
}
for (const [id, model, transform] of world.query(Model, Transform)) {
if (!model.model) continue
let primaryPart: BasePart
if (model.model.IsA("Model")) {
if (!model.model.PrimaryPart) continue
primaryPart = model.model.PrimaryPart
} else if (model.model.IsA("BasePart")) {
primaryPart = model.model
} else {
continue
}
if (primaryPart.Anchored) continue
if (transform.cframe.Y < Workspace.FallenPartsDestroyHeight) {
world.despawn(id)
continue
}
if (transform.cframe !== primaryPart.CFrame) {
world.insert(
id,
Transform({
cframe: primaryPart.CFrame,
_doNotReconcile: true
})
)
}
}
}
/**
* A system that updates {@link Transform | Transforms}.
*
* If a Transform is updated, the corresponding {@link Model} is updated to
* match the Transform.
*
* If a Model is updated, the new referenced instance is updated to match the
* Transform.
*
* If an non-anchored model moves, the Transform is updated to match the updated
* instance transform.
*
* This system runs after {@link removeMissingModels} to ensure updates aren't
* performed unnecessarily.
*/
export = {
system: updateTransforms,
after: [removeMissingModels]
}

View file

@ -0,0 +1,13 @@
import { start } from "ReplicatedStorage/ecs"
import { Host } from "ReplicatedStorage/hosts"
import { setEnvironment } from "ReplicatedStorage/idAttribute"
import { getEvent } from "ReplicatedStorage/remotes"
const HOST = Host.Server
// We only do this here at the moment to create a dummy event for replication.
// In the future this will be created by the replication system.
getEvent("EcsReplication")
setEnvironment(HOST)
start(HOST)

View file

@ -0,0 +1,3 @@
// This file exists to disable the roblox health regeneration
// This seems hacky to override something, but this is officially endorsed!
// See: https://create.roblox.com/docs/reference/engine/classes/Humanoid#Health

View file

@ -0,0 +1,8 @@
import { start } from "ReplicatedStorage/ecs"
import { Host } from "ReplicatedStorage/hosts"
import { setEnvironment } from "ReplicatedStorage/idAttribute"
const HOST = Host.Client
setEnvironment(HOST)
start(HOST)

View file

@ -0,0 +1,9 @@
/// <reference types="@rbxts/testez/globals" />
export = (): void => {
describe("Integration Test", () => {
it("should be true", () => {
expect(true).to.equal(true)
})
})
}

View file

@ -0,0 +1,5 @@
{
"properties": {
"Disabled": true
}
}

View file

@ -0,0 +1,12 @@
import { test } from "./util/tests"
import { roots } from "./util/roots"
const [completed, result] = test(roots)
if (completed) {
if (!result) {
error("Tests have failed.", 0)
}
} else {
error(result, 0)
}

View file

@ -0,0 +1,14 @@
{
"ReplicatedStorage": {
"goopler": {},
"tests": {}
},
"ServerScriptService": {
"goopler": {}
},
"StarterPlayer": {
"StarterPlayerScripts": {
"goopler": {}
}
}
}

View file

@ -0,0 +1,33 @@
import * as rootTree from "./rootTree.json"
type Node = { [key: string]: Node }
type RootNode = {
[key in keyof Services]?: Node;
}
function getRoots(node: Node, parent: Instance): Instance[] {
const roots: Instance[] = []
for (const [key, subNode] of pairs(node)) {
const subRoots = getRoots(
subNode,
parent.FindFirstChild(key) ?? error(`Could not find child ${key}`)
)
subRoots.move(0, subRoots.size(), roots.size(), roots)
}
if (roots.isEmpty()) {
roots.push(parent)
}
return roots
}
function getAllRoots(node: RootNode): Instance[] {
const roots: Instance[] = []
for (const [key, subNode] of pairs(node)) {
const subRoots = getRoots(subNode, game.GetService(key))
subRoots.move(0, subRoots.size(), roots.size(), roots)
}
return roots
}
export const roots = getAllRoots(rootTree)

View file

@ -0,0 +1,16 @@
import { TestBootstrap } from "@rbxts/testez"
export function test(
roots: Instance[]
): LuaTuple<[completed: true, result: boolean] | [completed: false, error: string]> {
print()
const call = xpcall(
() => {
const results = TestBootstrap.run(roots)
return results.failureCount === 0
},
(err) => debug.traceback(tostring(err))
)
print()
return call
}

27
tsconfig.json Normal file
View file

@ -0,0 +1,27 @@
{
"compilerOptions": {
// required
"allowSyntheticDefaultImports": true,
"downlevelIteration": true,
"jsx": "react",
"jsxFactory": "Roact.createElement",
"jsxFragmentFactory": "Roact.Fragment",
"module": "commonjs",
"moduleResolution": "Node",
"noLib": true,
"resolveJsonModule": true,
"experimentalDecorators": true,
"forceConsistentCasingInFileNames": true,
"moduleDetection": "force",
"strict": true,
"target": "ESNext",
"typeRoots": ["node_modules/@rbxts"],
// configurable
"rootDirs": ["src", "tests"],
"outDir": "out",
"baseUrl": "src",
"incremental": true,
"tsBuildInfoFile": "out/tsconfig.tsbuildinfo"
}
}

958
yarn.lock Normal file
View file

@ -0,0 +1,958 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
"@eslint-community/eslint-utils@^4.2.0":
version "4.4.0"
resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59"
integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==
dependencies:
eslint-visitor-keys "^3.3.0"
"@eslint-community/regexpp@^4.4.0":
version "4.5.1"
resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.5.1.tgz#cdd35dce4fa1a89a4fd42b1599eb35b3af408884"
integrity sha512-Z5ba73P98O1KUYCCJTUeVpja9RcGoMdncZ6T49FCUl2lN38JtCJ+3WgIDBv0AuY4WChU5PmtJmOCTlN6FZTFKQ==
"@eslint/eslintrc@^2.0.3":
version "2.0.3"
resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.0.3.tgz#4910db5505f4d503f27774bf356e3704818a0331"
integrity sha512-+5gy6OQfk+xx3q0d6jGZZC3f3KzAkXc/IanVxd1is/VIIziRqqt3ongQz0FiTUXqTk0c7aDB3OaFuKnuSoJicQ==
dependencies:
ajv "^6.12.4"
debug "^4.3.2"
espree "^9.5.2"
globals "^13.19.0"
ignore "^5.2.0"
import-fresh "^3.2.1"
js-yaml "^4.1.0"
minimatch "^3.1.2"
strip-json-comments "^3.1.1"
"@eslint/js@8.42.0":
version "8.42.0"
resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.42.0.tgz#484a1d638de2911e6f5a30c12f49c7e4a3270fb6"
integrity sha512-6SWlXpWU5AvId8Ac7zjzmIOqMOba/JWY8XZ4A7q7Gn1Vlfg/SFFIlrtHXt9nPn4op9ZPAkl91Jao+QQv3r/ukw==
"@humanwhocodes/config-array@^0.11.10":
version "0.11.10"
resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.10.tgz#5a3ffe32cc9306365fb3fd572596cd602d5e12d2"
integrity sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==
dependencies:
"@humanwhocodes/object-schema" "^1.2.1"
debug "^4.1.1"
minimatch "^3.0.5"
"@humanwhocodes/module-importer@^1.0.1":
version "1.0.1"
resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c"
integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==
"@humanwhocodes/object-schema@^1.2.1":
version "1.2.1"
resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45"
integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==
"@nodelib/fs.scandir@2.1.5":
version "2.1.5"
resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5"
integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==
dependencies:
"@nodelib/fs.stat" "2.0.5"
run-parallel "^1.1.9"
"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2":
version "2.0.5"
resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b"
integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==
"@nodelib/fs.walk@^1.2.3", "@nodelib/fs.walk@^1.2.8":
version "1.2.8"
resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a"
integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==
dependencies:
"@nodelib/fs.scandir" "2.1.5"
fastq "^1.6.0"
"@rbxts/compiler-types@^2.0.4-types.1":
version "2.0.4-types.1"
resolved "https://registry.yarnpkg.com/@rbxts/compiler-types/-/compiler-types-2.0.4-types.1.tgz#d37edf0766aa41895085c92795c6e65261355a53"
integrity sha512-sLFiyMH9j8kcCd07lt6R+WgneksCGqYUFKu7qX02ufUU7r9eR2dXoOt2A9Nxh3unTuCu5mYyO0M6JYb82fOHxA==
"@rbxts/matter@^0.6.2-ts.6":
version "0.6.2-ts.6"
resolved "https://registry.yarnpkg.com/@rbxts/matter/-/matter-0.6.2-ts.6.tgz#e6287da3f1fb4df6befcbe3bc3605c1c66a8e8d2"
integrity sha512-M/LHRYC0QVm0klRFef97nwTBPM9Y2v1gBno2JbE75KpFEtiFhM//dz51e62NXp7Vbx9d4qnO/ldBBoc+HmeBtQ==
"@rbxts/plasma@^0.4.1-ts.1":
version "0.4.1-ts.1"
resolved "https://registry.yarnpkg.com/@rbxts/plasma/-/plasma-0.4.1-ts.1.tgz#3d8db367c3220e6b6953cdddbf8af9f087165392"
integrity sha512-RhLkC3GQW0KeyqjFwvOUbHhsIJOHmXg+BhcKLp0IgUDVgC5GktShi3zmW6GQ319yod+RlUDG1XHjOnP3Omo4bA==
"@rbxts/rewire@^0.3.0":
version "0.3.0"
resolved "https://registry.yarnpkg.com/@rbxts/rewire/-/rewire-0.3.0.tgz#47f0cd651fe405cf418936799d2a4dac6b1bb7ce"
integrity sha512-wChhGZ3kEkEsMK9ZuwKpwRsC7OGVZlvxrYMR3beFgCIPXE58JKLziBLkDACmd709XCCEmsMAqv9HMCMhSTD08Q==
"@rbxts/services@^1.5.1":
version "1.5.1"
resolved "https://registry.yarnpkg.com/@rbxts/services/-/services-1.5.1.tgz#4536a87932f28797507ed591f0061277c52ea77f"
integrity sha512-SRtfIjga0K4YYSXRpK+eH3kcTq7ZXo9OHOt0jszaOOoEOIJloMGlyuRPqesPHyhveh2AMXAZr3TYbRMSD+u+kQ==
"@rbxts/testez@^0.4.2-ts.0":
version "0.4.2-ts.0"
resolved "https://registry.yarnpkg.com/@rbxts/testez/-/testez-0.4.2-ts.0.tgz#4475183d317182ac7099bffee6492ffcb7bcaf0b"
integrity sha512-8Q+OG9ddTD2P3aARCuRKpPqUBvuifgSnHvQMZ6jBMqUzxhIysnb0l4c3vnnaQnvdyZ1OW9tKxcdEHMGTb67uOw==
"@rbxts/types@^1.0.689":
version "1.0.689"
resolved "https://registry.yarnpkg.com/@rbxts/types/-/types-1.0.689.tgz#a53f657636dc5b74475749508ded1fbef3e21ccd"
integrity sha512-+5fBORSpfR1FVMXTm/wgs1aDDDZugRjx666QS+X5bJnTQD5HA77dz5X7Gsy6+2nFpnrVeR+IFUznU2OV3Ustow==
"@types/json-schema@^7.0.9":
version "7.0.12"
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.12.tgz#d70faba7039d5fca54c83c7dbab41051d2b6f6cb"
integrity sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==
"@types/node@^16.10.4":
version "16.18.36"
resolved "https://registry.yarnpkg.com/@types/node/-/node-16.18.36.tgz#0db5d7efc4760d36d0d1d22c85d1a53accd5dc27"
integrity sha512-8egDX8dE50XyXWH6C6PRCNkTP106DuUrvdrednFouDSmCi7IOvrqr0frznfZaHifHH/3aq/7a7v9N4wdXMqhBQ==
"@types/semver@^7.3.12":
version "7.5.0"
resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.0.tgz#591c1ce3a702c45ee15f47a42ade72c2fd78978a"
integrity sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==
"@typescript-eslint/eslint-plugin@^5.59.11":
version "5.59.11"
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.59.11.tgz#8d466aa21abea4c3f37129997b198d141f09e76f"
integrity sha512-XxuOfTkCUiOSyBWIvHlUraLw/JT/6Io1365RO6ZuI88STKMavJZPNMU0lFcUTeQXEhHiv64CbxYxBNoDVSmghg==
dependencies:
"@eslint-community/regexpp" "^4.4.0"
"@typescript-eslint/scope-manager" "5.59.11"
"@typescript-eslint/type-utils" "5.59.11"
"@typescript-eslint/utils" "5.59.11"
debug "^4.3.4"
grapheme-splitter "^1.0.4"
ignore "^5.2.0"
natural-compare-lite "^1.4.0"
semver "^7.3.7"
tsutils "^3.21.0"
"@typescript-eslint/experimental-utils@^5.0.0":
version "5.59.11"
resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-5.59.11.tgz#9f95e09313a9f96457006b0b8ed43c2e68eb8876"
integrity sha512-GkQGV0UF/V5Ra7gZMBmiD1WrYUFOJNvCZs+XQnUyJoxmqfWMXVNyB2NVCPRKefoQcpvTv9UpJyfCvsJFs8NzzQ==
dependencies:
"@typescript-eslint/utils" "5.59.11"
"@typescript-eslint/parser@^5.59.11":
version "5.59.11"
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.59.11.tgz#af7d4b7110e3068ce0b97550736de455e4250103"
integrity sha512-s9ZF3M+Nym6CAZEkJJeO2TFHHDsKAM3ecNkLuH4i4s8/RCPnF5JRip2GyviYkeEAcwGMJxkqG9h2dAsnA1nZpA==
dependencies:
"@typescript-eslint/scope-manager" "5.59.11"
"@typescript-eslint/types" "5.59.11"
"@typescript-eslint/typescript-estree" "5.59.11"
debug "^4.3.4"
"@typescript-eslint/scope-manager@5.59.11":
version "5.59.11"
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.59.11.tgz#5d131a67a19189c42598af9fb2ea1165252001ce"
integrity sha512-dHFOsxoLFtrIcSj5h0QoBT/89hxQONwmn3FOQ0GOQcLOOXm+MIrS8zEAhs4tWl5MraxCY3ZJpaXQQdFMc2Tu+Q==
dependencies:
"@typescript-eslint/types" "5.59.11"
"@typescript-eslint/visitor-keys" "5.59.11"
"@typescript-eslint/type-utils@5.59.11":
version "5.59.11"
resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.59.11.tgz#5eb67121808a84cb57d65a15f48f5bdda25f2346"
integrity sha512-LZqVY8hMiVRF2a7/swmkStMYSoXMFlzL6sXV6U/2gL5cwnLWQgLEG8tjWPpaE4rMIdZ6VKWwcffPlo1jPfk43g==
dependencies:
"@typescript-eslint/typescript-estree" "5.59.11"
"@typescript-eslint/utils" "5.59.11"
debug "^4.3.4"
tsutils "^3.21.0"
"@typescript-eslint/types@5.59.11":
version "5.59.11"
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.59.11.tgz#1a9018fe3c565ba6969561f2a49f330cf1fe8db1"
integrity sha512-epoN6R6tkvBYSc+cllrz+c2sOFWkbisJZWkOE+y3xHtvYaOE6Wk6B8e114McRJwFRjGvYdJwLXQH5c9osME/AA==
"@typescript-eslint/typescript-estree@5.59.11":
version "5.59.11"
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.11.tgz#b2caaa31725e17c33970c1197bcd54e3c5f42b9f"
integrity sha512-YupOpot5hJO0maupJXixi6l5ETdrITxeo5eBOeuV7RSKgYdU3G5cxO49/9WRnJq9EMrB7AuTSLH/bqOsXi7wPA==
dependencies:
"@typescript-eslint/types" "5.59.11"
"@typescript-eslint/visitor-keys" "5.59.11"
debug "^4.3.4"
globby "^11.1.0"
is-glob "^4.0.3"
semver "^7.3.7"
tsutils "^3.21.0"
"@typescript-eslint/utils@5.59.11":
version "5.59.11"
resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.59.11.tgz#9dbff49dc80bfdd9289f9f33548f2e8db3c59ba1"
integrity sha512-didu2rHSOMUdJThLk4aZ1Or8IcO3HzCw/ZvEjTTIfjIrcdd5cvSIwwDy2AOlE7htSNp7QIZ10fLMyRCveesMLg==
dependencies:
"@eslint-community/eslint-utils" "^4.2.0"
"@types/json-schema" "^7.0.9"
"@types/semver" "^7.3.12"
"@typescript-eslint/scope-manager" "5.59.11"
"@typescript-eslint/types" "5.59.11"
"@typescript-eslint/typescript-estree" "5.59.11"
eslint-scope "^5.1.1"
semver "^7.3.7"
"@typescript-eslint/visitor-keys@5.59.11":
version "5.59.11"
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.59.11.tgz#dca561ddad169dc27d62396d64f45b2d2c3ecc56"
integrity sha512-KGYniTGG3AMTuKF9QBD7EIrvufkB6O6uX3knP73xbKLMpH+QRPcgnCxjWXSHjMRuOxFLovljqQgQpR0c7GvjoA==
dependencies:
"@typescript-eslint/types" "5.59.11"
eslint-visitor-keys "^3.3.0"
acorn-jsx@^5.3.2:
version "5.3.2"
resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937"
integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==
acorn@^8.8.0:
version "8.9.0"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.9.0.tgz#78a16e3b2bcc198c10822786fa6679e245db5b59"
integrity sha512-jaVNAFBHNLXspO543WnNNPZFRtavh3skAkITqD0/2aeMkKZTN+254PyhwxFYrk3vQ1xfY+2wbesJMs/JC8/PwQ==
ajv@^6.10.0, ajv@^6.12.4:
version "6.12.6"
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4"
integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==
dependencies:
fast-deep-equal "^3.1.1"
fast-json-stable-stringify "^2.0.0"
json-schema-traverse "^0.4.1"
uri-js "^4.2.2"
ansi-regex@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304"
integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==
ansi-styles@^4.1.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937"
integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==
dependencies:
color-convert "^2.0.1"
argparse@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38"
integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==
array-union@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d"
integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==
balanced-match@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
brace-expansion@^1.1.7:
version "1.1.11"
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
dependencies:
balanced-match "^1.0.0"
concat-map "0.0.1"
braces@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==
dependencies:
fill-range "^7.0.1"
callsites@^3.0.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==
chalk@^4.0.0:
version "4.1.2"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01"
integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
dependencies:
ansi-styles "^4.1.0"
supports-color "^7.1.0"
color-convert@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3"
integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==
dependencies:
color-name "~1.1.4"
color-name@~1.1.4:
version "1.1.4"
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
concat-map@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==
cross-spawn@^7.0.2:
version "7.0.3"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==
dependencies:
path-key "^3.1.0"
shebang-command "^2.0.0"
which "^2.0.1"
debug@^4.1.1, debug@^4.3.2, debug@^4.3.4:
version "4.3.4"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
dependencies:
ms "2.1.2"
deep-is@^0.1.3:
version "0.1.4"
resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831"
integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==
dir-glob@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f"
integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==
dependencies:
path-type "^4.0.0"
doctrine@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961"
integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==
dependencies:
esutils "^2.0.2"
escape-string-regexp@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34"
integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==
eslint-plugin-roblox-ts@^0.0.35:
version "0.0.35"
resolved "https://registry.yarnpkg.com/eslint-plugin-roblox-ts/-/eslint-plugin-roblox-ts-0.0.35.tgz#9b1369b9ca0a454033125c2588f575985a3d0b3d"
integrity sha512-dITctpivgGVLWljPGZBGA0pvmjqA1VzTNd1K3ExOXMk6bYxSn4FyAVkrzHA+ITvAkVJYtgRzwKYJlf1HUoszQg==
dependencies:
"@types/node" "^16.10.4"
"@typescript-eslint/experimental-utils" "^5.0.0"
typescript "^4.4.4"
eslint-scope@^5.1.1:
version "5.1.1"
resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c"
integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==
dependencies:
esrecurse "^4.3.0"
estraverse "^4.1.1"
eslint-scope@^7.2.0:
version "7.2.0"
resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.0.tgz#f21ebdafda02352f103634b96dd47d9f81ca117b"
integrity sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==
dependencies:
esrecurse "^4.3.0"
estraverse "^5.2.0"
eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1:
version "3.4.1"
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz#c22c48f48942d08ca824cc526211ae400478a994"
integrity sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==
eslint@^8.42.0:
version "8.42.0"
resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.42.0.tgz#7bebdc3a55f9ed7167251fe7259f75219cade291"
integrity sha512-ulg9Ms6E1WPf67PHaEY4/6E2tEn5/f7FXGzr3t9cBMugOmf1INYvuUwwh1aXQN4MfJ6a5K2iNwP3w4AColvI9A==
dependencies:
"@eslint-community/eslint-utils" "^4.2.0"
"@eslint-community/regexpp" "^4.4.0"
"@eslint/eslintrc" "^2.0.3"
"@eslint/js" "8.42.0"
"@humanwhocodes/config-array" "^0.11.10"
"@humanwhocodes/module-importer" "^1.0.1"
"@nodelib/fs.walk" "^1.2.8"
ajv "^6.10.0"
chalk "^4.0.0"
cross-spawn "^7.0.2"
debug "^4.3.2"
doctrine "^3.0.0"
escape-string-regexp "^4.0.0"
eslint-scope "^7.2.0"
eslint-visitor-keys "^3.4.1"
espree "^9.5.2"
esquery "^1.4.2"
esutils "^2.0.2"
fast-deep-equal "^3.1.3"
file-entry-cache "^6.0.1"
find-up "^5.0.0"
glob-parent "^6.0.2"
globals "^13.19.0"
graphemer "^1.4.0"
ignore "^5.2.0"
import-fresh "^3.0.0"
imurmurhash "^0.1.4"
is-glob "^4.0.0"
is-path-inside "^3.0.3"
js-yaml "^4.1.0"
json-stable-stringify-without-jsonify "^1.0.1"
levn "^0.4.1"
lodash.merge "^4.6.2"
minimatch "^3.1.2"
natural-compare "^1.4.0"
optionator "^0.9.1"
strip-ansi "^6.0.1"
strip-json-comments "^3.1.0"
text-table "^0.2.0"
espree@^9.5.2:
version "9.5.2"
resolved "https://registry.yarnpkg.com/espree/-/espree-9.5.2.tgz#e994e7dc33a082a7a82dceaf12883a829353215b"
integrity sha512-7OASN1Wma5fum5SrNhFMAMJxOUAbhyfQ8dQ//PJaJbNw0URTPWqIghHWt1MmAANKhHZIYOHruW4Kw4ruUWOdGw==
dependencies:
acorn "^8.8.0"
acorn-jsx "^5.3.2"
eslint-visitor-keys "^3.4.1"
esquery@^1.4.2:
version "1.5.0"
resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.5.0.tgz#6ce17738de8577694edd7361c57182ac8cb0db0b"
integrity sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==
dependencies:
estraverse "^5.1.0"
esrecurse@^4.3.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921"
integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==
dependencies:
estraverse "^5.2.0"
estraverse@^4.1.1:
version "4.3.0"
resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d"
integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==
estraverse@^5.1.0, estraverse@^5.2.0:
version "5.3.0"
resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123"
integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==
esutils@^2.0.2:
version "2.0.3"
resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64"
integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==
fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3:
version "3.1.3"
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
fast-glob@^3.2.9:
version "3.2.12"
resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.12.tgz#7f39ec99c2e6ab030337142da9e0c18f37afae80"
integrity sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==
dependencies:
"@nodelib/fs.stat" "^2.0.2"
"@nodelib/fs.walk" "^1.2.3"
glob-parent "^5.1.2"
merge2 "^1.3.0"
micromatch "^4.0.4"
fast-json-stable-stringify@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633"
integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==
fast-levenshtein@^2.0.6:
version "2.0.6"
resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==
fastq@^1.6.0:
version "1.15.0"
resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.15.0.tgz#d04d07c6a2a68fe4599fea8d2e103a937fae6b3a"
integrity sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==
dependencies:
reusify "^1.0.4"
file-entry-cache@^6.0.1:
version "6.0.1"
resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027"
integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==
dependencies:
flat-cache "^3.0.4"
fill-range@^7.0.1:
version "7.0.1"
resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"
integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==
dependencies:
to-regex-range "^5.0.1"
find-up@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc"
integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==
dependencies:
locate-path "^6.0.0"
path-exists "^4.0.0"
flat-cache@^3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11"
integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==
dependencies:
flatted "^3.1.0"
rimraf "^3.0.2"
flatted@^3.1.0:
version "3.2.7"
resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.7.tgz#609f39207cb614b89d0765b477cb2d437fbf9787"
integrity sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==
fs.realpath@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==
glob-parent@^5.1.2:
version "5.1.2"
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4"
integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==
dependencies:
is-glob "^4.0.1"
glob-parent@^6.0.2:
version "6.0.2"
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3"
integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==
dependencies:
is-glob "^4.0.3"
glob@^7.1.3:
version "7.2.3"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b"
integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==
dependencies:
fs.realpath "^1.0.0"
inflight "^1.0.4"
inherits "2"
minimatch "^3.1.1"
once "^1.3.0"
path-is-absolute "^1.0.0"
globals@^13.19.0:
version "13.20.0"
resolved "https://registry.yarnpkg.com/globals/-/globals-13.20.0.tgz#ea276a1e508ffd4f1612888f9d1bad1e2717bf82"
integrity sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==
dependencies:
type-fest "^0.20.2"
globby@^11.1.0:
version "11.1.0"
resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b"
integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==
dependencies:
array-union "^2.1.0"
dir-glob "^3.0.1"
fast-glob "^3.2.9"
ignore "^5.2.0"
merge2 "^1.4.1"
slash "^3.0.0"
grapheme-splitter@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz#9cf3a665c6247479896834af35cf1dbb4400767e"
integrity sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==
graphemer@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6"
integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==
has-flag@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
ignore@^5.2.0:
version "5.2.4"
resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.4.tgz#a291c0c6178ff1b960befe47fcdec301674a6324"
integrity sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==
import-fresh@^3.0.0, import-fresh@^3.2.1:
version "3.3.0"
resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b"
integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==
dependencies:
parent-module "^1.0.0"
resolve-from "^4.0.0"
imurmurhash@^0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==
inflight@^1.0.4:
version "1.0.6"
resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==
dependencies:
once "^1.3.0"
wrappy "1"
inherits@2:
version "2.0.4"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
is-extglob@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==
is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3:
version "4.0.3"
resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084"
integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==
dependencies:
is-extglob "^2.1.1"
is-number@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
is-path-inside@^3.0.3:
version "3.0.3"
resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283"
integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==
isexe@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==
js-yaml@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602"
integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==
dependencies:
argparse "^2.0.1"
json-schema-traverse@^0.4.1:
version "0.4.1"
resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==
json-stable-stringify-without-jsonify@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651"
integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==
levn@^0.4.1:
version "0.4.1"
resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade"
integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==
dependencies:
prelude-ls "^1.2.1"
type-check "~0.4.0"
locate-path@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286"
integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==
dependencies:
p-locate "^5.0.0"
lodash.merge@^4.6.2:
version "4.6.2"
resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a"
integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==
lru-cache@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94"
integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==
dependencies:
yallist "^4.0.0"
merge2@^1.3.0, merge2@^1.4.1:
version "1.4.1"
resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae"
integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
micromatch@^4.0.4:
version "4.0.5"
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6"
integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==
dependencies:
braces "^3.0.2"
picomatch "^2.3.1"
minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2:
version "3.1.2"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
dependencies:
brace-expansion "^1.1.7"
ms@2.1.2:
version "2.1.2"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
natural-compare-lite@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz#17b09581988979fddafe0201e931ba933c96cbb4"
integrity sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==
natural-compare@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==
once@^1.3.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==
dependencies:
wrappy "1"
optionator@^0.9.1:
version "0.9.1"
resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499"
integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==
dependencies:
deep-is "^0.1.3"
fast-levenshtein "^2.0.6"
levn "^0.4.1"
prelude-ls "^1.2.1"
type-check "^0.4.0"
word-wrap "^1.2.3"
p-limit@^3.0.2:
version "3.1.0"
resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b"
integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==
dependencies:
yocto-queue "^0.1.0"
p-locate@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834"
integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==
dependencies:
p-limit "^3.0.2"
parent-module@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2"
integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==
dependencies:
callsites "^3.0.0"
path-exists@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3"
integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==
path-is-absolute@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==
path-key@^3.1.0:
version "3.1.1"
resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375"
integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==
path-type@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b"
integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==
picomatch@^2.3.1:
version "2.3.1"
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
prelude-ls@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396"
integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==
punycode@^2.1.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f"
integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==
queue-microtask@^1.2.2:
version "1.2.3"
resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243"
integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==
resolve-from@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==
reusify@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76"
integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==
rimraf@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a"
integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==
dependencies:
glob "^7.1.3"
run-parallel@^1.1.9:
version "1.2.0"
resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee"
integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==
dependencies:
queue-microtask "^1.2.2"
semver@^7.3.7:
version "7.5.2"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.2.tgz#5b851e66d1be07c1cdaf37dfc856f543325a2beb"
integrity sha512-SoftuTROv/cRjCze/scjGyiDtcUyxw1rgYQSZY7XTmtR5hX+dm76iDbTH8TkLPHCQmlbQVSSbNZCPM2hb0knnQ==
dependencies:
lru-cache "^6.0.0"
shebang-command@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea"
integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==
dependencies:
shebang-regex "^3.0.0"
shebang-regex@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172"
integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
slash@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634"
integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==
strip-ansi@^6.0.1:
version "6.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
dependencies:
ansi-regex "^5.0.1"
strip-json-comments@^3.1.0, strip-json-comments@^3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006"
integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==
supports-color@^7.1.0:
version "7.2.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da"
integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==
dependencies:
has-flag "^4.0.0"
text-table@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==
to-regex-range@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"
integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==
dependencies:
is-number "^7.0.0"
tslib@^1.8.1:
version "1.14.1"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
tsutils@^3.21.0:
version "3.21.0"
resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623"
integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==
dependencies:
tslib "^1.8.1"
type-check@^0.4.0, type-check@~0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1"
integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==
dependencies:
prelude-ls "^1.2.1"
type-fest@^0.20.2:
version "0.20.2"
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4"
integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==
typescript@^4.4.4:
version "4.9.5"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a"
integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==
typescript@^5.1.3:
version "5.1.3"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.1.3.tgz#8d84219244a6b40b6fb2b33cc1c062f715b9e826"
integrity sha512-XH627E9vkeqhlZFQuL+UsyAXEnibT0kWR2FWONlr4sTjvxyJYnyefgrkyECLzM5NenmKzRAy2rR/OlYLA1HkZw==
uri-js@^4.2.2:
version "4.4.1"
resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e"
integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==
dependencies:
punycode "^2.1.0"
which@^2.0.1:
version "2.0.2"
resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1"
integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==
dependencies:
isexe "^2.0.0"
word-wrap@^1.2.3:
version "1.2.3"
resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c"
integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==
wrappy@1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==
yallist@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
yocto-queue@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"
integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==