first commit
This commit is contained in:
commit
5302ecc6cc
43 changed files with 2530 additions and 0 deletions
48
.eslintrc
Normal file
48
.eslintrc
Normal 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
12
.gitignore
vendored
Normal 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
7
.vscode/extensions.json
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"recommendations": [
|
||||
"roblox-ts.vscode-roblox-ts",
|
||||
"dbaeumer.vscode-eslint",
|
||||
"evaera.vscode-rojo"
|
||||
]
|
||||
}
|
14
.vscode/settings.json
vendored
Normal file
14
.vscode/settings.json
vendored
Normal 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
7
aftman.toml
Normal 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
65
default.project.json
Normal 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
34
package.json
Normal 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
27
readme.md
Normal 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
|
8
src/ReplicatedStorage/ecs/boundTags.ts
Normal file
8
src/ReplicatedStorage/ecs/boundTags.ts
Normal file
|
@ -0,0 +1,8 @@
|
|||
import { Test } from "./components"
|
||||
|
||||
/**
|
||||
* A map of tags to their bound components.
|
||||
*/
|
||||
export const tags = new ReadonlyMap([
|
||||
["Example", Test]
|
||||
])
|
9
src/ReplicatedStorage/ecs/components/defaults.ts
Normal file
9
src/ReplicatedStorage/ecs/components/defaults.ts
Normal 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
|
||||
}
|
64
src/ReplicatedStorage/ecs/components/index.ts
Normal file
64
src/ReplicatedStorage/ecs/components/index.ts
Normal 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")
|
72
src/ReplicatedStorage/ecs/components/types.d.ts
vendored
Normal file
72
src/ReplicatedStorage/ecs/components/types.d.ts
vendored
Normal 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
|
||||
}
|
89
src/ReplicatedStorage/ecs/index.ts
Normal file
89
src/ReplicatedStorage/ecs/index.ts
Normal 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()
|
||||
}
|
104
src/ReplicatedStorage/ecs/replication.ts
Normal file
104
src/ReplicatedStorage/ecs/replication.ts
Normal 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
|
||||
}
|
8
src/ReplicatedStorage/ecs/state.ts
Normal file
8
src/ReplicatedStorage/ecs/state.ts
Normal 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
|
||||
}
|
8
src/ReplicatedStorage/ecs/systems/client/test.ts
Normal file
8
src/ReplicatedStorage/ecs/systems/client/test.ts
Normal file
|
@ -0,0 +1,8 @@
|
|||
/**
|
||||
* A test system that does nothing.
|
||||
*/
|
||||
function test(): void {
|
||||
// A test system.
|
||||
}
|
||||
|
||||
export = test
|
108
src/ReplicatedStorage/ecs/systems/index.ts
Normal file
108
src/ReplicatedStorage/ecs/systems/index.ts
Normal 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()
|
||||
}
|
19
src/ReplicatedStorage/ecs/systems/shared/lifetimesExpire.ts
Normal file
19
src/ReplicatedStorage/ecs/systems/shared/lifetimesExpire.ts
Normal 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
|
25
src/ReplicatedStorage/ecs/systems/shared/trackMemory.ts
Normal file
25
src/ReplicatedStorage/ecs/systems/shared/trackMemory.ts
Normal 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
|
|
@ -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
|
81
src/ReplicatedStorage/ecs/tags.ts
Normal file
81
src/ReplicatedStorage/ecs/tags.ts
Normal 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()
|
||||
}
|
24
src/ReplicatedStorage/hosts.ts
Normal file
24
src/ReplicatedStorage/hosts.ts
Normal 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
|
||||
}
|
47
src/ReplicatedStorage/idAttribute.ts
Normal file
47
src/ReplicatedStorage/idAttribute.ts
Normal 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
|
||||
}
|
||||
}
|
196
src/ReplicatedStorage/remotes.ts
Normal file
196
src/ReplicatedStorage/remotes.ts
Normal 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)
|
||||
}
|
||||
}
|
21
src/ServerScriptService/ecs/systems/server/damageHurts.ts
Normal file
21
src/ServerScriptService/ecs/systems/server/damageHurts.ts
Normal 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
|
37
src/ServerScriptService/ecs/systems/server/healthKills.ts
Normal file
37
src/ServerScriptService/ecs/systems/server/healthKills.ts
Normal 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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
83
src/ServerScriptService/ecs/systems/server/replication.ts
Normal file
83
src/ServerScriptService/ecs/systems/server/replication.ts
Normal 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
|
||||
}
|
|
@ -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]
|
||||
}
|
13
src/ServerScriptService/main.server.ts
Normal file
13
src/ServerScriptService/main.server.ts
Normal 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)
|
|
@ -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
|
8
src/StarterPlayer/StarterPlayerScripts/main.client.ts
Normal file
8
src/StarterPlayer/StarterPlayerScripts/main.client.ts
Normal 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)
|
9
tests/integration/integration.spec.ts
Normal file
9
tests/integration/integration.spec.ts
Normal file
|
@ -0,0 +1,9 @@
|
|||
/// <reference types="@rbxts/testez/globals" />
|
||||
|
||||
export = (): void => {
|
||||
describe("Integration Test", () => {
|
||||
it("should be true", () => {
|
||||
expect(true).to.equal(true)
|
||||
})
|
||||
})
|
||||
}
|
5
tests/runners/run.meta.json
Normal file
5
tests/runners/run.meta.json
Normal file
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"properties": {
|
||||
"Disabled": true
|
||||
}
|
||||
}
|
12
tests/runners/run.server.ts
Normal file
12
tests/runners/run.server.ts
Normal 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)
|
||||
}
|
14
tests/runners/util/rootTree.json
Normal file
14
tests/runners/util/rootTree.json
Normal file
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"ReplicatedStorage": {
|
||||
"goopler": {},
|
||||
"tests": {}
|
||||
},
|
||||
"ServerScriptService": {
|
||||
"goopler": {}
|
||||
},
|
||||
"StarterPlayer": {
|
||||
"StarterPlayerScripts": {
|
||||
"goopler": {}
|
||||
}
|
||||
}
|
||||
}
|
33
tests/runners/util/roots.ts
Normal file
33
tests/runners/util/roots.ts
Normal 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)
|
16
tests/runners/util/tests.ts
Normal file
16
tests/runners/util/tests.ts
Normal 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
27
tsconfig.json
Normal 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
958
yarn.lock
Normal 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==
|
Loading…
Add table
Add a link
Reference in a new issue