(null);
+
+
+ const handleEditorMount = useCallback((editor: MonacoEditor) => {
+ editorRef.current = editor;
+ }, []);
+
+ const result = usePlatformScript(yaml);
+
+ return (
+ <>
+
+ {result.loading && (
...loading
)}
+ onChange(value)}
+ value={yaml}
+ />
+
+ >
+ );
+}
diff --git a/packages/app/src/components/catalog/EntityPage.tsx b/packages/app/src/components/catalog/EntityPage.tsx
index 984e450897..11efb67b89 100644
--- a/packages/app/src/components/catalog/EntityPage.tsx
+++ b/packages/app/src/components/catalog/EntityPage.tsx
@@ -29,7 +29,6 @@ import {
EntityDependsOnResourcesCard,
EntityHasComponentsCard,
EntityHasResourcesCard,
- EntityHasSubcomponentsCard,
EntityHasSystemsCard,
EntityLayout,
EntityLinksCard,
@@ -54,12 +53,13 @@ import {
} from '@backstage/plugin-org';
import { EntityTechdocsContent } from '@backstage/plugin-techdocs';
import { EmptyState } from '@backstage/core-components';
-import { HumanitecCardComponent } from '@frontside/backstage-plugin-humanitec';
import { TechDocsAddons } from '@backstage/plugin-techdocs-react';
import { ReportIssue } from '@backstage/plugin-techdocs-module-addons-contrib';
+import { OverviewContent } from './OverviewContent';
+import { WebsiteLayout } from './WebsiteLayout';
-const techdocsContent = (
+export const techdocsContent = (
@@ -67,7 +67,7 @@ const techdocsContent = (
);
-const cicdContent = (
+export const cicdContent = (
// This is an example of how you can implement your company's logic in entity page.
// You can for example enforce that all components of type 'service' should use GitHubActions
@@ -94,7 +94,7 @@ const cicdContent = (
);
-const entityWarningContent = (
+export const entityWarningContent = (
<>
@@ -114,28 +114,10 @@ const entityWarningContent = (
>
);
-const overviewContent = (
-
- {entityWarningContent}
-
-
-
-
-
-
-
-
-
-
-
-
-
-);
-
const serviceEntityPage = (
- {overviewContent}
+
@@ -170,33 +152,6 @@ const serviceEntityPage = (
);
-const websiteEntityPage = (
-
-
- {overviewContent}
-
-
-
- {cicdContent}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {techdocsContent}
-
-
-);
-
/**
* NOTE: This page is designed to work on small screens such as mobile devices.
* This is based on Material UI Grid. If breakpoints are used, each grid item must set the `xs` prop to a column size or to `true`,
@@ -207,7 +162,7 @@ const websiteEntityPage = (
const defaultEntityPage = (
- {overviewContent}
+
@@ -223,7 +178,7 @@ const componentPage = (
- {websiteEntityPage}
+
{defaultEntityPage}
diff --git a/packages/app/src/components/catalog/OverviewContent.tsx b/packages/app/src/components/catalog/OverviewContent.tsx
new file mode 100644
index 0000000000..f424ff9d58
--- /dev/null
+++ b/packages/app/src/components/catalog/OverviewContent.tsx
@@ -0,0 +1,70 @@
+import React, { useMemo, useState } from 'react';
+import { useEntity } from '@backstage/plugin-catalog-react';
+import { PSOverviewContent } from './PSOverviewContent';
+import { stringify } from 'yaml';
+import { Grid } from '@material-ui/core';
+import { PlatformScriptEditor } from '../PlatformScriptPage';
+
+const defaultOverviewContent = `
+$Grid:
+ container: true
+ spacing: 3
+ alignItems: stretch
+children:
+ - $Grid:
+ item: true
+ md: 6
+ children:
+ - $EntityAboutCard:
+ variant: gridItem
+ - $Grid:
+ item: true
+ md: 6
+ children:
+ $HumanitecCardComponent: true
+ - $Grid:
+ item: true
+ md: 4
+ xs: 12
+ children:
+ $EntityLinksCard: true
+ - $Grid:
+ item: true
+ md: 8
+ xs: 12
+ children:
+ $EntityHasSubcomponentsCard:
+ variant: gridItem
+`
+
+export function OverviewContent({ isEditing }: { isEditing?: boolean }) {
+ const { entity } = useEntity();
+
+ const overviewContentLayout = useMemo(() => {
+ if (entity?.spec?.overviewContentLayout) {
+ return stringify(entity?.spec?.overviewContentLayout);
+ }
+ return defaultOverviewContent;
+ }, [entity?.spec?.overviewContentLayout]);
+
+ const [yaml, setYaml] = useState(overviewContentLayout);
+
+ if (isEditing) {
+ return (
+
+
+
+
+
+
+
+
+ )
+ }
+
+ return ;
+}
diff --git a/packages/app/src/components/catalog/PSOverviewContent.tsx b/packages/app/src/components/catalog/PSOverviewContent.tsx
new file mode 100644
index 0000000000..7464999fea
--- /dev/null
+++ b/packages/app/src/components/catalog/PSOverviewContent.tsx
@@ -0,0 +1,16 @@
+import React from 'react';
+import { usePlatformScript } from '../PlatformScriptPage';
+
+export function PSOverviewContent({ yaml }: { yaml: string; }) {
+ const result = usePlatformScript(yaml);
+
+ if (result.loading) {
+ return <>Loading...>;
+ }
+
+ if (result.error) {
+ return <>{result.error.message}>;
+ }
+
+ return <>{result.value}>;
+}
diff --git a/packages/app/src/components/catalog/WebsiteLayout.tsx b/packages/app/src/components/catalog/WebsiteLayout.tsx
new file mode 100644
index 0000000000..06585c26e6
--- /dev/null
+++ b/packages/app/src/components/catalog/WebsiteLayout.tsx
@@ -0,0 +1,47 @@
+import React from 'react';
+import { Grid } from '@material-ui/core';
+import {
+ EntityDependsOnComponentsCard,
+ EntityDependsOnResourcesCard, EntityLayout
+} from '@backstage/plugin-catalog';
+import { OverviewContent } from './OverviewContent';
+import DashboardIcon from '@material-ui/icons/Dashboard';
+import { useToggle } from '../../hooks';
+import { cicdContent, techdocsContent } from './EntityPage';
+
+export function WebsiteLayout() {
+ const [isEditing, toggleIsEditing] = useToggle();
+
+ return (
+ toggleIsEditing()
+ }
+ ]}>
+
+
+
+
+
+ {cicdContent}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {techdocsContent}
+
+
+ );
+}
diff --git a/packages/app/src/components/catalog/notes.yaml b/packages/app/src/components/catalog/notes.yaml
new file mode 100644
index 0000000000..1b81fa622d
--- /dev/null
+++ b/packages/app/src/components/catalog/notes.yaml
@@ -0,0 +1,28 @@
+$let:
+ EntityLinksEmptyState:
+ $():
+ $<>:
+ - $Typography:
+ variant: 'body1'
+ children:
+ "No links defined for this entity. You can add links to your entity YAML as shown in the highlighted example below:"
+ - $div:
+ children:
+ $CodeSnippet:
+ language: 'yaml'
+ text: >-
+ metadata:
+ name: example
+ links:
+ - url: https://dashboard.example.com
+ title: My Dashboard
+ icon: dashboard
+ showLineNumbers: true
+ highlightedNumbers: [3, 4, 5, 6]
+ - $Button:
+ text: "Read More"
+ variant: "contained"
+ color: "primary"
+ target: "_blank"
+ href: "https://backstage.io/docs/features/software-catalog/descriptor-format#links-optional"
+$do:
\ No newline at end of file
diff --git a/packages/app/src/components/globals.tsx b/packages/app/src/components/globals.tsx
new file mode 100644
index 0000000000..6a37df0baa
--- /dev/null
+++ b/packages/app/src/components/globals.tsx
@@ -0,0 +1,211 @@
+import React from 'react';
+import { assert } from 'assert-ts';
+import type { ComponentType } from 'react';
+import type { PlatformScript, PSMap, PSValue } from 'platformscript';
+import * as ps from 'platformscript';
+import { Button, Grid, Typography } from '@material-ui/core';
+import { CodeSnippet } from '@backstage/core-components';
+import { EntityAboutCard, EntityHasSubcomponentsCard, EntityLinksCard } from '@backstage/plugin-catalog';
+import { HumanitecCardComponent } from '@frontside/backstage-plugin-humanitec';
+
+type ComponentProps = C extends ComponentType
+? P
+: never;
+
+type TypographyProps = ComponentProps;
+type ButtonProps = ComponentProps;
+
+type Variant = TypographyProps['variant'];
+
+export function lookup(key: string, map: PSMap): PSValue | void {
+ for (const entry of map.value.entries()) {
+ const [k, value] = entry;
+ if (k.value.toString() === key) {
+ return value;
+ }
+ }
+ return void 0;
+}
+
+function createReactComponent(type: any) {
+ return ps.fn(function* ({ arg, env, rest }) {
+
+ const $arg: PSValue = yield* env.eval(arg);
+ if (rest.type === "map") {
+ // add key prop to each item in children array
+ for (const [key, value] of rest.value.entries()) {
+ if (key.type === "string" && key.value === "children" && value.type === "list") {
+ let index = 0;
+ for (const item of value.value) {
+ if (item.type === "map") {
+ let found;
+ for (const [propKey] of item.value.entries()) {
+ if (propKey.value === "key") {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ item.value.set(
+ { type: "string", value: "key" },
+ { type: "string", value: String(index) }
+ )
+ }
+ }
+ index++;
+ }
+ }
+ }
+ }
+ const $options = yield* env.eval(rest);
+
+ const props: Record = {};
+ let children = [];
+
+ switch ($arg.type) {
+ case "map":
+ for (const [key, value] of $arg.value.entries()) {
+ props[String(key.value)] = value.value
+ }
+ if ($options.type === "map") {
+ const key = lookup('key', $options);
+ if (!!key) {
+ props.key = key.value
+ }
+ const _children = lookup('children', $options);
+ if (!!_children) {
+ if (_children.type === "list") {
+ children = _children.value.map(value => value.value)
+ } else {
+ children = _children.value;
+ }
+ }
+ }
+ break;
+ case "list":
+ children = $arg.value.map(value => value.value);
+ break;
+ default:
+ children = $arg.value;
+ }
+
+ return ps.external(React.createElement(type, props, children))
+ });
+};
+
+export function globals(interpreter: PlatformScript) {
+ return ps.map({
+ div: createReactComponent('div'),
+ Grid: createReactComponent(Grid),
+ EntityAboutCard: createReactComponent(EntityAboutCard),
+ HumanitecCardComponent: createReactComponent(HumanitecCardComponent),
+ EntityLinksCard: createReactComponent(EntityLinksCard),
+ EntityHasSubcomponentsCard: createReactComponent(EntityHasSubcomponentsCard),
+ alert: ps.fn(function* ({ arg, env }) {
+ const $arg = yield* env.eval(arg);
+
+ const message = String($arg.value);
+
+ // eslint-disable-next-line no-alert
+ window.alert(message);
+
+ return ps.boolean(true);
+ }),
+ '<>': ps.fn(function* ({ arg, env }) {
+ const $arg = yield* env.eval(arg);
+
+ assert($arg.type === 'list', `a fragment must contain a list, found ${$arg.type}`);
+
+ // TODO: investigate types
+ // A JSX element has a `key` field which defaults to null
+ const elements = $arg.value.map((psValue: { value: any }, i: number) => ({ ...psValue.value, key: psValue.value.key !== null ? psValue.value.key : i }));
+
+ return ps.external(<>{elements}>);
+ }),
+ CodeSnippet: ps.fn(function* ({ arg, env }) {
+ const $arg = yield* env.eval(arg);
+ let text = '';
+ let showLineNumbers: boolean | undefined = undefined;
+ let highlightedNumbers: number[] = [];
+ let language = ''
+
+ if ($arg.type === 'map') {
+ text = lookup('text', $arg)?.value;
+ showLineNumbers = lookup('showLineNumbers', $arg)?.value;
+ highlightedNumbers = lookup('highlightedNumbers', $arg)?.value.map((v: any) => v.value);
+ language = lookup('language', $arg)?.value;
+ }
+
+ return ps.external(
+
+ )
+ }),
+ Typography: ps.fn(function* ({ arg, env }) {
+ const $arg = yield* env.eval(arg);
+ let variant = '';
+ let children: any = '';
+
+ switch ($arg.type) {
+ case 'map':
+ children = lookup('children', $arg);
+
+ variant = lookup('variant', $arg)?.value;
+
+ break;
+ default:
+ children = String($arg.type);
+ }
+
+ return ps.external({children.value});
+ },),
+ Button: ps.fn(function* ({ arg, env }) {
+ const $arg = yield* env.eval(arg);
+
+ let children = '';
+ let clickHandler = (): void => void 0;
+ let variant: Variant = undefined;
+ let color = '';
+ let href: string | undefined = undefined;
+
+ switch ($arg.type) {
+ case 'string':
+ children = $arg.value;
+ break;
+ case 'map': {
+ children = lookup('text', $arg)?.value ?? '';
+ variant = lookup('variant', $arg)?.value ?? '';
+ color = lookup('color', $arg)?.value ?? '';
+ href = lookup('href', $arg)?.value ?? '';
+
+ const psClickHandler = lookup('onClick', $arg);
+
+ if (psClickHandler) {
+ assert(psClickHandler.type === 'fn', `onClick must be a function but is ${psClickHandler.type}`);
+
+ clickHandler = () => {
+ interpreter.run(() => env.call(psClickHandler, ps.boolean(true)));
+ };
+ }
+
+ break;
+ }
+ default:
+ children = String($arg.type);
+ }
+
+ return ps.external(
+ );
+ },)
+ })
+}
\ No newline at end of file
diff --git a/packages/app/src/components/yaml-editor/YamlEditor.tsx b/packages/app/src/components/yaml-editor/YamlEditor.tsx
new file mode 100644
index 0000000000..e38d055101
--- /dev/null
+++ b/packages/app/src/components/yaml-editor/YamlEditor.tsx
@@ -0,0 +1,23 @@
+import React from 'react';
+import Editor from "@monaco-editor/react";
+import type { EditorProps, OnMount, BeforeMount, OnChange } from "@monaco-editor/react";
+import { handleEditorWillMount, LanguageId } from './editor-before-mount';
+
+export type YAMLEditorProps = Pick;
+export type MonacoEditor = Parameters[0];
+export type OnChangeArgs = Parameters;
+export type Monaco = Parameters[0];
+
+export function YAMLEditor({ onMount, onChange, defaultValue, value }: YAMLEditorProps): JSX.Element {
+ return (
+
+ );
+}
\ No newline at end of file
diff --git a/packages/app/src/components/yaml-editor/editor-before-mount.ts b/packages/app/src/components/yaml-editor/editor-before-mount.ts
new file mode 100644
index 0000000000..6586d81ec5
--- /dev/null
+++ b/packages/app/src/components/yaml-editor/editor-before-mount.ts
@@ -0,0 +1,44 @@
+import type { Monaco } from '@monaco-editor/react';
+
+export const LanguageId = 'yaml';
+
+export function handleEditorWillMount(monaco: Monaco) {
+ monaco.languages.setLanguageConfiguration(LanguageId, {
+ comments: {
+ lineComment: '#',
+ },
+ brackets: [
+ ['{', '}'],
+ ['[', ']'],
+ ['(', ')'],
+ ],
+ autoClosingPairs: [
+ { open: '{', close: '}' },
+ { open: '[', close: ']' },
+ { open: '(', close: ')' },
+ { open: '"', close: '"' },
+ { open: "'", close: "'" },
+ ],
+ surroundingPairs: [
+ { open: '{', close: '}' },
+ { open: '[', close: ']' },
+ { open: '(', close: ')' },
+ { open: '"', close: '"' },
+ { open: "'", close: "'" },
+ ],
+
+ onEnterRules: [
+ {
+ beforeText: /:\s*$/,
+ action: { indentAction: monaco.languages.IndentAction.Indent },
+ },
+ ],
+ });
+
+ monaco.languages.register({
+ id: LanguageId,
+ extensions: ['.yaml', '.yml'],
+ aliases: ['YAML', 'yaml', 'YML', 'yml'],
+ mimetypes: ['application/x-yaml'],
+ });
+}
diff --git a/packages/app/src/hooks.ts b/packages/app/src/hooks.ts
new file mode 100644
index 0000000000..002dae6384
--- /dev/null
+++ b/packages/app/src/hooks.ts
@@ -0,0 +1,20 @@
+import { useCallback, useState } from "react";
+
+/*
+// usage
+const [isEditing, setIsEditing] = useToggle();
+
+return (
+ <>
+ {isEditing & }
+
+ >
+);
+*/
+export function useToggle(initialState = false): (boolean | (() => void))[] {
+ const [state, setState] = useState(initialState);
+
+ const toggle = useCallback(() => setState((_state) => !_state), []);
+
+ return [state, toggle];
+}
\ No newline at end of file
diff --git a/packages/backend/ps/lib/hello.yaml b/packages/backend/ps/lib/hello.yaml
new file mode 100644
index 0000000000..bb82342e2e
--- /dev/null
+++ b/packages/backend/ps/lib/hello.yaml
@@ -0,0 +1,2 @@
+-
+ $Button: Press Me
diff --git a/packages/backend/src/index.ts b/packages/backend/src/index.ts
index 79890a0713..48f4175868 100644
--- a/packages/backend/src/index.ts
+++ b/packages/backend/src/index.ts
@@ -81,6 +81,12 @@ function makeCreateEnv(config: Config) {
};
}
+import { resolvePackagePath } from '@backstage/backend-common';
+import express from 'express';
+import path from 'path';
+
+const libps = express.static(path.join(resolvePackagePath('backend'), 'ps', 'lib'))
+
async function main() {
const config = await loadBackendConfig({
argv: process.argv,
@@ -111,6 +117,7 @@ async function main() {
apiRouter.use('/effection-inspector', await effectionInspector(effectionInspectorEnv));
apiRouter.use('/humanitec', await humanitec(humanitecEnv));
apiRouter.use('/graphql', await graphql(graphqlEnv));
+ apiRouter.use('/ps/lib', libps);
apiRouter.use(notFoundHandler());
const service = createServiceBuilder(module)
diff --git a/yarn.lock b/yarn.lock
index 47b80ca011..21e6a62135 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -5655,6 +5655,21 @@
prop-types "^15.7.2"
react-is "^16.8.0 || ^17.0.0"
+"@monaco-editor/loader@^1.3.2":
+ version "1.3.2"
+ resolved "https://registry.yarnpkg.com/@monaco-editor/loader/-/loader-1.3.2.tgz#04effbb87052d19cd7d3c9d81c0635490f9bb6d8"
+ integrity sha512-BTDbpHl3e47r3AAtpfVFTlAi7WXv4UQ/xZmz8atKl4q7epQV5e7+JbigFDViWF71VBi4IIBdcWP57Hj+OWuc9g==
+ dependencies:
+ state-local "^1.0.6"
+
+"@monaco-editor/react@4.4.5":
+ version "4.4.5"
+ resolved "https://registry.yarnpkg.com/@monaco-editor/react/-/react-4.4.5.tgz#beabe491efeb2457441a00d1c7651c653697f65b"
+ integrity sha512-IImtzU7sRc66OOaQVCG+5PFHkSWnnhrUWGBuH6zNmH2h0YgmAhcjHZQc/6MY9JWEbUtVF1WPBMJ9u1XuFbRrVA==
+ dependencies:
+ "@monaco-editor/loader" "^1.3.2"
+ prop-types "^15.7.2"
+
"@mswjs/cookies@^0.1.6":
version "0.1.7"
resolved "https://registry.yarnpkg.com/@mswjs/cookies/-/cookies-0.1.7.tgz#d334081b2c51057a61c1dd7b76ca3cac02251651"
@@ -7440,13 +7455,20 @@
resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.4.tgz#cd667bcfdd025213aafb7ca5915a932590acdcdc"
integrity sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==
-"@types/react-dom@*", "@types/react-dom@<18.0.0", "@types/react-dom@^17", "@types/react-dom@^18.0.0":
+"@types/react-dom@*", "@types/react-dom@<18.0.0":
version "17.0.18"
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-17.0.18.tgz#8f7af38f5d9b42f79162eea7492e5a1caff70dc2"
integrity sha512-rLVtIfbwyur2iFKykP2w0pl/1unw26b5td16d5xMgp7/yjTHomkyxPYChFoCr/FtEX1lN9wY6lFj1qvKdS5kDw==
dependencies:
"@types/react" "^17"
+"@types/react-dom@^18.0.0":
+ version "18.0.9"
+ resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.0.9.tgz#ffee5e4bfc2a2f8774b15496474f8e7fe8d0b504"
+ integrity sha512-qnVvHxASt/H7i+XG1U1xMiY5t+IHcPGUK7TDMDzom08xa7e86eCeKOiLZezwCKVxJn6NEiiy2ekgX8aQssjIKg==
+ dependencies:
+ "@types/react" "*"
+
"@types/react-redux@^7.1.20":
version "7.1.24"
resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-7.1.24.tgz#6caaff1603aba17b27d20f8ad073e4c077e975c0"
@@ -13314,11 +13336,21 @@ graphql-ws@^5.4.1:
resolved "https://registry.yarnpkg.com/graphql-ws/-/graphql-ws-5.9.1.tgz#9c0fa48ceb695d61d574ed3ab21b426729e87f2d"
integrity sha512-mL/SWGBwIT9Meq0NlfS55yXXTOeWPMbK7bZBEZhFu46bcGk1coTx2Sdtzxdk+9yHWngD+Fk1PZDWaAutQa9tpw==
-graphql@*, graphql@16.5.0, "graphql@^15.0.0 || ^16.0.0", graphql@^15.5.1, graphql@^16.0.0, graphql@^16.3.0, graphql@^16.5.0:
+graphql@*, "graphql@^15.0.0 || ^16.0.0", graphql@^16.0.0, graphql@^16.3.0, graphql@^16.5.0:
version "16.6.0"
resolved "https://registry.yarnpkg.com/graphql/-/graphql-16.6.0.tgz#c2dcffa4649db149f6282af726c8c83f1c7c5fdb"
integrity sha512-KPIBPDlW7NxrbT/eh4qPXz5FiFdL5UbaA0XUNz2Rp3Z3hqBSkbj0GVjwFDztsWVauZUWsbKHgMg++sk8UX0bkw==
+graphql@16.5.0:
+ version "16.5.0"
+ resolved "https://registry.yarnpkg.com/graphql/-/graphql-16.5.0.tgz#41b5c1182eaac7f3d47164fb247f61e4dfb69c85"
+ integrity sha512-qbHgh8Ix+j/qY+a/ZcJnFQ+j8ezakqPiHwPiZhV/3PgGlgf96QMBB5/f2rkiC9sgLoy/xvT6TSiaf2nTHJh5iA==
+
+graphql@^15.5.1:
+ version "15.8.0"
+ resolved "https://registry.yarnpkg.com/graphql/-/graphql-15.8.0.tgz#33410e96b012fa3bdb1091cc99a94769db212b38"
+ integrity sha512-5gghUc24tP9HRznNpV2+FIoq3xKkj5dTQqf4v0CpdPbFVwFkWoxOM+o+2OC9ZSvjEMTjfmG9QT+gcvggTwW1zw==
+
gson-conform@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/gson-conform/-/gson-conform-1.0.3.tgz#6f982f98ea84199280bd48b6bfbcd0ae7447f1e2"
@@ -18826,6 +18858,13 @@ pkginfo@0.4.x, pkginfo@^0.4.1:
resolved "https://registry.yarnpkg.com/pkginfo/-/pkginfo-0.4.1.tgz#b5418ef0439de5425fc4995042dced14fb2a84ff"
integrity sha512-8xCNE/aT/EXKenuMDZ+xTVwkT8gsoHN2z/Q29l80u0ppGEXVvsKRzNMbtKhg8LS8k1tJLAHHylf6p4VFmP6XUQ==
+platformscript@1.0.0-alpha.6:
+ version "1.0.0-alpha.6"
+ resolved "https://registry.yarnpkg.com/platformscript/-/platformscript-1.0.0-alpha.6.tgz#b995c514b769b587d6879f45ab6b249dc05ae83a"
+ integrity sha512-QSsY/yTBjj408NYMVyWAL0mDM9Ft3CvVc1O8F7xNzyg5pRl9GE8v7Hl+la2ZC/iYKNcByNc9j1FgHxkFfcpvSw==
+ dependencies:
+ yaml-ast-parser "0.0.43"
+
pluralize@^8.0.0:
version "8.0.0"
resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-8.0.0.tgz#1a6fa16a38d12a1901e0320fa017051c539ce3b1"
@@ -21398,6 +21437,11 @@ start-server-and-test@^1.10.11:
ps-tree "1.2.0"
wait-on "6.0.0"
+state-local@^1.0.6:
+ version "1.0.7"
+ resolved "https://registry.yarnpkg.com/state-local/-/state-local-1.0.7.tgz#da50211d07f05748d53009bee46307a37db386d5"
+ integrity sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w==
+
statuses@2.0.1, statuses@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63"
@@ -23617,6 +23661,11 @@ yaml@^2.0.0:
resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.1.1.tgz#1e06fb4ca46e60d9da07e4f786ea370ed3c3cfec"
integrity sha512-o96x3OPo8GjWeSLF+wOAbrPfhFOGY0W00GNaxCDv+9hkcDJEnev1yh8S7pgHF0ik6zc8sQLuL8hjHjJULZp8bw==
+yaml@^2.1.3:
+ version "2.1.3"
+ resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.1.3.tgz#9b3a4c8aff9821b696275c79a8bee8399d945207"
+ integrity sha512-AacA8nRULjKMX2DvWvOAdBZMOfQlypSFkjcOcu9FalllIDJ1kvlREzcdIZmidQUqqeMv7jorHjq2HlLv/+c2lg==
+
yargs-parser@20.2.4:
version "20.2.4"
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54"