diff --git a/packages/cli/src/lib/__testUtils__/createFeatureEnvironment.ts b/packages/cli/src/lib/__testUtils__/createFeatureEnvironment.ts index 51848a9d68..07c8f4f853 100644 --- a/packages/cli/src/lib/__testUtils__/createFeatureEnvironment.ts +++ b/packages/cli/src/lib/__testUtils__/createFeatureEnvironment.ts @@ -15,20 +15,11 @@ */ import { PackageRole } from '@backstage/cli-node'; -import { resolve as resolvePath } from 'path'; import { Project } from 'ts-morph'; import { EntryPoint } from '../entryPoints'; -import { - getDistTypeRoot, - BackstagePackageFeatureType, -} from '../typeDistProject'; +import { BackstagePackageFeatureType } from '../typeDistProject'; -const mockEntryPoint = { - mount: '.', - path: './src/index.d.ts', - name: 'index', - ext: '.d.ts', -}; +const mockEntryPoint = 'dist/index.d.ts'; type CreateFeatureEnvironmentOptions = { $$type?: BackstagePackageFeatureType; @@ -44,7 +35,7 @@ type FeatureEnvironment = { project: Project; role: PackageRole; dir: string; - entryPoint: EntryPoint; + entryPoint: string; }; type File = { @@ -54,7 +45,7 @@ type File = { const createTestType = ($$type: BackstagePackageFeatureType): File[] => [ { - path: './src/createTestType.d.ts', + path: './dist/createTestType.d.ts', content: ` export interface TestType { readonly $$type: '${$$type}'; @@ -71,7 +62,7 @@ export function createTestType(): TestType { const createMockDefaultExportAssignment = (): File[] => [ { - path: mockEntryPoint.path, + path: mockEntryPoint, content: ` declare const _default: import("./createTestType").TestType; export default _default; @@ -81,11 +72,11 @@ export default _default; const createMockDefaultExportFromFile = (): File[] => [ { - path: mockEntryPoint.path, + path: mockEntryPoint, content: `export { default } from './linked';`, }, { - path: './src/linked.d.ts', + path: './dist/linked.d.ts', content: ` declare const _default: import("./createTestType").TestType; export default _default; @@ -95,11 +86,11 @@ export default _default; const createMockDefaultExportFromFileAsDefault = (): File[] => [ { - path: mockEntryPoint.path, + path: mockEntryPoint, content: `export { test as default } from './linked';`, }, { - path: './src/linked.d.ts', + path: './dist/linked.d.ts', content: ` export declare const test: import("./createTestType").TestType; `, @@ -108,11 +99,11 @@ export declare const test: import("./createTestType").TestType; const createMockDefaultExportFromFileWithSibling = (): File[] => [ { - path: mockEntryPoint.path, + path: mockEntryPoint, content: `export { default, test } from './linked';`, }, { - path: './src/linked.d.ts', + path: './dist/linked.d.ts', content: ` import { createTestType } from './createTestType'; @@ -143,10 +134,7 @@ export default function createFeatureEnvironment( const files = [...createTestType($$type), ...formatToFiles[format]()]; for (const file of files) { - project.createSourceFile( - resolvePath(getDistTypeRoot(''), file.path), - file.content, - ); + project.createSourceFile(file.path, file.content); } return { diff --git a/packages/cli/src/lib/packager/productionPack.ts b/packages/cli/src/lib/packager/productionPack.ts index e4a1c13ffd..656b98f9fb 100644 --- a/packages/cli/src/lib/packager/productionPack.ts +++ b/packages/cli/src/lib/packager/productionPack.ts @@ -166,19 +166,22 @@ async function prepareExportsEntryPoints( exp[key] = `./${posixPath.join(`dist`, name)}`; } } + exp.default = exp.require ?? exp.import; - const defaultFeatureType = - pkg.backstage?.role && - getEntryPointDefaultFeatureType( - pkg.backstage?.role, - packageDir, - project, - entryPoint, - ); + if (exp.types) { + const defaultFeatureType = + pkg.backstage?.role && + getEntryPointDefaultFeatureType( + pkg.backstage?.role, + packageDir, + project, + exp.types, + ); - if (defaultFeatureType) { - exp.backstage = defaultFeatureType; + if (defaultFeatureType) { + exp.backstage = defaultFeatureType; + } } // This creates a directory with a lone package.json for backwards compatibility diff --git a/packages/cli/src/lib/typeDistProject.ts b/packages/cli/src/lib/typeDistProject.ts index 6845272433..cd5eb9cd74 100644 --- a/packages/cli/src/lib/typeDistProject.ts +++ b/packages/cli/src/lib/typeDistProject.ts @@ -14,114 +14,16 @@ * limitations under the License. */ import { findPaths } from '@backstage/cli-common'; -import { PackageGraph, PackageRole } from '@backstage/cli-node'; -import { builtinModules } from 'module'; +import { PackageRole } from '@backstage/cli-node'; import { resolve as resolvePath } from 'path'; import { Project, SourceFile, SyntaxKind, ts, Type } from 'ts-morph'; -import { EntryPoint, readEntryPoints } from './entryPoints'; - -export const getDistTypeRoot = (dir: string) => { - const workspaceRoot = findPaths(process.cwd()).targetRoot; - const relativeDirectory = dir.replace(workspaceRoot, ''); - const distTypeRoot = resolvePath( - workspaceRoot, - `./dist-types${relativeDirectory}`, - ); - - return distTypeRoot; -}; - -const getPackagesDistTypeMap = async () => { - const packages = await PackageGraph.listTargetPackages(); - const distTypeMap: Record = {}; - - for (const { dir, packageJson } of packages) { - const distTypeRoot = getDistTypeRoot(dir); - - for (const { name, path, ext } of readEntryPoints(packageJson)) { - const dtsPath = resolvePath(distTypeRoot, path.replace(ext, '.d.ts')); - - if (name === 'index') { - distTypeMap[packageJson.name] = dtsPath; - } else { - distTypeMap[`${packageJson.name}/${name}`] = dtsPath; - } - } - } - - return distTypeMap; -}; export const createTypeDistProject = async () => { - const distTypeMap = await getPackagesDistTypeMap(); - const assetTypeExtensions = await getAssetTypeExtensions(); const workspaceRoot = findPaths(process.cwd()).targetRoot; return new Project({ tsConfigFilePath: resolvePath(workspaceRoot, 'tsconfig.json'), skipAddingFilesFromTsConfig: true, - resolutionHost: (moduleResolutionHost, getCompilerOptions) => { - return { - resolveModuleNames: (moduleNames, containingFile) => { - const compilerOptions = getCompilerOptions(); - const resolvedModules: ts.ResolvedModule[] = []; - - for (let moduleName of moduleNames) { - // Handle resolving asset-type modules - for (const ext of assetTypeExtensions) { - if (moduleName.endsWith(ext)) { - moduleName = '@backstage/cli/asset-types'; - } - } - - // Handle resolving internal plugins and package entry points to dist-types folder - if (distTypeMap[moduleName]) { - resolvedModules.push({ - resolvedFileName: distTypeMap[moduleName], - isExternalLibraryImport: false, - resolvedUsingTsExtension: false, - }); - continue; - } - - // Handle resolving builtin node modules to @types/node - if (moduleName.startsWith('node:')) { - moduleName = moduleName.slice(5); - } - if (builtinModules.includes(moduleName)) { - const result = ts.resolveModuleName( - `@types/node/${moduleName}`, - containingFile, - compilerOptions, - moduleResolutionHost, - ); - - if (result.resolvedModule) { - resolvedModules.push(result.resolvedModule); - continue; - } - } - - // Handle resolving relative paths and external node_modules. - const result = ts.resolveModuleName( - moduleName, - containingFile, - compilerOptions, - moduleResolutionHost, - ); - - if (result.resolvedModule) { - resolvedModules.push(result.resolvedModule); - continue; - } - - throw new Error(`Failed to resolve module: ${moduleName}`); - } - - return resolvedModules; - }, - }; - }, }); }; @@ -150,17 +52,14 @@ export const getEntryPointDefaultFeatureType = ( role: PackageRole, packageDir: string, project: Project, - entryPoint: EntryPoint, + entryPoint: string, ): BackstagePackageFeatureType | null => { if (isTargetPackageRole(role)) { - const dtsPath = resolvePath( - getDistTypeRoot(packageDir), - entryPoint.path.replace(entryPoint.ext, '.d.ts'), - ); + const distPath = resolvePath(packageDir, entryPoint); try { const defaultFeatureType = getSourceFileDefaultFeatureType( - project.addSourceFileAtPath(dtsPath), + project.addSourceFileAtPath(distPath), ); if (defaultFeatureType) { @@ -168,7 +67,7 @@ export const getEntryPointDefaultFeatureType = ( } } catch (error) { console.error( - `Failed to extract default feature type from ${dtsPath}, ${error}. ` + + `Failed to extract default feature type from ${distPath}, ${error}. ` + 'Your package will publish fine but it may be missing metadata about its default feature.', ); } @@ -252,27 +151,3 @@ function isTargetFeatureType( !!type && targetFeatureTypes.includes(type as BackstagePackageFeatureType) ); } - -// Returns an array of the ending extensions fro the asset-types -// that are supported by the Backstage CLI -async function getAssetTypeExtensions() { - const assetTypes: string[] = []; - const assetTypesDts = await getAssetTypesDtsFilePath(); - const project = new Project({}); - const sourceFile = project.addSourceFileAtPath(assetTypesDts); - - for (const module of sourceFile.getModules()) { - assetTypes.push( - module - .getName() - .replace(/'/g, '') // remove surrounding single quotes - .replace(/^\*/g, ''), // remove leading * - ); - } - - return assetTypes; -} - -async function getAssetTypesDtsFilePath() { - return require.resolve('@backstage/cli/asset-types/asset-types.d.ts'); -}