Merge pull request #15816 from backstage/rugvip/subpath

[PRFC] Add support for subpath exports
This commit is contained in:
Patrik Oldsberg
2023-02-21 16:32:15 +01:00
committed by GitHub
314 changed files with 3275 additions and 1523 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/repo-tools': patch
---
Tweaked type dependency check to trim wildcard type imports.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/cli': patch
---
Added a new `migrate package-exports` command that synchronizes package exports fields in all `package.json`s.
+45
View File
@@ -0,0 +1,45 @@
---
'@backstage/plugin-catalog-backend-module-incremental-ingestion': patch
'@backstage/plugin-catalog-backend-module-bitbucket-server': patch
'@backstage/plugin-catalog-backend-module-bitbucket-cloud': patch
'@backstage/plugin-events-backend-module-bitbucket-cloud': patch
'@backstage/plugin-catalog-backend-module-msgraph': patch
'@backstage/plugin-catalog-backend-module-gerrit': patch
'@backstage/plugin-catalog-backend-module-github': patch
'@backstage/plugin-catalog-backend-module-gitlab': patch
'@backstage/plugin-events-backend-module-aws-sqs': patch
'@backstage/plugin-catalog-backend-module-azure': patch
'@backstage/plugin-events-backend-module-gerrit': patch
'@backstage/plugin-events-backend-module-github': patch
'@backstage/plugin-events-backend-module-gitlab': patch
'@backstage/plugin-events-backend-module-azure': patch
'@backstage/plugin-catalog-backend-module-aws': patch
'@backstage/backend-plugin-api': patch
'@backstage/backend-test-utils': patch
'@backstage/plugin-scaffolder-backend': patch
'@backstage/backend-defaults': patch
'@backstage/backend-app-api': patch
'@backstage/core-plugin-api': patch
'@backstage/plugin-scaffolder-react': patch
'@backstage/plugin-techdocs-backend': patch
'@backstage/backend-common': patch
'@backstage/plugin-catalog-backend': patch
'@backstage/plugin-sonarqube-react': patch
'@backstage/catalog-model': patch
'@backstage/plugin-catalog-common': patch
'@backstage/plugin-events-backend': patch
'@backstage/plugin-jenkins-common': patch
'@backstage/plugin-techdocs-react': patch
'@backstage/plugin-catalog-react': patch
'@backstage/plugin-cost-insights': patch
'@backstage/plugin-catalog-node': patch
'@backstage/test-utils': patch
'@backstage/plugin-app-backend': patch
'@backstage/plugin-events-node': patch
'@backstage/plugin-scaffolder': patch
'@backstage/plugin-sonarqube': patch
'@backstage/plugin-catalog': patch
'@backstage/plugin-jenkins': patch
---
Internal refactor of `/alpha` exports.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/repo-tools': patch
---
The API report generation process is now able to detect and generate reports for additional entry points declared in the package `"exports"` field.
+1
View File
@@ -5,6 +5,7 @@ coverage
*.hbs
templates
api-report.md
*-api-report.md
cli-report.md
plugins/scaffolder-backend/sample-templates
.vscode
+26
View File
@@ -650,8 +650,34 @@ The following is an excerpt of a typical setup of an isomorphic library package:
"files": ["dist"],
```
## Subpath Exports
The Backstage CLI supports implementation of subpath exports through the `"exports"` field in `package.json`. It might for example look like this:
```json
"name": "@backstage/plugin-foo",
"exports": {
".": "./src/index.ts",
"./components": "./src/components.ts",
},
```
This in turn would allow you to import anything exported in `src/index.ts` via `@backstage/plugins-foo`, and `src/components.ts` via `@backstage/plugins-foo/components`. Note that patterns are not supported, meaning the exports may not contain `*` wildcards.
As with the rest of the Backstage CLI build system, the setup is optimized for local development, which is why the `"exports"` targets point directly to source files. The `package build` command will detect the `"exports"` field and automatically generate the corresponding `dist` files, and the `prepublish` command will rewrite the `"exports"` field to point to the `dist` files, as well as generating folder-based entry points for backwards compatibility.
TypeScript support is currently handled though the `typesVersions` field, as there is not yet a module resolution mode that works well with `"exports"`. You can craft the `typesVersions` yourself, but it will also be automatically generated by the `migrate package-exports` command.
To add subpath exports to an existing package, simply add the desired `"exports"` fields and then run the following command:
```bash
yarn backstage-cli package migrate package-exports
```
## Experimental Type Build
> Note: Experimental type builds are deprecated and will be removed in the future. They have been replaced by [subpath exports](#subpath-exports).
The Backstage CLI has an experimental feature where multiple different type definition files can be generated for different release stages. The release stages are marked in the [TSDoc](https://tsdoc.org/) for each individual export, using either `@public`, `@alpha`, or `@beta`. Rather than just building a single `index.d.ts` file, the build process will instead output `index.d.ts`, `index.beta.d.ts`, and `index.alpha.d.ts`. Each of these files will have exports from more unstable release stages stripped, meaning that `index.d.ts` will omit all exports marked with `@alpha` or `@beta`, while `index.beta.d.ts` will omit all exports marked with `@alpha`.
This feature is aimed at projects that publish to package registries and wish to maintain different levels of API stability within each package. There is no need to use this within a single monorepo, as it has no effect due to only applying to built and published packages.
-1
View File
@@ -120,7 +120,6 @@ Build a package for production deployment or publishing
Options:
--role <name> Run the command with an explicit package role
--minify Minify the generated code. Does not apply to app or backend packages.
--experimental-type-build Enable experimental type build. Does not apply to app or backend packages.
--skip-build-dependencies Skip the automatic building of local dependencies. Applies to backend packages only.
--stats If bundle stats are available, write them to the output directory. Applies to app packages only.
--config <path> Config files to load instead of app-config.yaml. Applies to app packages only. (default: [])
+1 -1
View File
@@ -11,7 +11,7 @@
"build:backend": "yarn workspace backend build",
"build:all": "backstage-cli repo build --all",
"build:api-reports": "yarn build:api-reports:only --tsc",
"build:api-reports:only": "backstage-repo-tools api-reports --allow-warnings 'packages/core-components,plugins/+(catalog|catalog-import|git-release-manager|jenkins|kubernetes)' -o ae-wrong-input-file-type",
"build:api-reports:only": "backstage-repo-tools api-reports --allow-warnings 'packages/core-components,plugins/+(catalog|catalog-import|git-release-manager|jenkins|kubernetes)' -o ae-wrong-input-file-type --validate-release-tags",
"build:api-docs": "LANG=en_EN yarn build:api-reports --docs",
"tsc": "tsc",
"tsc:full": "backstage-cli repo clean && tsc --skipLibCheck false --incremental false",
+2 -2
View File
@@ -59,9 +59,9 @@ import { GraphiQLPage } from '@backstage/plugin-graphiql';
import { HomepageCompositionRoot } from '@backstage/plugin-home';
import { LighthousePage } from '@backstage/plugin-lighthouse';
import { NewRelicPage } from '@backstage/plugin-newrelic';
import { NextScaffolderPage } from '@backstage/plugin-scaffolder/alpha';
import {
ScaffolderPage,
NextScaffolderPage,
scaffolderPlugin,
ScaffolderLayouts,
} from '@backstage/plugin-scaffolder';
@@ -104,7 +104,7 @@ import * as plugins from './plugins';
import { techDocsPage } from './components/techdocs/TechDocsPage';
import { ApacheAirflowPage } from '@backstage/plugin-apache-airflow';
import { RequirePermission } from '@backstage/plugin-permission-react';
import { catalogEntityCreatePermission } from '@backstage/plugin-catalog-common';
import { catalogEntityCreatePermission } from '@backstage/plugin-catalog-common/alpha';
import { PlaylistIndexPage } from '@backstage/plugin-playlist';
import { TwoColumnLayout } from './components/scaffolder/customScaffolderLayouts';
import { ScoreBoardPage } from '@oriflame/backstage-plugin-score-card';
@@ -17,10 +17,11 @@ import React from 'react';
import type { FieldValidation } from '@rjsf/utils';
import { scaffolderPlugin } from '@backstage/plugin-scaffolder';
import { TextField } from '@material-ui/core';
import {
NextFieldExtensionComponentProps,
createNextScaffolderFieldExtension,
} from '@backstage/plugin-scaffolder-react/alpha';
import {
createScaffolderFieldExtension,
FieldExtensionComponentProps,
} from '@backstage/plugin-scaffolder-react';
+2 -3
View File
@@ -7,8 +7,7 @@
"publishConfig": {
"access": "public",
"main": "dist/index.cjs.js",
"types": "dist/index.d.ts",
"alphaTypes": "dist/index.alpha.d.ts"
"types": "dist/index.d.ts"
},
"backstage": {
"role": "node-library"
@@ -24,7 +23,7 @@
],
"license": "Apache-2.0",
"scripts": {
"build": "backstage-cli package build --experimental-type-build",
"build": "backstage-cli package build",
"lint": "backstage-cli package lint",
"test": "backstage-cli package test",
"prepack": "backstage-cli package prepack",
@@ -0,0 +1,32 @@
## API Report File for "@backstage/backend-common"
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
```ts
import { Duration } from 'luxon';
// @alpha
export interface Context {
readonly abortSignal: AbortSignal;
readonly deadline: Date | undefined;
value<T = unknown>(key: string): T | undefined;
}
// @alpha
export class Contexts {
static root(): Context;
static withAbort(
parentCtx: Context,
source: AbortController | AbortSignal,
): Context;
static withTimeoutDuration(parentCtx: Context, timeout: Duration): Context;
static withTimeoutMillis(parentCtx: Context, timeout: number): Context;
static withValue(
parentCtx: Context,
key: string,
value: unknown | ((previous: unknown | undefined) => unknown),
): Context;
}
// (No @packageDocumentation comment for this package)
```
-24
View File
@@ -20,7 +20,6 @@ import { Config } from '@backstage/config';
import { ConfigService } from '@backstage/backend-plugin-api';
import cors from 'cors';
import Docker from 'dockerode';
import { Duration } from 'luxon';
import { ErrorRequestHandler } from 'express';
import express from 'express';
import { GerritIntegration } from '@backstage/integration';
@@ -211,29 +210,6 @@ export interface ContainerRunner {
runContainer(opts: RunContainerOptions): Promise<void>;
}
// @alpha
export interface Context {
readonly abortSignal: AbortSignal;
readonly deadline: Date | undefined;
value<T = unknown>(key: string): T | undefined;
}
// @alpha
export class Contexts {
static root(): Context;
static withAbort(
parentCtx: Context,
source: AbortController | AbortSignal,
): Context;
static withTimeoutDuration(parentCtx: Context, timeout: Duration): Context;
static withTimeoutMillis(parentCtx: Context, timeout: number): Context;
static withValue(
parentCtx: Context,
key: string,
value: unknown | ((previous: unknown | undefined) => unknown),
): Context;
}
// @public
export function createDatabaseClient(
dbConfig: Config,
+17 -5
View File
@@ -5,10 +5,22 @@
"main": "src/index.ts",
"types": "src/index.ts",
"publishConfig": {
"access": "public",
"main": "dist/index.cjs.js",
"types": "dist/index.d.ts",
"alphaTypes": "dist/index.alpha.d.ts"
"access": "public"
},
"exports": {
".": "./src/index.ts",
"./alpha": "./src/alpha.ts",
"./package.json": "./package.json"
},
"typesVersions": {
"*": {
"alpha": [
"src/alpha.ts"
],
"package.json": [
"package.json"
]
}
},
"backstage": {
"role": "node-library"
@@ -24,7 +36,7 @@
],
"license": "Apache-2.0",
"scripts": {
"build": "backstage-cli package build --experimental-type-build",
"build": "backstage-cli package build",
"lint": "backstage-cli package lint",
"test": "backstage-cli package test",
"prepack": "backstage-cli package prepack",
+17
View File
@@ -0,0 +1,17 @@
/*
* Copyright 2023 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.
*/
export * from './context';
-1
View File
@@ -24,7 +24,6 @@ export { legacyPlugin, makeLegacyPlugin } from './legacy';
export type { LegacyCreateRouter } from './legacy';
export * from './cache';
export { loadBackendConfig } from './config';
export * from './context';
export * from './database';
export * from './discovery';
export * from './hot';
+3 -3
View File
@@ -14,10 +14,10 @@
* limitations under the License.
*/
import { catalogPlugin } from '@backstage/plugin-catalog-backend';
import { catalogModuleTemplateKind } from '@backstage/plugin-scaffolder-backend';
import { catalogPlugin } from '@backstage/plugin-catalog-backend/alpha';
import { catalogModuleTemplateKind } from '@backstage/plugin-scaffolder-backend/alpha';
import { createBackend } from '@backstage/backend-defaults';
import { appPlugin } from '@backstage/plugin-app-backend';
import { appPlugin } from '@backstage/plugin-app-backend/alpha';
import { todoPlugin } from '@backstage/plugin-todo-backend';
const backend = createBackend();
+2 -3
View File
@@ -7,8 +7,7 @@
"publishConfig": {
"access": "public",
"main": "dist/index.cjs.js",
"types": "dist/index.d.ts",
"alphaTypes": "dist/index.alpha.d.ts"
"types": "dist/index.d.ts"
},
"backstage": {
"role": "node-library"
@@ -24,7 +23,7 @@
],
"license": "Apache-2.0",
"scripts": {
"build": "backstage-cli package build --experimental-type-build",
"build": "backstage-cli package build",
"lint": "backstage-cli package lint",
"test": "backstage-cli package test",
"prepack": "backstage-cli package prepack",
+14 -7
View File
@@ -5,10 +5,18 @@
"main": "src/index.ts",
"types": "src/index.ts",
"publishConfig": {
"access": "public",
"main": "dist/index.cjs.js",
"types": "dist/index.d.ts",
"alphaTypes": "dist/index.alpha.d.ts"
"access": "public"
},
"exports": {
".": "./src/index.ts",
"./package.json": "./package.json"
},
"typesVersions": {
"*": {
"package.json": [
"package.json"
]
}
},
"backstage": {
"role": "node-library"
@@ -25,7 +33,7 @@
],
"license": "Apache-2.0",
"scripts": {
"build": "backstage-cli package build --experimental-type-build",
"build": "backstage-cli package build",
"lint": "backstage-cli package lint",
"test": "backstage-cli package test",
"prepack": "backstage-cli package prepack",
@@ -55,7 +63,6 @@
"supertest": "^6.1.3"
},
"files": [
"dist",
"alpha"
"dist"
]
}
@@ -0,0 +1,31 @@
## API Report File for "@backstage/catalog-model"
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
```ts
import { Entity } from '@backstage/catalog-model';
import { SerializedError } from '@backstage/errors';
// @alpha
export interface AlphaEntity extends Entity {
status?: EntityStatus;
}
// @alpha
export type EntityStatus = {
items?: EntityStatusItem[];
};
// @alpha
export type EntityStatusItem = {
type: string;
level: EntityStatusLevel;
message: string;
error?: SerializedError;
};
// @alpha
export type EntityStatusLevel = 'info' | 'warning' | 'error';
// (No @packageDocumentation comment for this package)
```
-22
View File
@@ -4,12 +4,6 @@
```ts
import { JsonObject } from '@backstage/types';
import { SerializedError } from '@backstage/errors';
// @alpha
export interface AlphaEntity extends Entity {
status?: EntityStatus;
}
// @public
export const ANNOTATION_EDIT_URL = 'backstage.io/edit-url';
@@ -209,22 +203,6 @@ export function entitySchemaValidator<T extends Entity = Entity>(
schema?: unknown,
): (data: unknown) => T;
// @alpha
export type EntityStatus = {
items?: EntityStatusItem[];
};
// @alpha
export type EntityStatusItem = {
type: string;
level: EntityStatusLevel;
message: string;
error?: SerializedError;
};
// @alpha
export type EntityStatusLevel = 'info' | 'warning' | 'error';
// @public
export class FieldFormatEntityPolicy implements EntityPolicy {
constructor(validators?: Validators);
+18 -8
View File
@@ -6,11 +6,22 @@
"types": "src/index.ts",
"license": "Apache-2.0",
"publishConfig": {
"access": "public",
"main": "dist/index.cjs.js",
"module": "dist/index.esm.js",
"types": "dist/index.d.ts",
"alphaTypes": "dist/index.alpha.d.ts"
"access": "public"
},
"exports": {
".": "./src/index.ts",
"./alpha": "./src/alpha.ts",
"./package.json": "./package.json"
},
"typesVersions": {
"*": {
"alpha": [
"src/alpha.ts"
],
"package.json": [
"package.json"
]
}
},
"backstage": {
"role": "common-library"
@@ -25,7 +36,7 @@
"backstage"
],
"scripts": {
"build": "backstage-cli package build --experimental-type-build",
"build": "backstage-cli package build",
"lint": "backstage-cli package lint",
"test": "backstage-cli package test",
"prepack": "backstage-cli package prepack",
@@ -48,7 +59,6 @@
"yaml": "^2.0.0"
},
"files": [
"dist",
"alpha"
"dist"
]
}
+22
View File
@@ -0,0 +1,22 @@
/*
* Copyright 2023 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.
*/
export type {
EntityStatus,
EntityStatusItem,
EntityStatusLevel,
} from './entity/EntityStatus';
export type { AlphaEntity } from './entity/AlphaEntity';
@@ -0,0 +1,39 @@
/*
* Copyright 2020 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.
*/
// TODO(Rugvip): Figure out best way to allow this import
// eslint-disable-next-line import/no-extraneous-dependencies
import { Entity } from '@backstage/catalog-model';
import { EntityStatus } from './EntityStatus';
/**
* A version of the `Entity` type that contains unstable alpha fields.
*
* @remarks
*
* Available via the `@backstage/catalog-model/alpha` import.
*
* @alpha
*/
export interface AlphaEntity extends Entity {
/**
* The current status of the entity, as claimed by various sources.
*
* The keys are implementation defined and the values can be any JSON object
* with semantics that match that implementation.
*/
status?: EntityStatus;
}
@@ -15,7 +15,6 @@
*/
import { JsonObject } from '@backstage/types';
import { EntityStatus } from './EntityStatus';
/**
* The parts of the format that's common to all versions/kinds of entity.
@@ -54,25 +53,6 @@ export type Entity = {
relations?: EntityRelation[];
};
/**
* A version of the {@link Entity} type that contains unstable alpha fields.
*
* @remarks
*
* Available via the `@backstage/catalog-model/alpha` import.
*
* @alpha
*/
export interface AlphaEntity extends Entity {
/**
* The current status of the entity, as claimed by various sources.
*
* The keys are implementation defined and the values can be any JSON object
* with semantics that match that implementation.
*/
status?: EntityStatus;
}
/**
* Metadata fields common to all versions/kinds of entity.
*
+1 -12
View File
@@ -16,19 +16,8 @@
export * from './conditions';
export * from './constants';
export type {
AlphaEntity,
Entity,
EntityLink,
EntityMeta,
EntityRelation,
} from './Entity';
export type { Entity, EntityLink, EntityMeta, EntityRelation } from './Entity';
export type { EntityEnvelope } from './EntityEnvelope';
export type {
EntityStatus,
EntityStatusItem,
EntityStatusLevel,
} from './EntityStatus';
export * from './policies';
export {
getCompoundEntityRef,
+10
View File
@@ -127,11 +127,21 @@ Options:
Commands:
package-roles
package-scripts
package-exports
package-lint-configs
react-router-deps
help [command]
```
### `backstage-cli migrate package-exports`
```
Usage: backstage-cli migrate package-exports [options]
Options:
-h, --help
```
### `backstage-cli migrate package-lint-configs`
```
@@ -37,6 +37,7 @@ export async function buildBackend(options: BuildBackendOptions) {
// We build the target package without generating type declarations.
await buildPackage({
targetDir: options.targetDir,
packageJson: pkg,
outputs: new Set([Output.cjs]),
});
+8 -1
View File
@@ -116,7 +116,7 @@ export function registerScriptCommand(program: Command) {
)
.option(
'--experimental-type-build',
'Enable experimental type build. Does not apply to app or backend packages.',
'Enable experimental type build. Does not apply to app or backend packages. [DEPRECATED]',
)
.option(
'--skip-build-dependencies',
@@ -191,6 +191,13 @@ export function registerMigrateCommand(program: Command) {
lazy(() => import('./migrate/packageScripts').then(m => m.command)),
);
command
.command('package-exports')
.description('Synchronize package subpath export definitions')
.action(
lazy(() => import('./migrate/packageExports').then(m => m.command)),
);
command
.command('package-lint-configs')
.description(
@@ -0,0 +1,121 @@
/*
* Copyright 2020 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 fs from 'fs-extra';
import { resolve as resolvePath } from 'path';
import { ExtendedPackageJSON, PackageGraph } from '../../lib/monorepo';
function trimRelative(path: string): string {
if (path.startsWith('./')) {
return path.slice(2);
}
return path;
}
export async function command() {
const packages = await PackageGraph.listTargetPackages();
await Promise.all(
packages.map(async ({ dir, packageJson }) => {
let changed = false;
let newPackageJson = packageJson;
let { exports: exp } = newPackageJson;
if (!exp) {
return;
}
if (Array.isArray(exp)) {
throw new Error('Unexpected array in package.json exports field');
}
// If exports is a string we rewrite it to an object to add package.json
if (typeof exp === 'string') {
changed = true;
exp = { '.': exp };
newPackageJson.exports = exp;
} else if (typeof exp !== 'object') {
return;
}
if (!exp['./package.json']) {
changed = true;
exp['./package.json'] = './package.json';
}
const existingTypesVersions = JSON.stringify(packageJson.typesVersions);
const typeEntries: Record<string, [string]> = {};
for (const [path, value] of Object.entries(exp)) {
// Main entry point does not need to be listed
if (path === '.') {
continue;
}
const newPath = trimRelative(path);
if (typeof value === 'string') {
typeEntries[newPath] = [trimRelative(value)];
} else if (
value &&
typeof value === 'object' &&
!Array.isArray(value)
) {
if (typeof value.types === 'string') {
typeEntries[newPath] = [trimRelative(value.types)];
} else if (typeof value.default === 'string') {
typeEntries[newPath] = [trimRelative(value.default)];
}
}
}
const typesVersions = { '*': typeEntries };
if (existingTypesVersions !== JSON.stringify(typesVersions)) {
console.log(`Synchronizing exports in ${packageJson.name}`);
const newPkgEntries = Object.entries(newPackageJson).filter(
([name]) => name !== 'typesVersions',
);
newPkgEntries.splice(
newPkgEntries.findIndex(([name]) => name === 'exports') + 1,
0,
['typesVersions', typesVersions],
);
newPackageJson = Object.fromEntries(
newPkgEntries,
) as ExtendedPackageJSON;
changed = true;
}
// Remove the legacy fields from publishConfig, which are no longer needed
const publishConfig = newPackageJson.publishConfig as
| Record<string, string>
| undefined;
if (publishConfig) {
for (const field of ['main', 'module', 'browser', 'types']) {
if (publishConfig[field]) {
delete publishConfig[field];
changed = true;
}
}
}
if (changed) {
await fs.writeJson(resolvePath(dir, 'package.json'), newPackageJson, {
spaces: 2,
});
}
}),
);
}
+6 -67
View File
@@ -14,77 +14,16 @@
* limitations under the License.
*/
import fs from 'fs-extra';
import {
productionPack,
revertProductionPack,
} from '../lib/packager/productionPack';
import { paths } from '../lib/paths';
import { join as joinPath } from 'path';
const SKIPPED_KEYS = ['access', 'registry', 'tag', 'alphaTypes', 'betaTypes'];
const PKG_PATH = 'package.json';
const PKG_BACKUP_PATH = 'package.json-prepack';
function resolveEntrypoint(pkg: any, name: string) {
const targetEntry = pkg.publishConfig[name] || pkg[name];
return targetEntry && joinPath('..', targetEntry);
}
// Writes e.g. alpha/package.json
async function writeReleaseStageEntrypoint(pkg: any, stage: 'alpha' | 'beta') {
await fs.ensureDir(paths.resolveTarget(stage));
await fs.writeJson(
paths.resolveTarget(stage, PKG_PATH),
{
name: pkg.name,
version: pkg.version,
main: resolveEntrypoint(pkg, 'main'),
module: resolveEntrypoint(pkg, 'module'),
browser: resolveEntrypoint(pkg, 'browser'),
types: joinPath('..', pkg.publishConfig[`${stage}Types`]),
},
{ encoding: 'utf8', spaces: 2 },
);
}
export const pre = async () => {
const pkgPath = paths.resolveTarget(PKG_PATH);
const pkgContent = await fs.readFile(pkgPath, 'utf8');
const pkg = JSON.parse(pkgContent);
await fs.writeFile(PKG_BACKUP_PATH, pkgContent);
const publishConfig = pkg.publishConfig ?? {};
for (const key of Object.keys(publishConfig)) {
if (!SKIPPED_KEYS.includes(key)) {
pkg[key] = publishConfig[key];
}
}
await fs.writeJson(pkgPath, pkg, { encoding: 'utf8', spaces: 2 });
if (publishConfig.alphaTypes) {
await writeReleaseStageEntrypoint(pkg, 'alpha');
}
if (publishConfig.betaTypes) {
await writeReleaseStageEntrypoint(pkg, 'beta');
}
await productionPack({ packageDir: paths.targetDir });
};
export const post = async () => {
// postpack isn't called by yarn right now, so it needs to be called manually
try {
await fs.move(PKG_BACKUP_PATH, PKG_PATH, { overwrite: true });
// Check if we're shipping types for other release stages, clean up in that case
const pkg = await fs.readJson(PKG_PATH);
if (pkg.publishConfig?.alphaTypes) {
await fs.remove(paths.resolveTarget('alpha'));
}
if (pkg.publishConfig?.betaTypes) {
await fs.remove(paths.resolveTarget('beta'));
}
} catch (error) {
console.warn(
`Failed to restore package.json during postpack, ${error}. ` +
'Your package will be fine but you may have ended up with some garbage in the repo.',
);
}
await revertProductionPack(paths.targetDir);
};
+1
View File
@@ -130,6 +130,7 @@ export async function command(opts: OptionValues, cmd: Command): Promise<void> {
return {
targetDir: pkg.dir,
packageJson: pkg.packageJson,
outputs,
logPrefix: `${chalk.cyan(relativePath(paths.targetRoot, pkg.dir))}: `,
minify: buildOptions.minify,
@@ -24,6 +24,11 @@ describe('makeRollupConfigs', () => {
const [config] = await makeRollupConfigs({
outputs: new Set([Output.cjs]),
packageJson: {
name: 'test',
version: '0.0.0',
main: './src/index.ts',
},
});
const external = config.external as Exclude<
ExternalOption,
+116 -98
View File
@@ -31,6 +31,10 @@ import { forwardFileImports } from './plugins';
import { BuildOptions, Output } from './types';
import { paths } from '../paths';
import { svgrTemplate } from '../svgrTemplate';
import { ExtendedPackageJSON } from '../monorepo';
import { readEntryPoints } from '../monorepo/entryPoints';
const SCRIPT_EXTS = ['.js', '.jsx', '.ts', '.tsx'];
function isFileImport(source: string) {
if (source.startsWith('.')) {
@@ -50,6 +54,13 @@ export async function makeRollupConfigs(
): Promise<RollupOptions[]> {
const configs = new Array<RollupOptions>();
const targetDir = options.targetDir ?? paths.targetDir;
let targetPkg = options.packageJson;
if (!targetPkg) {
const packagePath = resolvePath(targetDir, 'package.json');
targetPkg = (await fs.readJson(packagePath)) as ExtendedPackageJSON;
}
const onwarn = ({ code, message }: RollupWarning) => {
if (code === 'EMPTY_BUNDLE') {
return; // We don't care about this one
@@ -62,111 +73,118 @@ export async function makeRollupConfigs(
};
const distDir = resolvePath(targetDir, 'dist');
const entryPoints = readEntryPoints(targetPkg);
if (options.outputs.has(Output.cjs) || options.outputs.has(Output.esm)) {
const output = new Array<OutputOptions>();
const mainFields = ['module', 'main'];
if (options.outputs.has(Output.cjs)) {
output.push({
dir: distDir,
entryFileNames: 'index.cjs.js',
chunkFileNames: 'cjs/[name]-[hash].cjs.js',
format: 'commonjs',
sourcemap: true,
});
}
if (options.outputs.has(Output.esm)) {
output.push({
dir: distDir,
entryFileNames: 'index.esm.js',
chunkFileNames: 'esm/[name]-[hash].esm.js',
format: 'module',
sourcemap: true,
});
// Assume we're building for the browser if ESM output is included
mainFields.unshift('browser');
for (const { path, name, ext } of entryPoints) {
if (!SCRIPT_EXTS.includes(ext)) {
continue;
}
configs.push({
input: resolvePath(targetDir, 'src/index.ts'),
output,
onwarn,
preserveEntrySignatures: 'strict',
// All module imports are always marked as external
external: (source, importer, isResolved) =>
Boolean(importer && !isResolved && !isFileImport(source)),
plugins: [
resolve({ mainFields }),
commonjs({
include: /node_modules/,
exclude: [/\/[^/]+\.(?:stories|test)\.[^/]+$/],
}),
postcss(),
forwardFileImports({
exclude: /\.icon\.svg$/,
include: [
/\.svg$/,
/\.png$/,
/\.gif$/,
/\.jpg$/,
/\.jpeg$/,
/\.eot$/,
/\.woff$/,
/\.woff2$/,
/\.ttf$/,
],
}),
json(),
yaml(),
svgr({
include: /\.icon\.svg$/,
template: svgrTemplate,
}),
esbuild({
target: 'es2019',
minify: options.minify,
}),
],
});
}
if (options.outputs.has(Output.cjs) || options.outputs.has(Output.esm)) {
const output = new Array<OutputOptions>();
const mainFields = ['module', 'main'];
if (options.outputs.has(Output.types) && !options.useApiExtractor) {
const typesInput = paths.resolveTargetRoot(
'dist-types',
relativePath(paths.targetRoot, targetDir),
'src/index.d.ts',
);
if (options.outputs.has(Output.cjs)) {
output.push({
dir: distDir,
entryFileNames: `${name}.cjs.js`,
chunkFileNames: `cjs/${name}/[name]-[hash].cjs.js`,
format: 'commonjs',
sourcemap: true,
});
}
if (options.outputs.has(Output.esm)) {
output.push({
dir: distDir,
entryFileNames: `${name}.esm.js`,
chunkFileNames: `esm/${name}/[name]-[hash].esm.js`,
format: 'module',
sourcemap: true,
});
// Assume we're building for the browser if ESM output is included
mainFields.unshift('browser');
}
const declarationsExist = await fs.pathExists(typesInput);
if (!declarationsExist) {
const path = relativePath(targetDir, typesInput);
throw new Error(
`No declaration files found at ${path}, be sure to run ${chalk.bgRed.white(
'yarn tsc',
)} to generate .d.ts files before packaging`,
configs.push({
input: resolvePath(targetDir, path),
output,
onwarn,
preserveEntrySignatures: 'strict',
// All module imports are always marked as external
external: (source, importer, isResolved) =>
Boolean(importer && !isResolved && !isFileImport(source)),
plugins: [
resolve({ mainFields }),
commonjs({
include: /node_modules/,
exclude: [/\/[^/]+\.(?:stories|test)\.[^/]+$/],
}),
postcss(),
forwardFileImports({
exclude: /\.icon\.svg$/,
include: [
/\.svg$/,
/\.png$/,
/\.gif$/,
/\.jpg$/,
/\.jpeg$/,
/\.eot$/,
/\.woff$/,
/\.woff2$/,
/\.ttf$/,
],
}),
json(),
yaml(),
svgr({
include: /\.icon\.svg$/,
template: svgrTemplate,
}),
esbuild({
target: 'es2019',
minify: options.minify,
}),
],
});
}
if (options.outputs.has(Output.types) && !options.useApiExtractor) {
const typesInput = paths.resolveTargetRoot(
'dist-types',
relativePath(paths.targetRoot, targetDir),
path.replace(/\.ts$/, '.d.ts'),
);
}
configs.push({
input: typesInput,
output: {
file: resolvePath(distDir, 'index.d.ts'),
format: 'es',
},
external: [
/\.css$/,
/\.scss$/,
/\.sass$/,
/\.svg$/,
/\.eot$/,
/\.woff$/,
/\.woff2$/,
/\.ttf$/,
],
onwarn,
plugins: [dts()],
});
const declarationsExist = await fs.pathExists(typesInput);
if (!declarationsExist) {
const declarationPath = relativePath(targetDir, typesInput);
throw new Error(
`No declaration files found at ${declarationPath}, be sure to run ${chalk.bgRed.white(
'yarn tsc',
)} to generate .d.ts files before packaging`,
);
}
configs.push({
input: typesInput,
output: {
file: resolvePath(distDir, `${name}.d.ts`),
format: 'es',
},
external: [
/\.css$/,
/\.scss$/,
/\.sass$/,
/\.svg$/,
/\.eot$/,
/\.woff$/,
/\.woff2$/,
/\.ttf$/,
],
onwarn,
plugins: [dts()],
});
}
}
return configs;
+3
View File
@@ -14,6 +14,8 @@
* limitations under the License.
*/
import { ExtendedPackageJSON } from '../monorepo';
export enum Output {
esm,
cjs,
@@ -23,6 +25,7 @@ export enum Output {
export type BuildOptions = {
logPrefix?: string;
targetDir?: string;
packageJson?: ExtendedPackageJSON;
outputs: Set<Output>;
minify?: boolean;
useApiExtractor?: boolean;
@@ -20,10 +20,15 @@ import { paths } from '../paths';
import { PackageRole } from '../role';
import { listChangedFiles, readFileAtRef } from '../git';
import { Lockfile } from '../versioning';
import { JsonValue } from '@backstage/types';
type PackageJSON = Package['packageJson'];
export interface ExtendedPackageJSON extends PackageJSON {
main?: string;
module?: string;
types?: string;
scripts?: {
[key: string]: string;
};
@@ -34,6 +39,19 @@ export interface ExtendedPackageJSON extends PackageJSON {
backstage?: {
role?: PackageRole;
};
exports?: JsonValue;
typesVersions?: Record<string, Record<string, string[]>>;
files?: string[];
publishConfig?: {
access?: 'public' | 'restricted';
directory?: string;
registry?: string;
alphaTypes?: string;
betaTypes?: string;
};
}
export type ExtendedPackage = {
@@ -0,0 +1,77 @@
/*
* Copyright 2023 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 { extname } from 'path';
import { ExtendedPackageJSON } from './PackageGraph';
export interface EntryPoint {
mount: string;
path: string;
name: string;
ext: string;
}
// Unless explicitly specified in exports, the index entrypoint is always
// assumed to be at src/index.ts for backwards compatibility.
const defaultIndex = {
mount: '.',
path: 'src/index.ts',
name: 'index',
ext: '.ts',
};
function parseEntryPoint(mount: string, path: string): EntryPoint {
let name = mount;
if (name === '.') {
name = 'index';
} else if (name.startsWith('./')) {
name = name.slice(2);
}
if (name.includes('/')) {
throw new Error(`Mount point '${mount}' may not contain multiple slashes`);
}
return { mount, path, name, ext: extname(path) };
}
export function readEntryPoints(pkg: ExtendedPackageJSON): Array<EntryPoint> {
const exp = pkg.exports;
if (typeof exp === 'string') {
return [defaultIndex];
} else if (exp && typeof exp === 'object' && !Array.isArray(exp)) {
const entryPoints = new Array<{
mount: string;
path: string;
name: string;
ext: string;
}>();
for (const mount of Object.keys(exp)) {
const path = exp[mount];
if (typeof path !== 'string') {
throw new Error(
`Exports field value must be a string, got '${JSON.stringify(path)}'`,
);
}
entryPoints.push(parseEntryPoint(mount, path));
}
return entryPoints;
}
return [defaultIndex];
}
@@ -1,93 +0,0 @@
/*
* 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 fs from 'fs-extra';
import npmPackList from 'npm-packlist';
import { join as joinPath, resolve as resolvePath } from 'path';
const SKIPPED_KEYS = ['access', 'registry', 'tag', 'alphaTypes', 'betaTypes'];
function resolveEntrypoint(pkg: any, name: string) {
const targetEntry = pkg.publishConfig[name] || pkg[name];
return targetEntry && joinPath('..', targetEntry);
}
// Writes e.g. alpha/package.json
async function writeReleaseStageEntrypoint(
pkg: any,
stage: 'alpha' | 'beta',
targetDir: string,
) {
await fs.ensureDir(resolvePath(targetDir, stage));
await fs.writeJson(
resolvePath(targetDir, stage, 'package.json'),
{
name: pkg.name,
version: pkg.version,
main: resolveEntrypoint(pkg, 'main'),
module: resolveEntrypoint(pkg, 'module'),
browser: resolveEntrypoint(pkg, 'browser'),
types: joinPath('..', pkg.publishConfig[`${stage}Types`]),
},
{ encoding: 'utf8', spaces: 2 },
);
}
export async function copyPackageDist(packageDir: string, targetDir: string) {
const pkgPath = resolvePath(packageDir, 'package.json');
const pkgContent = await fs.readFile(pkgPath, 'utf8');
const pkg = JSON.parse(pkgContent);
const publishConfig = pkg.publishConfig ?? {};
for (const key of Object.keys(publishConfig)) {
if (!SKIPPED_KEYS.includes(key)) {
pkg[key] = publishConfig[key];
}
}
// We remove the dependencies from package.json of packages that are marked
// as bundled, so that yarn doesn't try to install them.
if (pkg.bundled) {
delete pkg.dependencies;
delete pkg.devDependencies;
delete pkg.peerDependencies;
delete pkg.optionalDependencies;
}
// Lists all dist files, respecting .npmignore, files field in package.json, etc.
const filePaths = await npmPackList({
path: packageDir,
// This makes sure we use the update package.json when listing files
packageJsonCache: new Map([[resolvePath(packageDir, 'package.json'), pkg]]),
});
await fs.ensureDir(targetDir);
for (const filePath of filePaths.sort()) {
const target = resolvePath(targetDir, filePath);
if (filePath === 'package.json') {
await fs.writeJson(target, pkg, { encoding: 'utf8', spaces: 2 });
} else {
await fs.copy(resolvePath(packageDir, filePath), target);
}
}
if (publishConfig.alphaTypes) {
await writeReleaseStageEntrypoint(pkg, 'alpha', targetDir);
}
if (publishConfig.betaTypes) {
await writeReleaseStageEntrypoint(pkg, 'beta', targetDir);
}
}
@@ -37,7 +37,7 @@ import {
getOutputsForRole,
Output,
} from '../builder';
import { copyPackageDist } from './copyPackageDist';
import { productionPack } from './productionPack';
import { getRoleInfo } from '../role';
import { runParallelWorkers } from '../parallel';
@@ -178,6 +178,7 @@ export async function createDistWorkspace(
if (outputs.size > 0) {
standardBuilds.push({
targetDir: pkg.dir,
packageJson: pkg.packageJson,
outputs: outputs,
logPrefix: `${chalk.cyan(relativePath(paths.targetRoot, pkg.dir))}: `,
// No need to detect these for the backend builds, we assume no minification or types
@@ -257,7 +258,10 @@ async function moveToDistWorkspace(
const outputDir = relativePath(paths.targetRoot, target.dir);
const absoluteOutputPath = resolvePath(workspaceDir, outputDir);
await copyPackageDist(target.dir, absoluteOutputPath);
await productionPack({
packageDir: target.dir,
targetDir: absoluteOutputPath,
});
}),
);
@@ -0,0 +1,259 @@
/*
* Copyright 2023 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 fs from 'fs-extra';
import npmPackList from 'npm-packlist';
import { join as joinPath, resolve as resolvePath } from 'path';
import { ExtendedPackageJSON } from '../monorepo';
import { readEntryPoints } from '../monorepo/entryPoints';
const PKG_PATH = 'package.json';
const PKG_BACKUP_PATH = 'package.json-prepack';
const SKIPPED_KEYS = ['access', 'registry', 'tag', 'alphaTypes', 'betaTypes'];
const SCRIPT_EXTS = ['.js', '.jsx', '.ts', '.tsx'];
interface ProductionPackOptions {
packageDir: string;
targetDir?: string;
}
export async function productionPack(options: ProductionPackOptions) {
const { packageDir, targetDir } = options;
const pkgPath = resolvePath(packageDir, PKG_PATH);
const pkgContent = await fs.readFile(pkgPath, 'utf8');
const pkg = JSON.parse(pkgContent) as ExtendedPackageJSON;
// If we're making the update in-line, back up the package.json
if (!targetDir) {
await fs.writeFile(PKG_BACKUP_PATH, pkgContent);
}
const hasStageEntry =
!!pkg.publishConfig?.alphaTypes || !!pkg.publishConfig?.betaTypes;
if (pkg.exports && hasStageEntry) {
throw new Error(
'Combining both exports and alpha/beta types is not supported',
);
}
// This mutates pkg to fill in index exports, so call it before applying publishConfig
const writeCompatibilityEntryPoints = await prepareExportsEntryPoints(
pkg,
packageDir,
);
// TODO(Rugvip): Once exports are rolled out more broadly we should deprecate and remove this behavior
const publishConfig = pkg.publishConfig ?? {};
for (const key of Object.keys(publishConfig)) {
if (!SKIPPED_KEYS.includes(key)) {
(pkg as any)[key] = publishConfig[key as keyof typeof publishConfig];
}
}
// For published packages we rely on compatibility entry points rather than this
delete pkg.typesVersions;
// We remove the dependencies from package.json of packages that are marked
// as bundled, so that yarn doesn't try to install them.
if (pkg.bundled) {
delete pkg.dependencies;
delete pkg.devDependencies;
delete pkg.peerDependencies;
delete pkg.optionalDependencies;
}
if (targetDir) {
// Lists all dist files, respecting .npmignore, files field in package.json, etc.
const filePaths = await npmPackList({
path: packageDir,
// This makes sure we use the updated package.json when listing files
packageJsonCache: new Map([
[resolvePath(packageDir, PKG_PATH), pkg],
]) as any, // Seems like this parameter type is wrong,
});
await fs.ensureDir(targetDir);
for (const filePath of filePaths.sort()) {
const target = resolvePath(targetDir, filePath);
if (filePath === PKG_PATH) {
await fs.writeJson(target, pkg, { encoding: 'utf8', spaces: 2 });
} else {
await fs.copy(resolvePath(packageDir, filePath), target);
}
}
} else {
await fs.writeJson(pkgPath, pkg, { encoding: 'utf8', spaces: 2 });
}
if (publishConfig.alphaTypes) {
await writeReleaseStageEntrypoint(pkg, 'alpha', targetDir ?? packageDir);
}
if (publishConfig.betaTypes) {
await writeReleaseStageEntrypoint(pkg, 'beta', targetDir ?? packageDir);
}
if (writeCompatibilityEntryPoints) {
await writeCompatibilityEntryPoints(targetDir ?? packageDir);
}
}
// Reverts the changes made by productionPack when called without a targetDir.
export async function revertProductionPack(packageDir: string) {
// postpack isn't called by yarn right now, so it needs to be called manually
try {
await fs.move(PKG_BACKUP_PATH, PKG_PATH, { overwrite: true });
// Check if we're shipping types for other release stages, clean up in that case
const pkg = await fs.readJson(PKG_PATH);
if (pkg.publishConfig?.alphaTypes) {
await fs.remove(resolvePath(packageDir, 'alpha'));
}
if (pkg.publishConfig?.betaTypes) {
await fs.remove(resolvePath(packageDir, 'beta'));
}
// Remove any extra entrypoint backwards compatibility directories
const entryPoints = readEntryPoints(pkg);
for (const entryPoint of entryPoints) {
if (entryPoint.mount !== '.' && SCRIPT_EXTS.includes(entryPoint.ext)) {
await fs.remove(resolvePath(packageDir, entryPoint.name));
}
}
} catch (error) {
console.warn(
`Failed to restore package.json, ${error}. ` +
'Your package will be fine but you may have ended up with some garbage in the repo.',
);
}
}
function resolveEntrypoint(pkg: any, name: string) {
const targetEntry = pkg.publishConfig[name] || pkg[name];
return targetEntry && joinPath('..', targetEntry);
}
// Writes e.g. alpha/package.json
async function writeReleaseStageEntrypoint(
pkg: ExtendedPackageJSON,
stage: 'alpha' | 'beta',
targetDir: string,
) {
await fs.ensureDir(resolvePath(targetDir, stage));
await fs.writeJson(
resolvePath(targetDir, stage, PKG_PATH),
{
name: pkg.name,
version: pkg.version,
main: resolveEntrypoint(pkg, 'main'),
module: resolveEntrypoint(pkg, 'module'),
browser: resolveEntrypoint(pkg, 'browser'),
types: joinPath('..', pkg.publishConfig![`${stage}Types`]!),
},
{ encoding: 'utf8', spaces: 2 },
);
}
const EXPORT_MAP = {
import: '.esm.js',
require: '.cjs.js',
types: '.d.ts',
};
/**
* Rewrites the exports field in package.json to point to dist files, as
* well as returning a function that creates backwards compatibility
* entry points for importers that don't support exports.
*/
async function prepareExportsEntryPoints(
pkg: ExtendedPackageJSON,
packageDir: string,
) {
const distPath = resolvePath(packageDir, 'dist');
if (!(await fs.pathExists(distPath))) {
return undefined;
}
const distFiles = await fs.readdir(distPath);
const outputExports = {} as Record<string, Record<string, string>>;
const compatibilityWriters = new Array<
(targetDir: string) => Promise<void>
>();
const entryPoints = readEntryPoints(pkg);
for (const entryPoint of entryPoints) {
if (!SCRIPT_EXTS.includes(entryPoint.ext)) {
continue;
}
const exp = {} as Record<string, string>;
for (const [key, ext] of Object.entries(EXPORT_MAP)) {
const name = `${entryPoint.name}${ext}`;
if (distFiles.includes(name)) {
exp[key] = `./${joinPath(`dist`, name)}`;
}
}
exp.default = exp.require ?? exp.import;
// This creates a directory with a lone package.json for backwards compatibility
if (entryPoint.mount === '.') {
if (exp.default) {
pkg.main = exp.default;
}
if (exp.import) {
pkg.module = exp.import;
}
if (exp.types) {
pkg.types = exp.types;
}
} else {
// This is deferred until after we have created the target directory
compatibilityWriters.push(async targetDir => {
const entryPointDir = resolvePath(targetDir, entryPoint.name);
await fs.ensureDir(entryPointDir);
await fs.writeJson(
resolvePath(entryPointDir, PKG_PATH),
{
name: pkg.name,
version: pkg.version,
...(exp.default ? { main: joinPath('..', exp.default) } : {}),
...(exp.import ? { module: joinPath('..', exp.import) } : {}),
...(exp.types ? { types: joinPath('..', exp.types) } : {}),
},
{ encoding: 'utf8', spaces: 2 },
);
});
if (Array.isArray(pkg.files) && !pkg.files.includes(entryPoint.name)) {
pkg.files.push(entryPoint.name);
}
}
if (Object.keys(exp).length > 0) {
outputExports[entryPoint.mount] = exp;
}
}
if (pkg.exports) {
pkg.exports = outputExports;
// We treat package.json as a fixed export that is always available in the published package
pkg.exports['./package.json'] = './package.json';
}
if (compatibilityWriters.length > 0) {
return async (targetDir: string) => {
await Promise.all(compatibilityWriters.map(writer => writer(targetDir)));
};
}
return undefined;
}
@@ -0,0 +1,26 @@
## API Report File for "@backstage/core-plugin-api"
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
```ts
import { BackstagePlugin } from '@backstage/core-plugin-api';
import { ReactNode } from 'react';
// @alpha
export interface PluginOptionsProviderProps {
// (undocumented)
children: ReactNode;
// (undocumented)
plugin?: BackstagePlugin;
}
// @alpha
export const PluginProvider: (props: PluginOptionsProviderProps) => JSX.Element;
// @alpha
export function usePluginOptions<
TPluginOptions extends {} = {},
>(): TPluginOptions;
// (No @packageDocumentation comment for this package)
```
-16
View File
@@ -649,17 +649,6 @@ export type PluginFeatureFlagConfig = {
name: string;
};
// @alpha
export interface PluginOptionsProviderProps {
// (undocumented)
children: ReactNode;
// (undocumented)
plugin?: BackstagePlugin;
}
// @alpha
export const PluginProvider: (props: PluginOptionsProviderProps) => JSX.Element;
// @public
export type ProfileInfo = {
email?: string;
@@ -760,11 +749,6 @@ export function useElementFilter<T>(
dependencies?: any[],
): T;
// @alpha
export function usePluginOptions<
TPluginOptions extends {} = {},
>(): TPluginOptions;
// @public
export function useRouteRef<Optional extends boolean, Params extends AnyParams>(
routeRef: ExternalRouteRef<Params, Optional>,
+18 -7
View File
@@ -3,10 +3,22 @@
"description": "Core API used by Backstage plugins",
"version": "1.4.0",
"publishConfig": {
"access": "public",
"main": "dist/index.esm.js",
"types": "dist/index.d.ts",
"alphaTypes": "dist/index.alpha.d.ts"
"access": "public"
},
"exports": {
".": "./src/index.ts",
"./alpha": "./src/alpha.ts",
"./package.json": "./package.json"
},
"typesVersions": {
"*": {
"alpha": [
"src/alpha.ts"
],
"package.json": [
"package.json"
]
}
},
"backstage": {
"role": "web-library"
@@ -24,7 +36,7 @@
"main": "src/index.ts",
"types": "src/index.ts",
"scripts": {
"build": "backstage-cli package build --experimental-type-build",
"build": "backstage-cli package build",
"lint": "backstage-cli package lint",
"test": "backstage-cli package test",
"prepack": "backstage-cli package prepack",
@@ -60,7 +72,6 @@
"msw": "^0.49.0"
},
"files": [
"dist",
"alpha"
"dist"
]
}
+17
View File
@@ -0,0 +1,17 @@
/*
* Copyright 2023 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.
*/
export * from './plugin-options';
-1
View File
@@ -22,7 +22,6 @@
export * from './analytics';
export * from './apis';
export * from './plugin-options';
export * from './app';
export * from './extensions';
export * from './icons';
@@ -19,7 +19,7 @@ import {
createVersionedValueMap,
useVersionedContext,
} from '@backstage/version-bridge';
import { BackstagePlugin } from '../plugin';
import { BackstagePlugin } from '@backstage/core-plugin-api';
import React, { ReactNode } from 'react';
const contextKey: string = 'plugin-context';
+1
View File
@@ -29,6 +29,7 @@ Options:
-a, --allow-warnings <allowWarningsPaths>
--allow-all-warnings
-o, --omit-messages <messageCodes>
--validate-release-tags
-h, --help
```
+1
View File
@@ -45,6 +45,7 @@
},
"devDependencies": {
"@backstage/cli": "workspace:^",
"@backstage/types": "workspace:^",
"@types/is-glob": "^4.0.2",
"@types/mock-fs": "^4.13.0",
"mock-fs": "^5.1.0"
@@ -62,6 +62,7 @@ import { IMarkdownEmitterContext } from '@microsoft/api-documenter/lib/markdown/
import { AstDeclaration } from '@microsoft/api-extractor/lib/analyzer/AstDeclaration';
import { paths as cliPaths } from '../../lib/paths';
import minimatch from 'minimatch';
import { getPackageExportNames } from '../../lib/entryPoints';
const tmpDir = cliPaths.resolveTargetRoot(
'./node_modules/.cache/api-extractor',
@@ -237,10 +238,9 @@ export async function createTemporaryTsConfig(includedPackageDirs: string[]) {
return path;
}
export async function countApiReportWarnings(projectFolder: string) {
const path = resolvePath(projectFolder, 'api-report.md');
export async function countApiReportWarnings(reportPath: string) {
try {
const content = await fs.readFile(path, 'utf8');
const content = await fs.readFile(reportPath, 'utf8');
const lines = content.split('\n');
const lineWarnings = lines.filter(line =>
@@ -300,6 +300,32 @@ function logApiReportInstructions() {
console.log('');
}
async function findPackageEntryPoints(packageDirs: string[]): Promise<
Array<{
packageDir: string;
name: string;
usesExperimentalTypeBuild?: boolean;
}>
> {
return Promise.all(
packageDirs.map(async packageDir => {
const pkg = await fs.readJson(
cliPaths.resolveTargetRoot(packageDir, 'package.json'),
);
return (
getPackageExportNames(pkg)?.map(name => ({ packageDir, name })) ?? {
packageDir,
name: 'index',
usesExperimentalTypeBuild: pkg.scripts?.build?.includes(
'--experimental-type-build',
),
}
);
}),
).then(results => results.flat());
}
interface ApiExtractionOptions {
packageDirs: string[];
outputDir: string;
@@ -307,6 +333,7 @@ interface ApiExtractionOptions {
tsconfigFilePath: string;
allowWarnings?: boolean | string[];
omitMessages?: string[];
validateReleaseTags?: boolean;
}
export async function runApiExtraction({
@@ -316,12 +343,15 @@ export async function runApiExtraction({
tsconfigFilePath,
allowWarnings = false,
omitMessages = [],
validateReleaseTags = false,
}: ApiExtractionOptions) {
await fs.remove(outputDir);
const entryPoints = packageDirs.map(packageDir => {
const packageEntryPoints = await findPackageEntryPoints(packageDirs);
const entryPoints = packageEntryPoints.map(({ packageDir, name }) => {
return cliPaths.resolveTargetRoot(
`./dist-types/${packageDir}/src/index.d.ts`,
`./dist-types/${packageDir}/src/${name}.d.ts`,
);
});
@@ -337,7 +367,11 @@ export async function runApiExtraction({
}
const warnings = new Array<string>();
for (const packageDir of packageDirs) {
for (const {
packageDir,
name,
usesExperimentalTypeBuild,
} of packageEntryPoints) {
console.log(`## Processing ${packageDir}`);
const noBail = Array.isArray(allowWarnings)
? allowWarnings.some(aw => aw === packageDir || minimatch(packageDir, aw))
@@ -349,11 +383,15 @@ export async function runApiExtraction({
packageDir,
);
const warningCountBefore = await countApiReportWarnings(projectFolder);
const prefix = name === 'index' ? '' : `${name}-`;
const reportFileName = `${prefix}api-report.md`;
const reportPath = resolvePath(projectFolder, reportFileName);
const warningCountBefore = await countApiReportWarnings(reportPath);
const extractorConfig = ExtractorConfig.prepare({
configObject: {
mainEntryPointFilePath: resolvePath(packageFolder, 'src/index.d.ts'),
mainEntryPointFilePath: resolvePath(packageFolder, `src/${name}.d.ts`),
bundledPackages: [],
compiler: {
@@ -362,16 +400,21 @@ export async function runApiExtraction({
apiReport: {
enabled: true,
reportFileName: 'api-report.md',
reportFileName,
reportFolder: projectFolder,
reportTempFolder: resolvePath(outputDir, '<unscopedPackageName>'),
reportTempFolder: resolvePath(
outputDir,
`${prefix}<unscopedPackageName>`,
),
},
docModel: {
enabled: true,
// TODO(Rugvip): This skips docs for non-index entry points. We can try to work around it, but
// most likely it makes sense to wait for API Extractor to natively support exports.
enabled: name === 'index',
apiJsonFilePath: resolvePath(
outputDir,
'<unscopedPackageName>.api.json',
`${prefix}<unscopedPackageName>.api.json`,
),
},
@@ -461,6 +504,35 @@ export async function runApiExtraction({
compilerState,
});
// This release tag validation makes sure that the release tag of known entry points match expectations.
// The root index entrypoint is only allowed @public exports, while /alpha and /beta only allow @alpha and @beta.
if (validateReleaseTags && !usesExperimentalTypeBuild) {
if (['index', 'alpha', 'beta'].includes(name)) {
const report = await fs.readFile(
extractorConfig.reportFilePath,
'utf8',
);
const lines = report.split(/\r?\n/);
const expectedTag = name === 'index' ? 'public' : name;
for (let i = 0; i < lines.length; i += 1) {
const line = lines[i];
const match = line.match(/^\/\/ @(alpha|beta|public)/);
if (match && match[1] !== expectedTag) {
// Because of limitations in the type script rollup logic we need to allow public exports from the other release stages
// TODO(Rugvip): Try to work around the need for this exception
if (expectedTag !== 'public' && match[1] === 'public') {
continue;
}
throw new Error(
`Unexpected release tag ${match[1]} in ${
extractorConfig.reportFilePath
} at line ${i + 1}`,
);
}
}
}
}
if (!extractorResult.succeeded) {
if (shouldLogInstructions) {
logApiReportInstructions();
@@ -488,7 +560,7 @@ export async function runApiExtraction({
);
}
const warningCountAfter = await countApiReportWarnings(projectFolder);
const warningCountAfter = await countApiReportWarnings(reportPath);
if (noBail) {
console.log(`Skipping warnings check for ${packageDir}`);
}
@@ -33,6 +33,7 @@ type Options = {
allowWarnings?: string;
allowAllWarnings?: boolean;
omitMessages?: string;
validateReleaseTags?: boolean;
} & OptionValues;
export const buildApiReports = async (paths: string[] = [], opts: Options) => {
@@ -90,6 +91,7 @@ export const buildApiReports = async (paths: string[] = [], opts: Options) => {
tsconfigFilePath,
allowWarnings: allowAllWarnings || allowWarnings,
omitMessages: Array.isArray(omitMessages) ? omitMessages : [],
validateReleaseTags: opts.validateReleaseTags,
});
}
if (cliPackageDirs.length > 0) {
@@ -37,6 +37,10 @@ export function registerCommands(program: Command) {
'-o, --omit-messages <messageCodes>',
'select some message code to be omited on the API Extractor (comma separated values i.e ae-cyclic-inherit-doc,ae-missing-getter )',
)
.option(
'--validate-release-tags',
'Turn on release tag validation for the public, beta, and alpha APIs',
)
.description('Generate an API report for selected packages')
.action(
lazy(() =>
@@ -20,6 +20,7 @@ import { resolve as resolvePath } from 'path';
// eslint-disable-next-line @backstage/no-undeclared-imports
import chalk from 'chalk';
import { getPackages, Package } from '@manypkg/get-packages';
import { getPackageExportNames } from '../../lib/entryPoints';
export default async () => {
const { packages } = await getPackages(resolvePath('.'));
@@ -96,16 +97,23 @@ function findAllDeps(declSrc: string) {
* missing or incorrect in package.json
*/
function checkTypes(pkg: Package) {
const typeDecl = fs.readFileSync(
resolvePath(pkg.dir, 'dist/index.d.ts'),
'utf8',
);
const allDeps = findAllDeps(typeDecl);
const entryPointNames = getPackageExportNames(pkg.packageJson) ?? ['index'];
const allDeps = entryPointNames.flatMap(name => {
const typeDecl = fs.readFileSync(
resolvePath(pkg.dir, `dist/${name}.d.ts`),
'utf8',
);
return findAllDeps(typeDecl);
});
const deps = Array.from(new Set(allDeps));
const errors = [];
const typeDeps = [];
for (const dep of deps) {
for (let dep of deps) {
if (dep.endsWith('/*')) {
dep = dep.slice(0, -2);
}
try {
const typeDep = findTypesPackage(dep, pkg);
if (typeDep) {
@@ -0,0 +1,39 @@
/*
* Copyright 2023 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 { extname } from 'path';
import type { JsonObject } from '@backstage/types';
export function getPackageExportNames(pkg: JsonObject): string[] | undefined {
if (pkg.exports && typeof pkg.exports !== 'string') {
return Object.entries(pkg.exports).flatMap(([mount, path]) => {
const ext = extname(String(path));
if (!['.ts', '.tsx', '.cts', '.mts'].includes(ext)) {
return []; // Ignore non-TS entry points
}
let name = mount;
if (name.startsWith('./')) {
name = name.slice(2);
}
if (!name || name === '.') {
return ['index'];
}
return [name];
});
}
return undefined;
}
+14
View File
@@ -0,0 +1,14 @@
## API Report File for "@backstage/test-utils"
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
```ts
import { PropsWithChildren } from 'react';
// @alpha
export const MockPluginProvider: ({
children,
}: PropsWithChildren<{}>) => JSX.Element;
// (No @packageDocumentation comment for this package)
```
-6
View File
@@ -26,7 +26,6 @@ import { JsonValue } from '@backstage/types';
import { MatcherFunction } from '@testing-library/react';
import { Observable } from '@backstage/types';
import { PermissionApi } from '@backstage/plugin-permission-react';
import { PropsWithChildren } from 'react';
import { ReactElement } from 'react';
import { ReactNode } from 'react';
import { RenderOptions } from '@testing-library/react';
@@ -167,11 +166,6 @@ export class MockPermissionApi implements PermissionApi {
): Promise<EvaluatePermissionResponse>;
}
// @alpha
export const MockPluginProvider: ({
children,
}: PropsWithChildren<{}>) => JSX.Element;
// @public
export class MockStorageApi implements StorageApi {
// (undocumented)
+18 -7
View File
@@ -3,10 +3,22 @@
"description": "Utilities to test Backstage plugins and apps.",
"version": "1.2.5",
"publishConfig": {
"access": "public",
"main": "dist/index.esm.js",
"types": "dist/index.d.ts",
"alphaTypes": "dist/index.alpha.d.ts"
"access": "public"
},
"exports": {
".": "./src/index.ts",
"./alpha": "./src/alpha.ts",
"./package.json": "./package.json"
},
"typesVersions": {
"*": {
"alpha": [
"src/alpha.ts"
],
"package.json": [
"package.json"
]
}
},
"backstage": {
"role": "web-library"
@@ -24,7 +36,7 @@
"main": "src/index.ts",
"types": "src/index.ts",
"scripts": {
"build": "backstage-cli package build --experimental-type-build",
"build": "backstage-cli package build",
"lint": "backstage-cli package lint",
"test": "backstage-cli package test",
"prepack": "backstage-cli package prepack",
@@ -60,7 +72,6 @@
"msw": "^0.49.0"
},
"files": [
"dist",
"alpha"
"dist"
]
}
+17
View File
@@ -0,0 +1,17 @@
/*
* Copyright 2023 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.
*/
export * from './testUtils/MockPluginProvider';
@@ -15,7 +15,8 @@
*/
import React, { PropsWithChildren } from 'react';
import { createPlugin, PluginProvider } from '@backstage/core-plugin-api';
import { PluginProvider } from '@backstage/core-plugin-api/alpha';
import { createPlugin } from '@backstage/core-plugin-api';
/**
* Mock for PluginProvider to use in unit tests
@@ -25,7 +25,6 @@ export {
export type { TestAppOptions } from './appWrappers';
export * from './msw';
export * from './logCollector';
export * from './providers';
export * from './testingLibrary';
export { TestApiProvider, TestApiRegistry } from './TestApiProvider';
export type { TestApiProviderProps } from './TestApiProvider';
+21
View File
@@ -0,0 +1,21 @@
## API Report File for "@backstage/plugin-app-backend"
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
```ts
import { BackendFeature } from '@backstage/backend-plugin-api';
import express from 'express';
// @alpha
export const appPlugin: (options: AppPluginOptions) => BackendFeature;
// @alpha (undocumented)
export type AppPluginOptions = {
appPackageName?: string;
staticFallbackHandler?: express.Handler;
disableConfigInjection?: boolean;
disableStaticFallbackCache?: boolean;
};
// (No @packageDocumentation comment for this package)
```
-12
View File
@@ -3,23 +3,11 @@
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
```ts
import { BackendFeature } from '@backstage/backend-plugin-api';
import { Config } from '@backstage/config';
import express from 'express';
import { Logger } from 'winston';
import { PluginDatabaseManager } from '@backstage/backend-common';
// @alpha
export const appPlugin: (options: AppPluginOptions) => BackendFeature;
// @alpha (undocumented)
export type AppPluginOptions = {
appPackageName?: string;
staticFallbackHandler?: express.Handler;
disableConfigInjection?: boolean;
disableStaticFallbackCache?: boolean;
};
// @public (undocumented)
export function createRouter(options: RouterOptions): Promise<express.Router>;
+17 -6
View File
@@ -6,10 +6,22 @@
"types": "src/index.ts",
"license": "Apache-2.0",
"publishConfig": {
"access": "public",
"main": "dist/index.cjs.js",
"types": "dist/index.d.ts",
"alphaTypes": "dist/index.alpha.d.ts"
"access": "public"
},
"exports": {
".": "./src/index.ts",
"./alpha": "./src/alpha.ts",
"./package.json": "./package.json"
},
"typesVersions": {
"*": {
"alpha": [
"src/alpha.ts"
],
"package.json": [
"package.json"
]
}
},
"backstage": {
"role": "backend-plugin"
@@ -25,7 +37,7 @@
],
"scripts": {
"start": "backstage-cli package start",
"build": "backstage-cli package build --experimental-type-build",
"build": "backstage-cli package build",
"lint": "backstage-cli package lint",
"test": "backstage-cli package test",
"prepack": "backstage-cli package prepack",
@@ -63,7 +75,6 @@
},
"files": [
"dist",
"alpha",
"migrations/**/*.{js,d.ts}",
"static"
]
+18
View File
@@ -0,0 +1,18 @@
/*
* Copyright 2023 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.
*/
export { appPlugin } from './service/appPlugin';
export type { AppPluginOptions } from './service/appPlugin';
-2
View File
@@ -21,5 +21,3 @@
*/
export * from './service/router';
export { appPlugin } from './service/appPlugin';
export type { AppPluginOptions } from './service/appPlugin';
@@ -0,0 +1,12 @@
## API Report File for "@backstage/plugin-catalog-backend-module-aws"
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
```ts
import { BackendFeature } from '@backstage/backend-plugin-api';
// @alpha
export const awsS3EntityProviderCatalogModule: () => BackendFeature;
// (No @packageDocumentation comment for this package)
```
@@ -3,7 +3,6 @@
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
```ts
import { BackendFeature } from '@backstage/backend-plugin-api';
import { CatalogProcessor } from '@backstage/plugin-catalog-backend';
import { CatalogProcessorEmit } from '@backstage/plugin-catalog-backend';
import { CatalogProcessorParser } from '@backstage/plugin-catalog-backend';
@@ -88,7 +87,4 @@ export class AwsS3EntityProvider implements EntityProvider {
// (undocumented)
refresh(logger: Logger): Promise<void>;
}
// @alpha
export const awsS3EntityProviderCatalogModule: () => BackendFeature;
```
@@ -6,10 +6,22 @@
"types": "src/index.ts",
"license": "Apache-2.0",
"publishConfig": {
"access": "public",
"alphaTypes": "dist/index.alpha.d.ts",
"main": "dist/index.cjs.js",
"types": "dist/index.d.ts"
"access": "public"
},
"exports": {
".": "./src/index.ts",
"./alpha": "./src/alpha.ts",
"./package.json": "./package.json"
},
"typesVersions": {
"*": {
"alpha": [
"src/alpha.ts"
],
"package.json": [
"package.json"
]
}
},
"backstage": {
"role": "backend-plugin-module"
@@ -25,7 +37,7 @@
],
"scripts": {
"start": "backstage-cli package start",
"build": "backstage-cli package build --experimental-type-build",
"build": "backstage-cli package build",
"lint": "backstage-cli package lint",
"test": "backstage-cli package test",
"prepack": "backstage-cli package prepack",
@@ -60,7 +72,6 @@
"yaml": "^2.0.0"
},
"files": [
"alpha",
"config.d.ts",
"dist"
],
@@ -0,0 +1,17 @@
/*
* Copyright 2023 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.
*/
export { awsS3EntityProviderCatalogModule } from './service/AwsS3EntityProviderCatalogModule';
@@ -22,5 +22,4 @@
export * from './processors';
export * from './providers';
export { awsS3EntityProviderCatalogModule } from './service/AwsS3EntityProviderCatalogModule';
export * from './types';
@@ -22,7 +22,7 @@ import {
} from '@backstage/backend-tasks';
import { startTestBackend } from '@backstage/backend-test-utils';
import { ConfigReader } from '@backstage/config';
import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node';
import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node/alpha';
import { Duration } from 'luxon';
import { awsS3EntityProviderCatalogModule } from './AwsS3EntityProviderCatalogModule';
import { AwsS3EntityProvider } from '../providers';
@@ -19,7 +19,7 @@ import {
coreServices,
createBackendModule,
} from '@backstage/backend-plugin-api';
import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node';
import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node/alpha';
import { AwsS3EntityProvider } from '../providers';
/**
@@ -0,0 +1,12 @@
## API Report File for "@backstage/plugin-catalog-backend-module-azure"
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
```ts
import { BackendFeature } from '@backstage/backend-plugin-api';
// @alpha
export const azureDevOpsEntityProviderCatalogModule: () => BackendFeature;
// (No @packageDocumentation comment for this package)
```
@@ -3,7 +3,6 @@
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
```ts
import { BackendFeature } from '@backstage/backend-plugin-api';
import { CatalogProcessor } from '@backstage/plugin-catalog-backend';
import { CatalogProcessorEmit } from '@backstage/plugin-catalog-backend';
import { Config } from '@backstage/config';
@@ -56,7 +55,4 @@ export class AzureDevOpsEntityProvider implements EntityProvider {
// (undocumented)
refresh(logger: Logger): Promise<void>;
}
// @alpha
export const azureDevOpsEntityProviderCatalogModule: () => BackendFeature;
```
@@ -6,10 +6,22 @@
"types": "src/index.ts",
"license": "Apache-2.0",
"publishConfig": {
"access": "public",
"alphaTypes": "dist/index.alpha.d.ts",
"main": "dist/index.cjs.js",
"types": "dist/index.d.ts"
"access": "public"
},
"exports": {
".": "./src/index.ts",
"./alpha": "./src/alpha.ts",
"./package.json": "./package.json"
},
"typesVersions": {
"*": {
"alpha": [
"src/alpha.ts"
],
"package.json": [
"package.json"
]
}
},
"backstage": {
"role": "backend-plugin-module"
@@ -25,7 +37,7 @@
],
"scripts": {
"start": "backstage-cli package start",
"build": "backstage-cli package build --experimental-type-build",
"build": "backstage-cli package build",
"lint": "backstage-cli package lint",
"test": "backstage-cli package test",
"prepack": "backstage-cli package prepack",
@@ -56,7 +68,6 @@
"msw": "^0.49.0"
},
"files": [
"alpha",
"config.d.ts",
"dist"
],
@@ -0,0 +1,17 @@
/*
* Copyright 2023 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.
*/
export { azureDevOpsEntityProviderCatalogModule } from './service/AzureDevOpsEntityProviderCatalogModule';
@@ -22,4 +22,3 @@
export { AzureDevOpsDiscoveryProcessor } from './processors';
export { AzureDevOpsEntityProvider } from './providers';
export { azureDevOpsEntityProviderCatalogModule } from './service/AzureDevOpsEntityProviderCatalogModule';
@@ -22,7 +22,7 @@ import {
} from '@backstage/backend-tasks';
import { startTestBackend } from '@backstage/backend-test-utils';
import { ConfigReader } from '@backstage/config';
import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node';
import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node/alpha';
import { Duration } from 'luxon';
import { azureDevOpsEntityProviderCatalogModule } from './AzureDevOpsEntityProviderCatalogModule';
import { AzureDevOpsEntityProvider } from '../providers';
@@ -19,7 +19,7 @@ import {
createBackendModule,
coreServices,
} from '@backstage/backend-plugin-api';
import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node';
import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node/alpha';
import { AzureDevOpsEntityProvider } from '../providers';
/**
@@ -0,0 +1,12 @@
## API Report File for "@backstage/plugin-catalog-backend-module-bitbucket-cloud"
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
```ts
import { BackendFeature } from '@backstage/backend-plugin-api';
// @alpha (undocumented)
export const bitbucketCloudEntityProviderCatalogModule: () => BackendFeature;
// (No @packageDocumentation comment for this package)
```
@@ -3,7 +3,6 @@
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
```ts
import { BackendFeature } from '@backstage/backend-plugin-api';
import { CatalogApi } from '@backstage/catalog-client';
import { Config } from '@backstage/config';
import { EntityProvider } from '@backstage/plugin-catalog-backend';
@@ -46,7 +45,4 @@ export class BitbucketCloudEntityProvider
// (undocumented)
supportsEventTopics(): string[];
}
// @alpha (undocumented)
export const bitbucketCloudEntityProviderCatalogModule: () => BackendFeature;
```
@@ -6,10 +6,22 @@
"types": "src/index.ts",
"license": "Apache-2.0",
"publishConfig": {
"access": "public",
"alphaTypes": "dist/index.alpha.d.ts",
"main": "dist/index.cjs.js",
"types": "dist/index.d.ts"
"access": "public"
},
"exports": {
".": "./src/index.ts",
"./alpha": "./src/alpha.ts",
"./package.json": "./package.json"
},
"typesVersions": {
"*": {
"alpha": [
"src/alpha.ts"
],
"package.json": [
"package.json"
]
}
},
"backstage": {
"role": "backend-plugin-module"
@@ -25,7 +37,7 @@
],
"scripts": {
"start": "backstage-cli package start",
"build": "backstage-cli package build --experimental-type-build",
"build": "backstage-cli package build",
"lint": "backstage-cli package lint",
"test": "backstage-cli package test",
"prepack": "backstage-cli package prepack",
@@ -56,7 +68,6 @@
"msw": "^0.49.0"
},
"files": [
"alpha",
"config.d.ts",
"dist"
],
@@ -0,0 +1,17 @@
/*
* Copyright 2023 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.
*/
export { bitbucketCloudEntityProviderCatalogModule } from './service/BitbucketCloudEntityProviderCatalogModule';
@@ -21,4 +21,3 @@
*/
export { BitbucketCloudEntityProvider } from './BitbucketCloudEntityProvider';
export { bitbucketCloudEntityProviderCatalogModule } from './service/BitbucketCloudEntityProviderCatalogModule';
@@ -20,8 +20,8 @@ import {
TaskScheduleDefinition,
} from '@backstage/backend-tasks';
import { startTestBackend, mockServices } from '@backstage/backend-test-utils';
import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node';
import { eventsExtensionPoint } from '@backstage/plugin-events-node';
import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node/alpha';
import { eventsExtensionPoint } from '@backstage/plugin-events-node/alpha';
import { Duration } from 'luxon';
import { bitbucketCloudEntityProviderCatalogModule } from './BitbucketCloudEntityProviderCatalogModule';
import { BitbucketCloudEntityProvider } from '../BitbucketCloudEntityProvider';
@@ -22,8 +22,8 @@ import {
import {
catalogProcessingExtensionPoint,
catalogServiceRef,
} from '@backstage/plugin-catalog-node';
import { eventsExtensionPoint } from '@backstage/plugin-events-node';
} from '@backstage/plugin-catalog-node/alpha';
import { eventsExtensionPoint } from '@backstage/plugin-events-node/alpha';
import { BitbucketCloudEntityProvider } from '../BitbucketCloudEntityProvider';
/**
@@ -0,0 +1,12 @@
## API Report File for "@backstage/plugin-catalog-backend-module-bitbucket-server"
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
```ts
import { BackendFeature } from '@backstage/backend-plugin-api';
// @alpha (undocumented)
export const bitbucketServerEntityProviderCatalogModule: () => BackendFeature;
// (No @packageDocumentation comment for this package)
```
@@ -3,7 +3,6 @@
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
```ts
import { BackendFeature } from '@backstage/backend-plugin-api';
import { BitbucketServerIntegrationConfig } from '@backstage/integration';
import { Config } from '@backstage/config';
import { Entity } from '@backstage/catalog-model';
@@ -68,9 +67,6 @@ export class BitbucketServerEntityProvider implements EntityProvider {
refresh(logger: Logger): Promise<void>;
}
// @alpha (undocumented)
export const bitbucketServerEntityProviderCatalogModule: () => BackendFeature;
// @public (undocumented)
export type BitbucketServerListOptions = {
[key: string]: number | undefined;
@@ -5,10 +5,22 @@
"types": "src/index.ts",
"license": "Apache-2.0",
"publishConfig": {
"access": "public",
"alphaTypes": "dist/index.alpha.d.ts",
"main": "dist/index.cjs.js",
"types": "dist/index.d.ts"
"access": "public"
},
"exports": {
".": "./src/index.ts",
"./alpha": "./src/alpha.ts",
"./package.json": "./package.json"
},
"typesVersions": {
"*": {
"alpha": [
"src/alpha.ts"
],
"package.json": [
"package.json"
]
}
},
"backstage": {
"role": "backend-plugin-module"
@@ -24,7 +36,7 @@
],
"scripts": {
"start": "backstage-cli package start",
"build": "backstage-cli package build --experimental-type-build",
"build": "backstage-cli package build",
"lint": "backstage-cli package lint",
"test": "backstage-cli package test",
"prepack": "backstage-cli package prepack",
@@ -53,7 +65,6 @@
"msw": "^0.49.0"
},
"files": [
"alpha",
"config.d.ts",
"dist"
],
@@ -0,0 +1,17 @@
/*
* Copyright 2023 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.
*/
export { bitbucketServerEntityProviderCatalogModule } from './service/BitbucketServerEntityProviderCatalogModule';
@@ -29,4 +29,3 @@ export type {
} from './lib';
export { BitbucketServerEntityProvider } from './providers';
export type { BitbucketServerLocationParser } from './providers';
export { bitbucketServerEntityProviderCatalogModule } from './service/BitbucketServerEntityProviderCatalogModule';
@@ -22,7 +22,7 @@ import {
TaskScheduleDefinition,
} from '@backstage/backend-tasks';
import { startTestBackend } from '@backstage/backend-test-utils';
import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node';
import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node/alpha';
import { bitbucketServerEntityProviderCatalogModule } from './BitbucketServerEntityProviderCatalogModule';
import { Duration } from 'luxon';
import { BitbucketServerEntityProvider } from '../providers';
@@ -19,7 +19,7 @@ import {
coreServices,
createBackendModule,
} from '@backstage/backend-plugin-api';
import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node';
import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node/alpha';
import { BitbucketServerEntityProvider } from '../providers';
/**
@@ -0,0 +1,12 @@
## API Report File for "@backstage/plugin-catalog-backend-module-gerrit"
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
```ts
import { BackendFeature } from '@backstage/backend-plugin-api';
// @alpha (undocumented)
export const gerritEntityProviderCatalogModule: () => BackendFeature;
// (No @packageDocumentation comment for this package)
```
@@ -3,7 +3,6 @@
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
```ts
import { BackendFeature } from '@backstage/backend-plugin-api';
import { Config } from '@backstage/config';
import { EntityProvider } from '@backstage/plugin-catalog-backend';
import { EntityProviderConnection } from '@backstage/plugin-catalog-backend';
@@ -30,8 +29,5 @@ export class GerritEntityProvider implements EntityProvider {
refresh(logger: Logger): Promise<void>;
}
// @alpha (undocumented)
export const gerritEntityProviderCatalogModule: () => BackendFeature;
// (No @packageDocumentation comment for this package)
```
@@ -5,10 +5,22 @@
"types": "src/index.ts",
"license": "Apache-2.0",
"publishConfig": {
"access": "public",
"alphaTypes": "dist/index.alpha.d.ts",
"main": "dist/index.cjs.js",
"types": "dist/index.d.ts"
"access": "public"
},
"exports": {
".": "./src/index.ts",
"./alpha": "./src/alpha.ts",
"./package.json": "./package.json"
},
"typesVersions": {
"*": {
"alpha": [
"src/alpha.ts"
],
"package.json": [
"package.json"
]
}
},
"backstage": {
"role": "backend-plugin-module"
@@ -21,7 +33,7 @@
},
"scripts": {
"start": "backstage-cli package start",
"build": "backstage-cli package build --experimental-type-build",
"build": "backstage-cli package build",
"lint": "backstage-cli package lint",
"test": "backstage-cli package test",
"prepack": "backstage-cli package prepack",
@@ -0,0 +1,17 @@
/*
* Copyright 2023 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.
*/
export { gerritEntityProviderCatalogModule } from './service/GerritEntityProviderCatalogModule';
@@ -15,4 +15,3 @@
*/
export { GerritEntityProvider } from './providers/GerritEntityProvider';
export { gerritEntityProviderCatalogModule } from './service/GerritEntityProviderCatalogModule';
@@ -22,7 +22,7 @@ import {
} from '@backstage/backend-tasks';
import { startTestBackend } from '@backstage/backend-test-utils';
import { ConfigReader } from '@backstage/config';
import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node';
import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node/alpha';
import { Duration } from 'luxon';
import { gerritEntityProviderCatalogModule } from './GerritEntityProviderCatalogModule';
import { GerritEntityProvider } from '../providers/GerritEntityProvider';
@@ -19,7 +19,7 @@ import {
coreServices,
createBackendModule,
} from '@backstage/backend-plugin-api';
import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node';
import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node/alpha';
import { GerritEntityProvider } from '../providers/GerritEntityProvider';
/**
@@ -0,0 +1,12 @@
## API Report File for "@backstage/plugin-catalog-backend-module-github"
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
```ts
import { BackendFeature } from '@backstage/backend-plugin-api';
// @alpha
export const githubEntityProviderCatalogModule: () => BackendFeature;
// (No @packageDocumentation comment for this package)
```

Some files were not shown because too many files have changed in this diff Show More