diff --git a/packages/backend-app-api/api-report.md b/packages/backend-app-api/api-report.md new file mode 100644 index 0000000000..8c64858310 --- /dev/null +++ b/packages/backend-app-api/api-report.md @@ -0,0 +1,15 @@ +## API Report File for "@backstage/backend-app-api" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +import { AnyServiceFactory } from '@backstage/backend-plugin-api'; +import { BackendRegistrable } from '@backstage/backend-plugin-api'; + +// Warning: (ae-forgotten-export) The symbol "CreateBackendOptions" needs to be exported by the entry point index.d.ts +// Warning: (ae-forgotten-export) The symbol "Backend" needs to be exported by the entry point index.d.ts +// Warning: (ae-missing-release-tag) "createBackend" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export function createBackend(options?: CreateBackendOptions): Backend; +``` diff --git a/packages/backend-app-api/package.json b/packages/backend-app-api/package.json index fe2d517086..ab88009d64 100644 --- a/packages/backend-app-api/package.json +++ b/packages/backend-app-api/package.json @@ -33,7 +33,9 @@ "clean": "backstage-cli package clean", "start": "backstage-cli package start" }, - "dependencies": {}, + "dependencies": { + "@backstage/backend-plugin-api": "^0.0.0" + }, "devDependencies": { "@backstage/cli": "^0.17.2-next.0" }, diff --git a/packages/backend-app-api/src/index.ts b/packages/backend-app-api/src/index.ts index 1888a9b037..33aca2b291 100644 --- a/packages/backend-app-api/src/index.ts +++ b/packages/backend-app-api/src/index.ts @@ -20,4 +20,4 @@ * @packageDocumentation */ -export {}; +export { createBackend } from './wiring/types'; diff --git a/packages/backend-app-api/src/wiring/BackendInitializer.ts b/packages/backend-app-api/src/wiring/BackendInitializer.ts new file mode 100644 index 0000000000..8c2f2714c4 --- /dev/null +++ b/packages/backend-app-api/src/wiring/BackendInitializer.ts @@ -0,0 +1,153 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { BackendRegistrable, ServiceRef } from '@backstage/backend-plugin-api'; +import { BackendRegisterInit, ApiHolder } from './types'; + +export class BackendInitializer { + #started = false; + #extensions = new Map(); + // #stops = []; + #registerInits = new Array(); + #apis = new Map, unknown>(); + #apiHolder: ApiHolder; + + constructor(apiHolder: ApiHolder) { + this.#apiHolder = apiHolder; + } + + async #getInitDeps( + deps: { [name: string]: ServiceRef }, + pluginId: string, + ) { + return Object.fromEntries( + await Promise.all( + Object.entries(deps).map(async ([name, apiRef]) => [ + name, + this.#apis.get(apiRef) || + (await this.#apiHolder.get(apiRef)!(pluginId)), + ]), + ), + ); + } + + add(extension: BackendRegistrable, options?: TOptions) { + if (this.#started) { + throw new Error( + 'extension can not be added after the backend has started', + ); + } + this.#extensions.set(extension, options); + } + + async start(): Promise { + console.log(`Starting backend`); + if (this.#started) { + throw new Error('Backend has already started'); + } + this.#started = true; + + for (const [extension] of this.#extensions) { + const provides = new Set>(); + + let registerInit: BackendRegisterInit | undefined = undefined; + + console.log('Registering', extension.id); + extension.register({ + registerExtensionPoint: (api, impl) => { + if (registerInit) { + throw new Error('registerInitApi called after registerInit'); + } + if (this.#apis.has(api)) { + throw new Error(`API ${api.id} already registered`); + } + this.#apis.set(api, impl); + provides.add(api); + }, + registerInit: registerOptions => { + if (registerInit) { + throw new Error('registerInit must only be called once'); + } + registerInit = { + id: extension.id, + provides, + consumes: new Set(Object.values(registerOptions.deps)), + deps: registerOptions.deps, + init: registerOptions.init as BackendRegisterInit['init'], + }; + }, + }); + + if (!registerInit) { + throw new Error( + `registerInit was not called by register in ${extension.id}`, + ); + } + + this.#registerInits.push(registerInit); + } + + this.validateSetup(); + + const orderedRegisterResults = this.#resolveInitOrder(this.#registerInits); + + for (const registerInit of orderedRegisterResults) { + // TODO: DI + const deps = await this.#getInitDeps(registerInit.deps, registerInit.id); + await registerInit.init(deps); + // Maybe return stop? or lifecycle API + // this.#stops.push(); + } + } + + // async stop(): Promise { + // for (const stop of this.#stops) { + // await stop.stop(); + // } + // } + + private validateSetup() {} + + #resolveInitOrder(registerInits: Array) { + let registerInitsToOrder = registerInits.slice(); + const orderedRegisterInits = new Array(); + + // TODO: Validate duplicates + + while (registerInitsToOrder.length > 0) { + const toRemove = new Set(); + + for (const registerInit of registerInitsToOrder) { + const unInitializedDependents = Array.from( + registerInit.provides, + // eslint-disable-next-line no-loop-func + ).filter(r => + registerInitsToOrder.some( + init => init !== registerInit && init.consumes.has(r), + ), + ); + + if (unInitializedDependents.length === 0) { + orderedRegisterInits.push(registerInit); + toRemove.add(registerInit); + } + } + + registerInitsToOrder = registerInitsToOrder.filter(r => !toRemove.has(r)); + } + return orderedRegisterInits; + } +} diff --git a/packages/backend-app-api/src/wiring/BackstageBackend.ts b/packages/backend-app-api/src/wiring/BackstageBackend.ts new file mode 100644 index 0000000000..ae27c4ee05 --- /dev/null +++ b/packages/backend-app-api/src/wiring/BackstageBackend.ts @@ -0,0 +1,44 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { + BackendRegistrable, + AnyServiceFactory, +} from '@backstage/backend-plugin-api'; +import { BackendInitializer } from './BackendInitializer'; +import { CoreApiRegistry } from './CoreApiRegistry'; +import { Backend } from './types'; + +export class BackstageBackend implements Backend { + #coreApis: CoreApiRegistry; + #initializer: BackendInitializer; + + constructor(apiFactories: AnyServiceFactory[]) { + this.#coreApis = new CoreApiRegistry(apiFactories); + this.#initializer = new BackendInitializer(this.#coreApis); + } + + add(extension: BackendRegistrable): void { + this.#initializer.add(extension); + } + + async start(): Promise { + await this.#initializer.start(); + } + + // async stop(): Promise { + // await this.#initializer.stop(); + // } +} diff --git a/packages/backend-app-api/src/wiring/CoreApiRegistry.ts b/packages/backend-app-api/src/wiring/CoreApiRegistry.ts new file mode 100644 index 0000000000..a144fc448d --- /dev/null +++ b/packages/backend-app-api/src/wiring/CoreApiRegistry.ts @@ -0,0 +1,65 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { + AnyServiceFactory, + ServiceRef, + FactoryFunc, +} from '@backstage/backend-plugin-api'; + +export class CoreApiRegistry { + readonly #implementations: Map>; + readonly #factories: Map; + + constructor(factories: AnyServiceFactory[]) { + this.#factories = new Map(factories.map(f => [f.service.id, f])); + this.#implementations = new Map(); + } + + get(ref: ServiceRef): FactoryFunc | undefined { + const factory = this.#factories.get(ref.id); + if (!factory) { + return undefined; + } + + return async (pluginId: string): Promise => { + if (this.#implementations.has(ref.id)) { + if (this.#implementations.get(ref.id)!.has(pluginId)) { + return this.#implementations.get(ref.id)!.get(pluginId) as T; + } + this.#implementations.set(ref.id, new Map()); + } else { + this.#implementations.set(ref.id, new Map()); + } + + const factoryDeps = Object.fromEntries( + Object.entries(factory.deps).map(([name, apiRef]) => [ + name, + this.get(apiRef)!, // TODO: throw + ]), + ); + + const factoryFunc = await factory.factory(factoryDeps); + const implementation = await factoryFunc(pluginId); + + this.#implementations.set( + ref.id, + this.#implementations.get(ref.id)!.set(pluginId, implementation), + ); + + return implementation as T; + }; + } +} diff --git a/packages/backend-app-api/src/wiring/types.ts b/packages/backend-app-api/src/wiring/types.ts index cf600ba1d0..44640cbc07 100644 --- a/packages/backend-app-api/src/wiring/types.ts +++ b/packages/backend-app-api/src/wiring/types.ts @@ -14,14 +14,35 @@ * limitations under the License. */ -export interface BackendApp { - add(registrable: BackendRegistrable): void; +import { + BackendRegistrable, + AnyServiceFactory, + ServiceRef, + FactoryFunc, +} from '@backstage/backend-plugin-api'; +import { BackstageBackend } from './BackstageBackend'; + +export interface Backend { + add(extension: BackendRegistrable): void; + start(): Promise; +} + +export interface BackendRegisterInit { + id: string; + consumes: Set>; + provides: Set>; + deps: { [name: string]: ServiceRef }; + init: (deps: { [name: string]: unknown }) => Promise; } interface CreateBackendOptions { apis: AnyServiceFactory[]; } +export type ApiHolder = { + get(api: ServiceRef): FactoryFunc | undefined; +}; + export function createBackend(options?: CreateBackendOptions): Backend { return new BackstageBackend(options?.apis ?? []); } diff --git a/packages/backend-plugin-api/package.json b/packages/backend-plugin-api/package.json index 967ae734ee..ccda227018 100644 --- a/packages/backend-plugin-api/package.json +++ b/packages/backend-plugin-api/package.json @@ -33,7 +33,9 @@ "clean": "backstage-cli package clean", "start": "backstage-cli package start" }, - "dependencies": {}, + "dependencies": { + "@backstage/config": "^1.0.1" + }, "devDependencies": { "@backstage/cli": "^0.17.2-next.0" }, diff --git a/packages/backend-plugin-api/src/index.ts b/packages/backend-plugin-api/src/index.ts index da51896950..e82218ca69 100644 --- a/packages/backend-plugin-api/src/index.ts +++ b/packages/backend-plugin-api/src/index.ts @@ -21,3 +21,5 @@ */ export * from './wiring'; +export * from './services/system/types'; +export * from './services/definitions'; diff --git a/packages/backend-plugin-api/src/services/definitions/configApiRef.ts b/packages/backend-plugin-api/src/services/definitions/configApiRef.ts new file mode 100644 index 0000000000..cca1445079 --- /dev/null +++ b/packages/backend-plugin-api/src/services/definitions/configApiRef.ts @@ -0,0 +1,22 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Config } from '@backstage/config'; +import { createServiceRef } from '../system/types'; + +export const configApiRef = createServiceRef({ + id: 'core.config', +}); diff --git a/packages/backend-plugin-api/src/services/definitions/httpRouterApiRef.ts b/packages/backend-plugin-api/src/services/definitions/httpRouterApiRef.ts new file mode 100644 index 0000000000..d54ebd36bf --- /dev/null +++ b/packages/backend-plugin-api/src/services/definitions/httpRouterApiRef.ts @@ -0,0 +1,25 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { createServiceRef } from '../system/types'; + +export interface HttpRouterApi { + get(path: string): void; +} + +export const httpRouterApiRef = createServiceRef({ + id: 'core.httpRouter', +}); diff --git a/packages/backend-plugin-api/src/services/definitions/types.ts b/packages/backend-plugin-api/src/services/definitions/index.ts similarity index 66% rename from packages/backend-plugin-api/src/services/definitions/types.ts rename to packages/backend-plugin-api/src/services/definitions/index.ts index 8e85e1198d..b11b2f8c4e 100644 --- a/packages/backend-plugin-api/src/services/definitions/types.ts +++ b/packages/backend-plugin-api/src/services/definitions/index.ts @@ -14,31 +14,6 @@ * limitations under the License. */ -interface Logger { - log(message: string): void; - child(fields: { [name: string]: string }): Logger; -} - -interface ConfigApi { - getString(key: string): string; -} - -interface HttpRouterApi { - get(path: string): void; -} - -export const loggerApiRef = createServiceRef({ - id: 'core.logger', -}); - -export const configApiRef = createServiceRef({ - id: 'core.config', -}); - -export const httpRouterApiRef = createServiceRef({ - id: 'core.apiRouter', -}); - // export type PluginEnvironment = { // logger: Logger; // cache: PluginCacheManager; @@ -50,3 +25,9 @@ export const httpRouterApiRef = createServiceRef({ // permissions: PermissionEvaluator | PermissionAuthorizer; // scheduler: PluginTaskScheduler; // }; + +export { configApiRef } from './configApiRef'; +export { httpRouterApiRef } from './httpRouterApiRef'; +export type { HttpRouterApi } from './httpRouterApiRef'; +export { loggerApiRef } from './loggerApiRef'; +export type { Logger } from './loggerApiRef'; diff --git a/packages/backend-plugin-api/src/services/definitions/loggerApiRef.ts b/packages/backend-plugin-api/src/services/definitions/loggerApiRef.ts new file mode 100644 index 0000000000..348ffc9cf4 --- /dev/null +++ b/packages/backend-plugin-api/src/services/definitions/loggerApiRef.ts @@ -0,0 +1,26 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { createServiceRef } from '../system/types'; + +export interface Logger { + log(message: string): void; + child(fields: { [name: string]: string }): Logger; +} + +export const loggerApiRef = createServiceRef({ + id: 'core.logger', +}); diff --git a/packages/backend-plugin-api/src/services/system/types.ts b/packages/backend-plugin-api/src/services/system/types.ts index 4b6b284a1d..86ad8d42f0 100644 --- a/packages/backend-plugin-api/src/services/system/types.ts +++ b/packages/backend-plugin-api/src/services/system/types.ts @@ -14,17 +14,56 @@ * limitations under the License. */ +/** + * TODO + * + * @public + */ export interface ServiceRef { id: string; + + /** + * Utility for getting the type of the service, using `typeof serviceRef.T`. + * Attempting to actually read this value will result in an exception. + */ T: T; + + toString(): string; + $$ref: 'service'; } +type TypesToServiceRef = { [key in keyof T]: ServiceRef }; +type DepsToDepFactories = { + [key in keyof T]: (pluginId: string) => Promise; +}; + +export type FactoryFunc = (pluginId: string) => Promise; + +export type ServiceFactory< + TApi, + TImpl extends TApi, + TDeps extends { [name in string]: unknown }, +> = { + service: ServiceRef; + deps: TypesToServiceRef; + factory(deps: DepsToDepFactories): Promise>; +}; + +export type AnyServiceFactory = ServiceFactory< + unknown, + unknown, + { [key in string]: unknown } +>; + export function createServiceRef(options: { id: string }): ServiceRef { return { id: options.id, get T(): T { - throw Error('NO T'); + throw new Error(`tried to read ServiceRef.T of ${this}`); + }, + toString() { + return `serviceRef{${options.id}}`; }, $$ref: 'service', // TODO: declare }; diff --git a/packages/backend-plugin-api/src/wiring/index.ts b/packages/backend-plugin-api/src/wiring/index.ts index 259fe2b2ea..9340dc8fa9 100644 --- a/packages/backend-plugin-api/src/wiring/index.ts +++ b/packages/backend-plugin-api/src/wiring/index.ts @@ -14,4 +14,5 @@ * limitations under the License. */ -export { BackendRegistrable } from './types'; +export type { BackendRegistrable } from './types'; +export * from './types'; diff --git a/packages/backend-plugin-api/src/wiring/types.ts b/packages/backend-plugin-api/src/wiring/types.ts index 32a5afba0c..746d47b355 100644 --- a/packages/backend-plugin-api/src/wiring/types.ts +++ b/packages/backend-plugin-api/src/wiring/types.ts @@ -14,9 +14,25 @@ * limitations under the License. */ +import { ServiceRef } from '../services/system/types'; + +/** + * TODO + * + * @public + */ export interface ExtensionPoint { id: string; + + /** + * Utility for getting the type of the extension point, using `typeof + * extensionPoint.T`. Attempting to actually read this value will result in an + * exception. + */ T: T; + + toString(): string; + $$ref: 'extension-point'; } @@ -26,7 +42,10 @@ export function createExtensionPoint(options: { return { id: options.id, get T(): T { - throw Error('NO T'); + throw new Error(`tried to read ExtensionPoint.T of ${this}`); + }, + toString() { + return `extensionPoint{${options.id}}`; }, $$ref: 'extension-point', // TODO: declare }; diff --git a/packages/backend/package.json b/packages/backend/package.json index df6fe5ec3b..7604f1e609 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -26,6 +26,8 @@ "build-image": "docker build ../.. -f Dockerfile --tag example-backend" }, "dependencies": { + "@backstage/backend-plugin-api": "^0.0.0", + "@backstage/backend-app-api": "^0.0.0", "@backstage/backend-common": "^0.14.1-next.2", "@backstage/backend-tasks": "^0.3.3-next.2", "@backstage/catalog-client": "^1.0.4-next.1", diff --git a/packages/backend/src/next/index.ts b/packages/backend/src/next/index.ts new file mode 100644 index 0000000000..221332f6ba --- /dev/null +++ b/packages/backend/src/next/index.ts @@ -0,0 +1,100 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { createBackend } from '@backstage/backend-app-api'; +import { + createBackendModule, + createBackendPlugin, + createServiceRef, +} from '@backstage/backend-plugin-api'; +// import { catalogPlugin } from '@backstage/plugin-catalog-backend'; +// import { scaffolderPlugin } from '@backstage/plugin-scaffolder-backend'; + +interface CatalogProcessor { + process(): void; +} + +interface CatalogProcessingInitApi { + addProcessor(processor: CatalogProcessor): void; +} + +export const catalogProcessingInitApiRef = + createServiceRef({ + id: 'catalog.processing', + }); + +class CatalogExtensionPointImpl implements CatalogProcessingInitApi { + #processors = new Array(); + + addProcessor(processor: CatalogProcessor): void { + this.#processors.push(processor); + } + + get processors() { + return this.#processors; + } +} + +export const catalogPlugin = createBackendPlugin({ + id: 'catalog', + register(env) { + const processingExtensions = new CatalogExtensionPointImpl(); + // plugins depending on this API will be initialized before this plugins init method is executed. + env.registerExtensionPoint( + catalogProcessingInitApiRef, + processingExtensions, + ); + + env.registerInit({ + deps: { + // logger: loggerApiRef, + }, + async init() { + console.log('I HAZ', processingExtensions.processors[0].process()); + console.log('I AM le CATALOG!'); + // logger.log('HELLO!'); + }, + }); + }, +}); + +export const scaffolderCatalogExtension = createBackendModule({ + moduleId: 'boop', + pluginId: 'catalog', + register(env) { + env.registerInit({ + deps: { + catalogProcessingInitApi: catalogProcessingInitApiRef, + }, + async init({ catalogProcessingInitApi }) { + catalogProcessingInitApi.addProcessor({ + process() { + console.log('Running scaffolder processor'); + }, + }); + }, + }); + }, +}); + +const backend = createBackend({ + apis: [], +}); + +// backend.add(scaffolderPlugin()); +backend.add(catalogPlugin({})); +backend.add(scaffolderCatalogExtension({})); +backend.start(); diff --git a/yarn.lock b/yarn.lock index e35aee85fb..fe5ff8cb76 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1557,6 +1557,126 @@ lodash "^4.17.21" uuid "^8.0.0" +"@backstage/cli@^0.17.2-next.0": + version "0.17.2" + resolved "https://registry.npmjs.org/@backstage/cli/-/cli-0.17.2.tgz#2387b8d24d8af4828b84baaa62e6b444ec4330e6" + integrity sha512-stRJWmokD7SXnclZ1dsVfA1stUP4PQPkbi3GkwY1zM84y4M20dU+YHde7MrTILMPnhMY+16WdTdfbeqLfXOJrw== + dependencies: + "@backstage/cli-common" "^0.1.9" + "@backstage/config" "^1.0.1" + "@backstage/config-loader" "^1.1.2" + "@backstage/errors" "^1.0.0" + "@backstage/release-manifests" "^0.0.4" + "@backstage/types" "^1.0.0" + "@hot-loader/react-dom-v16" "npm:@hot-loader/react-dom@^16.0.2" + "@hot-loader/react-dom-v17" "npm:@hot-loader/react-dom@^17.0.2" + "@manypkg/get-packages" "^1.1.3" + "@octokit/request" "^5.4.12" + "@rollup/plugin-commonjs" "^22.0.0" + "@rollup/plugin-json" "^4.1.0" + "@rollup/plugin-node-resolve" "^13.0.0" + "@rollup/plugin-yaml" "^3.1.0" + "@spotify/eslint-config-base" "^13.0.0" + "@spotify/eslint-config-react" "^13.0.0" + "@spotify/eslint-config-typescript" "^13.0.0" + "@sucrase/jest-plugin" "^2.1.1" + "@sucrase/webpack-loader" "^2.0.0" + "@svgr/plugin-jsx" "6.2.x" + "@svgr/plugin-svgo" "6.2.x" + "@svgr/rollup" "6.2.x" + "@svgr/webpack" "6.2.x" + "@types/webpack-env" "^1.15.2" + "@typescript-eslint/eslint-plugin" "^5.9.0" + "@typescript-eslint/parser" "^5.9.0" + "@yarnpkg/lockfile" "^1.1.0" + "@yarnpkg/parsers" "^3.0.0-rc.4" + bfj "^7.0.2" + buffer "^6.0.3" + chalk "^4.0.0" + chokidar "^3.3.1" + commander "^9.1.0" + css-loader "^6.5.1" + diff "^5.0.0" + esbuild "^0.14.10" + esbuild-loader "^2.18.0" + eslint "^8.6.0" + eslint-config-prettier "^8.3.0" + eslint-formatter-friendly "^7.0.0" + eslint-plugin-deprecation "^1.3.2" + eslint-plugin-import "^2.25.4" + eslint-plugin-jest "^26.1.2" + eslint-plugin-jsx-a11y "^6.5.1" + eslint-plugin-monorepo "^0.3.2" + eslint-plugin-react "^7.28.0" + eslint-plugin-react-hooks "^4.3.0" + eslint-webpack-plugin "^3.1.1" + express "^4.17.1" + fork-ts-checker-webpack-plugin "^7.0.0-alpha.8" + fs-extra "10.1.0" + glob "^7.1.7" + global-agent "^3.0.0" + handlebars "^4.7.3" + html-webpack-plugin "^5.3.1" + inquirer "^8.2.0" + jest "^27.5.1" + jest-css-modules "^2.1.0" + jest-runtime "^27.5.1" + jest-transform-yaml "^1.0.0" + json-schema "^0.4.0" + lodash "^4.17.21" + mini-css-extract-plugin "^2.4.2" + minimatch "5.1.0" + node-fetch "^2.6.7" + node-libs-browser "^2.2.1" + npm-packlist "^5.0.0" + ora "^5.3.0" + postcss "^8.1.0" + process "^0.11.10" + react-dev-utils "^12.0.0-next.60" + react-hot-loader "^4.13.0" + recursive-readdir "^2.2.2" + replace-in-file "^6.0.0" + rollup "^2.60.2" + rollup-plugin-dts "^4.0.1" + rollup-plugin-esbuild "^4.7.2" + rollup-plugin-postcss "^4.0.0" + rollup-pluginutils "^2.8.2" + run-script-webpack-plugin "^0.0.14" + semver "^7.3.2" + style-loader "^3.3.1" + sucrase "^3.20.2" + tar "^6.1.2" + terser-webpack-plugin "^5.1.3" + util "^0.12.3" + webpack "^5.66.0" + webpack-dev-server "^4.7.3" + webpack-node-externals "^3.0.0" + yaml "^1.10.0" + yml-loader "^2.1.0" + yn "^4.0.0" + zod "^3.11.6" + +"@backstage/config-loader@^1.1.2": + version "1.1.2" + resolved "https://registry.npmjs.org/@backstage/config-loader/-/config-loader-1.1.2.tgz#72cb0d7b2647f5a646bb279360bc34732e06521f" + integrity sha512-c5ZO7xDJn609DBIsYAWGE5kgh+7SPYUmG2ADtVX9SbXaql3VCafGlhc2hAZQa/O12W04qi3GgwGg0bqSFmx5uw== + dependencies: + "@backstage/cli-common" "^0.1.9" + "@backstage/config" "^1.0.1" + "@backstage/errors" "^1.0.0" + "@backstage/types" "^1.0.0" + "@types/json-schema" "^7.0.6" + ajv "^8.10.0" + chokidar "^3.5.2" + fs-extra "10.1.0" + json-schema "^0.4.0" + json-schema-merge-allof "^0.8.1" + json-schema-traverse "^1.0.0" + node-fetch "^2.6.7" + typescript-json-schema "^0.53.0" + yaml "^1.9.2" + yup "^0.32.9" + "@backstage/core-components@^0.9.0", "@backstage/core-components@^0.9.5": version "0.9.5" resolved "https://registry.npmjs.org/@backstage/core-components/-/core-components-0.9.5.tgz#5a0b34867aaee0549bfa67b39a69c09588fa3c7a" @@ -5555,7 +5675,7 @@ dependencies: "@rollup/pluginutils" "^3.0.8" -"@rollup/plugin-node-resolve@^13.0.6": +"@rollup/plugin-node-resolve@^13.0.0", "@rollup/plugin-node-resolve@^13.0.6": version "13.3.0" resolved "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-13.3.0.tgz#da1c5c5ce8316cef96a2f823d111c1e4e498801c" integrity sha512-Lus8rbUo1eEcnS4yTFKLZrVumLPY+YayBdWXgFSHYhTT2iJbMhoaaBL3xl5NCdeRytErGr8tZ0L71BMRmnlwSw== @@ -20504,6 +20624,11 @@ path-case@^3.0.4: dot-case "^3.0.4" tslib "^2.0.3" +path-equal@1.1.2: + version "1.1.2" + resolved "https://registry.npmjs.org/path-equal/-/path-equal-1.1.2.tgz#260e7c449c4c2022f68cc5fa6e617e892858250d" + integrity sha512-p5kxPPwCdbf5AdXzT1bUBJomhgBlEjRBavYNr1XUpMFIE4Hnf2roueCMXudZK5tnaAu1tTmp3GPzqwJK45IHEA== + path-equal@^1.1.2: version "1.2.2" resolved "https://registry.npmjs.org/path-equal/-/path-equal-1.2.2.tgz#fa2997f0a829de22ec8f5f86461ca5590d49b832" @@ -23028,6 +23153,11 @@ run-parallel@^1.1.9: resolved "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.9.tgz#c9dd3a7cf9f4b2c4b6244e173a6ed866e61dd679" integrity sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q== +run-script-webpack-plugin@^0.0.14: + version "0.0.14" + resolved "https://registry.npmjs.org/run-script-webpack-plugin/-/run-script-webpack-plugin-0.0.14.tgz#fe2362b32c1dab7a8af7a6f1246fc043690cedd7" + integrity sha512-DXe6lzzEVXjBr/74zd4m4yOfmz5P6GMjzhQxDDsViOmwG7cap8UCE6RgD5rT7zf4wM83a+ToHnpB3v4efUv5IA== + run-script-webpack-plugin@^0.1.0: version "0.1.1" resolved "https://registry.npmjs.org/run-script-webpack-plugin/-/run-script-webpack-plugin-0.1.1.tgz#dad3114be32eb864d2160306e4d9c52a2c1cfd59" @@ -25311,6 +25441,20 @@ typedarray@^0.0.6: resolved "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= +typescript-json-schema@^0.53.0: + version "0.53.1" + resolved "https://registry.npmjs.org/typescript-json-schema/-/typescript-json-schema-0.53.1.tgz#9204547f3e145169b40928998366ff6d28b81d32" + integrity sha512-Hg+RnOKUd38MOzC0rDft03a8xvwO+gCcj1F77smw2tCoZYQpFoLtrXWBGdvCX+REliko5WYel2kux17HPFqjLQ== + dependencies: + "@types/json-schema" "^7.0.9" + "@types/node" "^16.9.2" + glob "^7.1.7" + path-equal "1.1.2" + safe-stable-stringify "^2.2.0" + ts-node "^10.2.1" + typescript "~4.6.0" + yargs "^17.1.1" + typescript-json-schema@^0.54.0: version "0.54.0" resolved "https://registry.npmjs.org/typescript-json-schema/-/typescript-json-schema-0.54.0.tgz#b3fc42ad90df6a0f6ab57571ebc8b4d41125df4f"