1
0
mirror of https://github.com/tobspr/shapez.io.git synced 2025-12-13 18:21:51 +00:00

Merge remote-tracking branch 'upstream/modloader' into modloader

This commit is contained in:
saile515 2022-01-24 19:30:14 +01:00
commit aa679b2dda
34 changed files with 176 additions and 27 deletions

View File

@ -41,6 +41,7 @@ To get into shapez.io modding, I highly recommend checking out all of the exampl
| [modify_existing_building.js](modify_existing_building.js) | Makes the rotator building always unlocked and adds a new statistic to the building panel | Modifying a builtin building, replacing builtin methods | | [modify_existing_building.js](modify_existing_building.js) | Makes the rotator building always unlocked and adds a new statistic to the building panel | Modifying a builtin building, replacing builtin methods |
| [modify_ui.js](modify_ui.js) | Shows how to add custom IU elements to builtin game states (the Main Menu in this case) | Extending builtin UI states, Adding CSS | | [modify_ui.js](modify_ui.js) | Shows how to add custom IU elements to builtin game states (the Main Menu in this case) | Extending builtin UI states, Adding CSS |
| [pasting.js](pasting.js) | Shows a dialog when pasting text in the game | Listening to paste events | | [pasting.js](pasting.js) | Shows a dialog when pasting text in the game | Listening to paste events |
| [sandbox.js](sandbox.js) | Makes blueprints free and always unlocked | Overriding builtin methods |
### Advanced Examples ### Advanced Examples

View File

@ -6,6 +6,7 @@ const METADATA = {
version: "1", version: "1",
id: "add-building-basic", id: "add-building-basic",
description: "Shows how to add a new basic building", description: "Shows how to add a new basic building",
minimumGameVersion: ">=1.5.0",
}; };
class MetaDemoModBuilding extends shapez.ModMetaBuilding { class MetaDemoModBuilding extends shapez.ModMetaBuilding {

View File

@ -7,6 +7,7 @@ const METADATA = {
id: "add-building-extended", id: "add-building-extended",
description: description:
"Shows how to add a new building with logic, in this case it flips/mirrors shapez from top to down", "Shows how to add a new building with logic, in this case it flips/mirrors shapez from top to down",
minimumGameVersion: ">=1.5.0",
}; };
// Declare a new type of item processor // Declare a new type of item processor

View File

@ -6,6 +6,7 @@ const METADATA = {
version: "1", version: "1",
id: "base", id: "base",
description: "The most basic mod", description: "The most basic mod",
minimumGameVersion: ">=1.5.0",
}; };
class Mod extends shapez.Mod { class Mod extends shapez.Mod {

View File

@ -6,6 +6,7 @@ const METADATA = {
version: "1", version: "1",
id: "patch-methods", id: "patch-methods",
description: "Shows how to patch existing methods to change the game by making the belts cost shapes", description: "Shows how to patch existing methods to change the game by making the belts cost shapes",
minimumGameVersion: ">=1.5.0",
}; };
class Mod extends shapez.Mod { class Mod extends shapez.Mod {

View File

@ -6,6 +6,7 @@ const METADATA = {
version: "1", version: "1",
id: "class-extensions", id: "class-extensions",
description: "Shows how to extend builtin classes", description: "Shows how to extend builtin classes",
minimumGameVersion: ">=1.5.0",
}; };
const BeltExtension = ({ $super, $old }) => ({ const BeltExtension = ({ $super, $old }) => ({

View File

@ -6,6 +6,7 @@ const METADATA = {
version: "1", version: "1",
id: "custom-css", id: "custom-css",
description: "Shows how to add custom css", description: "Shows how to add custom css",
minimumGameVersion: ">=1.5.0",
}; };
class Mod extends shapez.Mod { class Mod extends shapez.Mod {

View File

@ -6,6 +6,7 @@ const METADATA = {
version: "1", version: "1",
id: "base", id: "base",
description: "Displays an indicator on every item processing building when its working", description: "Displays an indicator on every item processing building when its working",
minimumGameVersion: ">=1.5.0",
}; };
class ItemProcessorStatusGameSystem extends shapez.GameSystem { class ItemProcessorStatusGameSystem extends shapez.GameSystem {

View File

@ -6,6 +6,7 @@ const METADATA = {
version: "1", version: "1",
id: "base", id: "base",
description: "Shows how to add a new keybinding", description: "Shows how to add a new keybinding",
minimumGameVersion: ">=1.5.0",
}; };
class Mod extends shapez.Mod { class Mod extends shapez.Mod {

View File

@ -6,6 +6,7 @@ const METADATA = {
version: "1", version: "1",
id: "custom-sub-shapes", id: "custom-sub-shapes",
description: "Shows how to add custom sub shapes", description: "Shows how to add custom sub shapes",
minimumGameVersion: ">=1.5.0",
}; };
class Mod extends shapez.Mod { class Mod extends shapez.Mod {

View File

@ -6,6 +6,7 @@ const METADATA = {
version: "1", version: "1",
id: "custom-theme", id: "custom-theme",
description: "Shows how to add a custom game theme", description: "Shows how to add a custom game theme",
minimumGameVersion: ">=1.5.0",
}; };
class Mod extends shapez.Mod { class Mod extends shapez.Mod {

View File

@ -6,6 +6,7 @@ const METADATA = {
version: "1", version: "1",
id: "mod-settings", id: "mod-settings",
description: "Shows how to add settings to your mod", description: "Shows how to add settings to your mod",
minimumGameVersion: ">=1.5.0",
settings: { settings: {
timesLaunched: 0, timesLaunched: 0,

View File

@ -6,6 +6,7 @@ const METADATA = {
version: "1", version: "1",
id: "modify-existing-building", id: "modify-existing-building",
description: "Shows how to modify an existing building", description: "Shows how to modify an existing building",
minimumGameVersion: ">=1.5.0",
}; };
class Mod extends shapez.Mod { class Mod extends shapez.Mod {

View File

@ -6,6 +6,7 @@ const METADATA = {
version: "1", version: "1",
id: "modify-theme", id: "modify-theme",
description: "Shows how to modify builtin themes", description: "Shows how to modify builtin themes",
minimumGameVersion: ">=1.5.0",
}; };
class Mod extends shapez.Mod { class Mod extends shapez.Mod {

View File

@ -6,6 +6,7 @@ const METADATA = {
version: "1", version: "1",
id: "modify-ui", id: "modify-ui",
description: "Shows how to modify a builtin game state, in this case the main menu", description: "Shows how to modify a builtin game state, in this case the main menu",
minimumGameVersion: ">=1.5.0",
}; };
class Mod extends shapez.Mod { class Mod extends shapez.Mod {

View File

@ -6,6 +6,7 @@ const METADATA = {
version: "1", version: "1",
id: "new-item-type", id: "new-item-type",
description: "Shows how to add a new item type (fluid)", description: "Shows how to add a new item type (fluid)",
minimumGameVersion: ">=1.5.0",
}; };
// Define which fluid types there are // Define which fluid types there are

View File

@ -7,6 +7,8 @@ const METADATA = {
id: "notification-blocks", id: "notification-blocks",
description: description:
"Adds a new building to the wires layer, 'Notification Blocks' which show a custom notification when they get a truthy signal.", "Adds a new building to the wires layer, 'Notification Blocks' which show a custom notification when they get a truthy signal.",
minimumGameVersion: ">=1.5.0",
}; };
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////

View File

@ -6,6 +6,7 @@ const METADATA = {
version: "1", version: "1",
id: "pasting", id: "pasting",
description: "Shows how to properly receive paste events ingame", description: "Shows how to properly receive paste events ingame",
minimumGameVersion: ">=1.5.0",
}; };
class Mod extends shapez.Mod { class Mod extends shapez.Mod {

View File

@ -6,6 +6,7 @@ const METADATA = {
version: "1", version: "1",
id: "replace-builtin-sprites", id: "replace-builtin-sprites",
description: "Shows how to replace builtin sprites", description: "Shows how to replace builtin sprites",
minimumGameVersion: ">=1.5.0",
}; };
class Mod extends shapez.Mod { class Mod extends shapez.Mod {

21
mod_examples/sandbox.js Normal file
View File

@ -0,0 +1,21 @@
// @ts-nocheck
const METADATA = {
website: "https://tobspr.io",
author: "tobspr",
name: "Sandbox",
version: "1",
id: "sandbox",
description: "Blueprints are always unlocked and cost no money, also all buildings are unlocked",
minimumGameVersion: ">=1.5.0",
};
class Mod extends shapez.Mod {
init() {
this.modInterface.replaceMethod(shapez.Blueprint, "getCost", function () {
return 0;
});
this.modInterface.replaceMethod(shapez.HubGoals, "isRewardUnlocked", function () {
return true;
});
}
}

View File

@ -6,6 +6,7 @@ const METADATA = {
version: "1", version: "1",
id: "translations", id: "translations",
description: "Shows how to add and modify translations", description: "Shows how to add and modify translations",
minimumGameVersion: ">=1.5.0",
}; };
class Mod extends shapez.Mod { class Mod extends shapez.Mod {

View File

@ -7,6 +7,8 @@ const METADATA = {
id: "usage-statistics", id: "usage-statistics",
description: description:
"Shows how to add a new component to the game, how to save additional data and how to add custom logic and drawings", "Shows how to add a new component to the game, how to save additional data and how to add custom logic and drawings",
minimumGameVersion: ">=1.5.0",
}; };
/** /**

View File

@ -56,6 +56,7 @@
"promise-polyfill": "^8.1.0", "promise-polyfill": "^8.1.0",
"query-string": "^6.8.1", "query-string": "^6.8.1",
"rusha": "^0.8.13", "rusha": "^0.8.13",
"semver": "^7.3.5",
"serialize-error": "^3.0.0", "serialize-error": "^3.0.0",
"strictdom": "^1.0.1", "strictdom": "^1.0.1",
"string-replace-webpack-plugin": "^0.1.3", "string-replace-webpack-plugin": "^0.1.3",

View File

@ -199,10 +199,6 @@
transform: translateX(50%) rotate(-7deg) scale(1.1); transform: translateX(50%) rotate(-7deg) scale(1.1);
} }
} }
@include DarkThemeOverride {
color: $colorBlueBright;
}
} }
} }
@ -326,6 +322,7 @@
/* @load-async */ /* @load-async */
background-image: uiResource("icons/edit_key.png") !important; background-image: uiResource("icons/edit_key.png") !important;
} }
@include DarkThemeInvert;
} }
} }
@ -354,13 +351,14 @@
box-sizing: border-box; box-sizing: border-box;
@include PlainText; @include PlainText;
@include S(margin-bottom, 5px); @include S(margin-bottom, 5px);
display: grid; display: flex;
grid-template-columns: 1fr auto auto; flex-direction: column;
@include S(grid-gap, 5px);
.author, .author,
.version { .version {
@include SuperSmallText; @include SuperSmallText;
align-self: end;
opacity: 0.4;
} }
.name { .name {
overflow: hidden; overflow: hidden;
@ -457,19 +455,19 @@
.newGameButton { .newGameButton {
@include IncreasedClickArea(0px); @include IncreasedClickArea(0px);
@include S(margin-left, 15px); @include S(margin-left, 10px);
} }
.modsButton { .modsButton {
@include IncreasedClickArea(0px); @include IncreasedClickArea(0px);
@include S(margin-left, 15px); @include S(margin-left, 10px);
@include S(width, 20px); // @include S(width, 20px);
& { // & {
/* @load-async */ // /* @load-async */
background-image: uiResource("res/ui/icons/mods_white.png") !important; // background-image: uiResource("res/ui/icons/mods_white.png") !important;
} // }
background-position: center center; background-position: center center;
background-size: D(15px); background-size: D(15px);
background-color: $modsColor !important; background-color: $modsColor !important;
@ -837,6 +835,23 @@
} }
} }
.modsOverview {
background: $darkModeControlsBackground;
.modsList {
border-color: darken($darkModeControlsBackground, 5);
.mod {
background: darken($darkModeControlsBackground, 5);
color: white;
}
}
.dlcHint {
color: $accentColorBright;
}
}
.footer { .footer {
> a, > a,
.sidelinks > a { .sidelinks > a {

View File

@ -62,6 +62,11 @@
@include S(margin-top, 100px); @include S(margin-top, 100px);
color: lighten($accentColorDark, 15); color: lighten($accentColorDark, 15);
button {
@include S(margin-top, 10px);
@include S(padding, 10px, 20px);
}
&::before { &::before {
@include S(margin-bottom, 15px); @include S(margin-bottom, 15px);
content: ""; content: "";
@ -94,6 +99,10 @@
display: grid; display: grid;
grid-template-columns: 1fr D(100px) D(80px) D(50px); grid-template-columns: 1fr D(100px) D(80px) D(50px);
@include DarkThemeOverride {
background: darken($darkModeControlsBackground, 5);
}
.checkbox { .checkbox {
align-self: center; align-self: center;
justify-self: center; justify-self: center;

View File

@ -28,6 +28,8 @@ export const THIRDPARTY_URLS = {
25: "https://www.youtube.com/watch?v=7OCV1g40Iew&", 25: "https://www.youtube.com/watch?v=7OCV1g40Iew&",
26: "https://www.youtube.com/watch?v=gfm6dS1dCoY", 26: "https://www.youtube.com/watch?v=gfm6dS1dCoY",
}, },
modBrowser: "https://shapez.mod.io/?preview=f55f6304ca4873d9a25f3b575571b948",
}; };
// export const A_B_TESTING_LINK_TYPE = Math.random() > 0.95 ? "steam_1_pr" : "steam_2_npr"; // export const A_B_TESTING_LINK_TYPE = Math.random() > 0.95 ? "steam_1_pr" : "steam_2_npr";

View File

@ -94,11 +94,12 @@ export class HUDEntityDebugger extends BaseHUDPart {
<div>`; <div>`;
for (const property in val) { for (const property in val) {
const isRoot = val[property] == this.root; let hiddenValue = null;
const isRecursive = recursion.includes(val[property]); if (val[property] == this.root) {
hiddenValue = "<root>";
let hiddenValue = isRoot ? "<root>" : null; } else if (val[property] instanceof Node) {
if (isRecursive) { hiddenValue = `<${val[property].constructor.name}>`;
} else if (recursion.includes(val[property])) {
// Avoid recursion by not "expanding" object more than once // Avoid recursion by not "expanding" object more than once
hiddenValue = "<recursion>"; hiddenValue = "<recursion>";
} }

View File

@ -50,8 +50,13 @@ export class StorageSystem extends GameSystemWithFilter {
let targetAlpha = storageComp.storedCount > 0 ? 1 : 0; let targetAlpha = storageComp.storedCount > 0 ? 1 : 0;
storageComp.overlayOpacity = lerp(storageComp.overlayOpacity, targetAlpha, 0.05); storageComp.overlayOpacity = lerp(storageComp.overlayOpacity, targetAlpha, 0.05);
pinsComp.slots[0].value = storageComp.storedItem; // a wired pins component is not guaranteed, but if its there, set the value
pinsComp.slots[1].value = storageComp.getIsFull() ? BOOL_TRUE_SINGLETON : BOOL_FALSE_SINGLETON; if (pinsComp) {
pinsComp.slots[0].value = storageComp.storedItem;
pinsComp.slots[1].value = storageComp.getIsFull()
? BOOL_TRUE_SINGLETON
: BOOL_FALSE_SINGLETON;
}
} }
} }

View File

@ -31,6 +31,12 @@ import { BaseHUDPart } from "../game/hud/base_hud_part";
* @typedef {{new(...args: any[]): any, prototype: any}} constructable * @typedef {{new(...args: any[]): any, prototype: any}} constructable
*/ */
/**
* @template {(...args: any) => any} F The function
* @template {object} T The value of this
* @typedef {(this: T, ...args: Parameters<F>) => ReturnType<F>} bindThis
*/
/** /**
* @template {(...args: any[]) => any} F * @template {(...args: any[]) => any} F
* @template P * @template P
@ -400,7 +406,7 @@ export class ModInterface {
* @template {extendsPrams<P[M]>} O the method that will override the old one * @template {extendsPrams<P[M]>} O the method that will override the old one
* @param {C} classHandle * @param {C} classHandle
* @param {M} methodName * @param {M} methodName
* @param {beforePrams<O, P[M]>} override * @param {bindThis<beforePrams<O, P[M]>, InstanceType<C>>} override
*/ */
replaceMethod(classHandle, methodName, override) { replaceMethod(classHandle, methodName, override) {
const oldMethod = classHandle.prototype[methodName]; const oldMethod = classHandle.prototype[methodName];
@ -418,7 +424,7 @@ export class ModInterface {
* @template {extendsPrams<P[M]>} O the method that will run before the old one * @template {extendsPrams<P[M]>} O the method that will run before the old one
* @param {C} classHandle * @param {C} classHandle
* @param {M} methodName * @param {M} methodName
* @param {O} executeBefore * @param {bindThis<O, InstanceType<C>>} executeBefore
*/ */
runBeforeMethod(classHandle, methodName, executeBefore) { runBeforeMethod(classHandle, methodName, executeBefore) {
const oldHandle = classHandle.prototype[methodName]; const oldHandle = classHandle.prototype[methodName];
@ -437,7 +443,7 @@ export class ModInterface {
* @template {extendsPrams<P[M]>} O the method that will run before the old one * @template {extendsPrams<P[M]>} O the method that will run before the old one
* @param {C} classHandle * @param {C} classHandle
* @param {M} methodName * @param {M} methodName
* @param {O} executeAfter * @param {bindThis<O, InstanceType<C>>} executeAfter
*/ */
runAfterMethod(classHandle, methodName, executeAfter) { runAfterMethod(classHandle, methodName, executeAfter) {
const oldHandle = classHandle.prototype[methodName]; const oldHandle = classHandle.prototype[methodName];

View File

@ -10,6 +10,9 @@ import { Mod } from "./mod";
import { ModInterface } from "./mod_interface"; import { ModInterface } from "./mod_interface";
import { MOD_SIGNALS } from "./mod_signals"; import { MOD_SIGNALS } from "./mod_signals";
import semverValidRange from "semver/ranges/valid";
import semverSatisifies from "semver/functions/satisfies";
const LOG = createLogger("mods"); const LOG = createLogger("mods");
/** /**
@ -20,6 +23,7 @@ const LOG = createLogger("mods");
* website: string; * website: string;
* description: string; * description: string;
* id: string; * id: string;
* minimumGameVersion?: string;
* settings: [] * settings: []
* }} ModMetadata * }} ModMetadata
*/ */
@ -158,6 +162,27 @@ export class ModLoader {
const { modClass, meta } = this.modLoadQueue[i]; const { modClass, meta } = this.modLoadQueue[i];
const modDataFile = "modsettings_" + meta.id + "__" + meta.version + ".json"; const modDataFile = "modsettings_" + meta.id + "__" + meta.version + ".json";
if (meta.minimumGameVersion) {
console.warn(meta.minimumGameVersion, G_BUILD_VERSION);
const minimumGameVersion = meta.minimumGameVersion;
if (!semverValidRange(minimumGameVersion)) {
alert("Mod " + meta.id + " has invalid minimumGameVersion: " + minimumGameVersion);
continue;
}
if (!semverSatisifies(G_BUILD_VERSION, minimumGameVersion)) {
alert(
"Mod '" +
meta.id +
"' is incompatible with this version of the game: \n\n" +
"Mod requires version " +
minimumGameVersion +
" but this game has version " +
G_BUILD_VERSION
);
continue;
}
}
let settings = meta.settings; let settings = meta.settings;
if (meta.settings) { if (meta.settings) {

View File

@ -161,7 +161,10 @@ export class MainMenuState extends GameState {
${MODS.mods ${MODS.mods
.map(mod => { .map(mod => {
return ` return `
<div class="mod">${mod.metadata.name} @ v${mod.metadata.version}</div> <div class="mod">
<div class="name">${mod.metadata.name}</div>
<div class="author">by ${mod.metadata.author}</div>
</div>
`; `;
}) })
.join("")} .join("")}
@ -413,7 +416,10 @@ export class MainMenuState extends GameState {
} }
// Mods // Mods
this.trackClicks(makeButton(outerDiv, ["modsButton", "styledButton"], "&nbsp;"), this.onModsClicked); this.trackClicks(
makeButton(outerDiv, ["modsButton", "styledButton"], T.mods.title),
this.onModsClicked
);
buttonContainer.appendChild(outerDiv); buttonContainer.appendChild(outerDiv);
} }

View File

@ -18,6 +18,11 @@ export class ModsState extends TextualGameState {
<h1><button class="backButton"></button> ${this.getStateHeaderTitle()}</h1> <h1><button class="backButton"></button> ${this.getStateHeaderTitle()}</h1>
<div class="actions"> <div class="actions">
${
(G_IS_STANDALONE || G_IS_DEV) && MODS.mods.length > 0
? `<button class="styledButton browseMods">${T.mods.browseMods}</button>`
: ""
}
${ ${
G_IS_STANDALONE || G_IS_DEV G_IS_STANDALONE || G_IS_DEV
? `<button class="styledButton openModsFolder">${T.mods.openFolder}</button>` ? `<button class="styledButton openModsFolder">${T.mods.openFolder}</button>`
@ -53,8 +58,9 @@ export class ModsState extends TextualGameState {
return ` return `
<div class="modsStats noMods"> <div class="modsStats noMods">
${T.mods.modsInfo} ${T.mods.modsInfo}
<button class="styledButton browseMods">${T.mods.browseMods}</button>
</div> </div>
`; `;
@ -100,6 +106,10 @@ export class ModsState extends TextualGameState {
if (openModsFolder) { if (openModsFolder) {
this.trackClicks(openModsFolder, this.openModsFolder); this.trackClicks(openModsFolder, this.openModsFolder);
} }
const browseMods = this.htmlElement.querySelector(".browseMods");
if (browseMods) {
this.trackClicks(browseMods, this.openBrowseMods);
}
const checkboxes = this.htmlElement.querySelectorAll(".checkbox"); const checkboxes = this.htmlElement.querySelectorAll(".checkbox");
Array.from(checkboxes).forEach(checkbox => { Array.from(checkboxes).forEach(checkbox => {
@ -119,6 +129,11 @@ export class ModsState extends TextualGameState {
ipcRenderer.invoke("open-mods-folder"); ipcRenderer.invoke("open-mods-folder");
} }
openBrowseMods() {
this.app.analytics.trackUiClick("mods_sbrowse_link");
this.app.platformWrapper.openExternalLink(THIRDPARTY_URLS.modBrowser);
}
onSteamLinkClicked() { onSteamLinkClicked() {
this.app.analytics.trackUiClick("mods_steam_link"); this.app.analytics.trackUiClick("mods_steam_link");
this.app.platformWrapper.openExternalLink( this.app.platformWrapper.openExternalLink(

View File

@ -1098,6 +1098,7 @@ mods:
version: Version version: Version
openFolder: Open Mods Folder openFolder: Open Mods Folder
folderOnlyStandalone: Opening the mod folder is only possible when running the standalone. folderOnlyStandalone: Opening the mod folder is only possible when running the standalone.
browseMods: Browse Mods
modsInfo: >- modsInfo: >-
To install and manage mods, copy them to the mods folder within the game directory. You can also use the 'Open Mods Folder' button on the top right. To install and manage mods, copy them to the mods folder within the game directory. You can also use the 'Open Mods Folder' button on the top right.

View File

@ -5245,6 +5245,13 @@ lru-cache@^5.1.1:
dependencies: dependencies:
yallist "^3.0.2" yallist "^3.0.2"
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"
lz-string@^1.4.4: lz-string@^1.4.4:
version "1.4.4" version "1.4.4"
resolved "https://registry.npmjs.org/lz-string/-/lz-string-1.4.4.tgz" resolved "https://registry.npmjs.org/lz-string/-/lz-string-1.4.4.tgz"
@ -7496,6 +7503,13 @@ semver@^7.2.1, semver@^7.3.2:
resolved "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz" resolved "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz"
integrity sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ== integrity sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==
semver@^7.3.5:
version "7.3.5"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7"
integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==
dependencies:
lru-cache "^6.0.0"
send@0.17.1: send@0.17.1:
version "0.17.1" version "0.17.1"
resolved "https://registry.npmjs.org/send/-/send-0.17.1.tgz" resolved "https://registry.npmjs.org/send/-/send-0.17.1.tgz"
@ -8800,6 +8814,11 @@ yallist@^3.0.2:
resolved "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz" resolved "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz"
integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==
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==
yaml-js@^0.1.3: yaml-js@^0.1.3:
version "0.1.5" version "0.1.5"
resolved "https://registry.npmjs.org/yaml-js/-/yaml-js-0.1.5.tgz" resolved "https://registry.npmjs.org/yaml-js/-/yaml-js-0.1.5.tgz"