Skip to content

Commit

Permalink
breaking: Remove API extractor. (#104)
Browse files Browse the repository at this point in the history
* Remove api extractor.

* Remove types.

* Clean up tests.

* Update docs.

* Fix changelog.
  • Loading branch information
milesj committed Apr 20, 2022
1 parent 5b16274 commit e3270e1
Show file tree
Hide file tree
Showing 21 changed files with 90 additions and 824 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"prerelease": "yarn run clean && yarn run setup && yarn run pack && yarn run check",
"release": "yarn prerelease && beemo run-script lerna-release",
"version": "yarn install && git add yarn.lock",
"pack": "NODE_ENV=production yarn run packemon build --addEngines --addExports --declaration=standard",
"pack": "NODE_ENV=production yarn run packemon build --addEngines --addExports --declaration",
"packemon": "node ./packages/packemon/lib/bin.js"
},
"workspaces": [
Expand Down
21 changes: 8 additions & 13 deletions packages/packemon/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,21 +20,16 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline
**Note:** Version bump only for package packemon


## 1.14.1 - 2022-03-19

#### 📦 Dependencies


## <small>1.14.1 (2022-03-19)</small>

* deps: Update internals. ([3aba5ac](https://github.com/milesj/packemon/commit/3aba5ac))
* deps(beemo): Update to v2 latest. ([d6aeac1](https://github.com/milesj/packemon/commit/d6aeac1))
* deps(magic-string): Update to v0.26. ([dde44a1](https://github.com/milesj/packemon/commit/dde44a1))
* deps(npm-packlist): Update to v4. ([263013e](https://github.com/milesj/packemon/commit/263013e))
* deps(rollup-plugin-visualizer): Update to v5.6. ([0ed1404](https://github.com/milesj/packemon/commit/0ed1404))
* deps(rollup): Update to v2.70. (#103) ([a1af6ef](https://github.com/milesj/packemon/commit/a1af6ef)), closes [#103](https://github.com/milesj/packemon/issues/103)
* tests: Fix failing visualizer test. ([828ea38](https://github.com/milesj/packemon/commit/828ea38))



- Update internals. ([3aba5ac](https://github.com/milesj/packemon/commit/3aba5ac))
- **[beemo]** Update to v2 latest. ([d6aeac1](https://github.com/milesj/packemon/commit/d6aeac1))
- **[magic-string]** Update to v0.26. ([dde44a1](https://github.com/milesj/packemon/commit/dde44a1))
- **[npm-packlist]** Update to v4. ([263013e](https://github.com/milesj/packemon/commit/263013e))
- **[rollup-plugin-visualizer]** Update to v5.6. ([0ed1404](https://github.com/milesj/packemon/commit/0ed1404))
- **[rollup]** Update to v2.70. (#103) ([a1af6ef](https://github.com/milesj/packemon/commit/a1af6ef)), closes [#103](https://github.com/milesj/packemon/issues/103)


## 1.14.0 - 2022-02-23
Expand Down
1 change: 0 additions & 1 deletion packages/packemon/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@
"@boost/event": "^3.0.1",
"@boost/pipeline": "^3.2.2",
"@boost/terminal": "^3.0.0",
"@microsoft/api-extractor": "^7.19.5",
"@rollup/plugin-babel": "^5.3.1",
"@rollup/plugin-commonjs": "^21.0.2",
"@rollup/plugin-json": "^4.1.0",
Expand Down
5 changes: 2 additions & 3 deletions packages/packemon/src/Packemon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ export class Packemon {
*/
generateArtifacts(
packages: Package[],
{ declaration = 'none', filterFormats, filterPlatforms }: BuildOptions = {},
{ declaration, filterFormats, filterPlatforms }: BuildOptions = {},
): Package[] {
this.debug('Generating artifacts for packages');

Expand Down Expand Up @@ -294,10 +294,9 @@ export class Packemon {
});
});

if (declaration !== 'none') {
if (declaration) {
const artifact = new TypesArtifact(pkg, Object.values(typesBuilds));
artifact.api = apiType;
artifact.declarationType = declaration;

pkg.addArtifact(artifact);
}
Expand Down
15 changes: 1 addition & 14 deletions packages/packemon/src/Project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import semver from 'semver';
import { Memoize, Path, Project as BaseProject, VirtualPath } from '@boost/common';
import { getVersion } from './helpers/getVersion';
import { Package } from './Package';
import { DeclarationType } from './types';

export class Project extends BaseProject {
workspaces: string[] = [];
Expand Down Expand Up @@ -39,11 +38,7 @@ export class Project extends BaseProject {
return this.workspaces.length > 0;
}

async generateDeclarations(
declarationType: DeclarationType,
pkgPath?: Path,
declarationConfig?: string,
): Promise<unknown> {
async generateDeclarations(pkgPath?: Path, declarationConfig?: string): Promise<unknown> {
if (this.buildPromise) {
return this.buildPromise;
}
Expand All @@ -55,14 +50,6 @@ export class Project extends BaseProject {
if (this.isWorkspacesEnabled()) {
args.push('--build');

// Since we collapse all DTS into a single file,
// we need to force build to overwrite the types,
// since they're not what the TS build expects.
if (declarationType) {
// TODO: This seems to always be required??
args.push('--force');
}

// Only build the specific project when applicable
if (pkgPath) {
let projectPath = this.root.relativeTo(pkgPath);
Expand Down
180 changes: 6 additions & 174 deletions packages/packemon/src/TypesArtifact.ts
Original file line number Diff line number Diff line change
@@ -1,76 +1,20 @@
import glob from 'fast-glob';
import fs from 'fs-extra';
import { Path, VirtualPath } from '@boost/common';
import { VirtualPath } from '@boost/common';
import { createDebugger, Debugger } from '@boost/debug';
import { Extractor, ExtractorConfig } from '@microsoft/api-extractor';
import { Artifact } from './Artifact';
import { removeSourcePath } from './helpers/removeSourcePath';
import {
APIExtractorStructure,
BuildOptions,
DeclarationType,
PackageExports,
TSConfigStructure,
TypesBuild,
} from './types';
import { apiExtractorConfig } from './typescript/apiExtractorConfig';
import { BuildOptions, PackageExports, TSConfigStructure, TypesBuild } from './types';

export class TypesArtifact extends Artifact<TypesBuild> {
declarationType: DeclarationType = 'standard';

protected debug!: Debugger;

override startup() {
this.debug = createDebugger(['packemon', 'types', this.package.getSlug(), this.getLabel()]);
}

override async cleanup(): Promise<void> {
// API extractor config files
await this.removeFiles(
this.builds.map(({ outputName }) => this.getApiExtractorConfigPath(outputName)),
);
}

async build(options: BuildOptions): Promise<void> {
this.debug('Building "%s" types artifact with TypeScript', this.declarationType);

const tsConfig = this.loadTsconfigJson();

// Compile the current projects declarations
this.debug('Generating declarations at the root using `tsc`');

await this.package.project.generateDeclarations(
this.declarationType,
this.package.path,
options.declarationConfig,
);

// Combine all DTS files into a single file for each input
if (this.declarationType === 'api') {
this.debug('Combining declarations into a single API declaration file');

// Resolved compiler options use absolute paths, so we should match
let dtsBuildPath = this.package.path.append('dts');

// Workspaces use the tsconfig setting, while non-workspaces is hard-coded to "dts"
if (tsConfig && this.package.project.isWorkspacesEnabled()) {
dtsBuildPath = new Path(
tsConfig.options.declarationDir ?? tsConfig.options.outDir ?? dtsBuildPath,
);
}
this.debug('Building types artifact with TypeScript');

await Promise.all(
this.builds.map(({ inputFile, outputName }) =>
this.generateApiDeclaration(outputName, inputFile, dtsBuildPath),
),
);

// Remove the TS output directory to reduce package size.
// We do this in the background to speed up the CLI process!
this.debug('Removing old and unnecessary declarations in the background');

void this.removeDeclarationBuild(dtsBuildPath);
}
await this.package.project.generateDeclarations(this.package.path, options.declarationConfig);
}

findEntryPoint(outputName: string): string {
Expand All @@ -80,11 +24,7 @@ export class TypesArtifact extends Artifact<TypesBuild> {
return '';
}

// When not generating individual API declarations, we need to mirror the source structure
const entry =
this.declarationType === 'standard' ? removeSourcePath(output.inputFile) : outputName;

return `./${new VirtualPath('dts', entry)}.d.ts`;
return `./${new VirtualPath('dts', removeSourcePath(output.inputFile))}.d.ts`;
}

getLabel(): string {
Expand All @@ -98,7 +38,7 @@ export class TypesArtifact extends Artifact<TypesBuild> {
getPackageExports(): PackageExports {
const exportMap: PackageExports = {};

if (this.api === 'private' || this.declarationType === 'api') {
if (this.api === 'private') {
this.builds.forEach(({ outputName }) => {
exportMap[outputName === 'index' ? '.' : `./${outputName}`] = {
types: this.findEntryPoint(outputName),
Expand All @@ -116,117 +56,9 @@ export class TypesArtifact extends Artifact<TypesBuild> {
return `types (${this.getLabel()})`;
}

protected async generateApiDeclaration(
outputName: string,
inputFile: string,
dtsBuildPath: Path,
): Promise<void> {
const dtsEntryPoint = dtsBuildPath.append(`${removeSourcePath(inputFile)}.d.ts`);

if (!dtsEntryPoint.exists()) {
console.warn(
`Unable to generate declaration for "${outputName}". Declaration entry point "${dtsEntryPoint}" does not exist.`,
);

return;
}

// Create a fake config file
const configPath = this.getApiExtractorConfigPath(outputName).path();
const config: APIExtractorStructure = {
...apiExtractorConfig,
projectFolder: VirtualPath.create(this.package.path).path(),
mainEntryPointFilePath: VirtualPath.create(dtsEntryPoint).path(),
dtsRollup: {
...apiExtractorConfig.dtsRollup,
untrimmedFilePath: `<projectFolder>/dts/${outputName}.d.ts`,
},
};

// Create the config file within the package
await fs.writeJson(configPath, config);

// Extract all DTS into a single file
const result = Extractor.invoke(ExtractorConfig.loadFileAndPrepare(configPath), {
localBuild: __DEV__,
messageCallback: /* istanbul ignore next */ (warn) => {
// eslint-disable-next-line no-param-reassign
warn.handled = true;

if (
warn.messageId === 'ae-missing-release-tag' ||
warn.messageId === 'console-preamble' ||
warn.logLevel === 'verbose'
) {
return;
}

let level = 'info';

if (warn.logLevel === 'error') {
level = 'error';
} else if (warn.logLevel === 'warning') {
level = 'warn';
}

this.logWithSource(warn.text, level as 'info', {
id: warn.messageId,
output: `${this.package.getSlug()}:${outputName}`,
sourceColumn: warn.sourceFileColumn,
sourceFile: warn.sourceFilePath,
sourceLine: warn.sourceFileLine,
});
},
});

if (!result.succeeded) {
console.error(
`Generated "${outputName}" types completed with ${result.errorCount} errors and ${result.warningCount} warnings!`,
);
}
}

protected getApiExtractorConfigPath(outputName: string): Path {
return this.package.path.append(`api-extractor-${outputName}.json`);
}

// This method only exists so that we can mock in tests.
// istanbul ignore next
protected loadTsconfigJson(): TSConfigStructure | undefined {
return this.package.tsconfigJson;
}

/**
* This method is unfortunate but necessary if TypeScript is using project references.
* When using references, TS uses the `types` (or `typings`) field to determine types
* across packages. But since we set that field to "dts/index.d.ts" for distributing
* only the types necessary, it breaks the `tsc --build` unless the `outDir` is "dts".
*
* But when this happens, we have all the generated `*.d.ts` and `*.js` files in the "dts"
* folder, which we do not want to distribute. So we need to manually delete all of them
* except for the output files we created above.
*
* Not sure of a workaround or better solution :(
*/
protected async removeDeclarationBuild(dtsBuildPath: Path) {
const outputs = new Set<string>(this.builds.map(({ outputName }) => `${outputName}.d.ts`));

// Remove all non-output files
const files = await glob('*', {
cwd: dtsBuildPath.path(),
onlyFiles: true,
});

// Remove all folders
const folders = await glob('*', {
cwd: dtsBuildPath.path(),
onlyDirectories: true,
});

await Promise.all(
[...files, ...folders]
.filter((file) => !outputs.has(file))
.map((file) => fs.remove(dtsBuildPath.append(file).path())),
);
}
}
8 changes: 3 additions & 5 deletions packages/packemon/src/commands/Build.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import os from 'os';
import { Arg, Config } from '@boost/cli';
import { AnalyzeType, BuildOptions, DeclarationType } from '../types';
import { AnalyzeType, BuildOptions } from '../types';
import { BaseCommand } from './Base';

@Config('build', 'Build standardized packages for distribution')
Expand All @@ -22,10 +22,8 @@ export class BuildCommand extends BaseCommand<Required<BuildOptions>> {
@Arg.Number('Number of builds to run in parallel')
concurrency: number = os.cpus().length;

@Arg.String('Generate TypeScript declarations for each package', {
choices: ['none', 'standard', 'api'],
})
declaration: DeclarationType = 'none';
@Arg.Flag('Generate TypeScript declarations for each package')
declaration: boolean = false;

@Arg.String('Path to a custom `tsconfig` for declaration building')
declarationConfig: string = 'tsconfig.json';
Expand Down
3 changes: 1 addition & 2 deletions packages/packemon/src/schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import {
ApiType,
BrowserFormat,
BuildOptions,
DeclarationType,
Format,
NativeFormat,
NodeFormat,
Expand Down Expand Up @@ -76,7 +75,7 @@ export const buildBlueprint: Blueprint<BuildOptions> = {
addFiles: bool(),
analyze: string('none').oneOf<AnalyzeType>(['none', 'sunburst', 'treemap', 'network']),
concurrency: number(1).gte(1),
declaration: string('none').oneOf<DeclarationType>(['none', 'standard', 'api']),
declaration: bool(),
declarationConfig: string(),
filter: string(),
filterFormats: string(),
Expand Down
12 changes: 1 addition & 11 deletions packages/packemon/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,6 @@ export type ApiType = 'private' | 'public';

export type AnalyzeType = 'network' | 'none' | 'sunburst' | 'treemap';

export type DeclarationType = 'api' | 'none' | 'standard';

// PACKAGES

export type InputMap = Record<string, string>;
Expand Down Expand Up @@ -123,7 +121,7 @@ export interface BuildOptions extends FilterOptions {
addFiles?: boolean;
analyze?: AnalyzeType;
concurrency?: number;
declaration?: DeclarationType;
declaration?: boolean;
declarationConfig?: string;
loadConfigs?: boolean;
stamp?: boolean;
Expand Down Expand Up @@ -233,11 +231,3 @@ export interface TSConfigStructure {
strict?: boolean;
};
}

export interface APIExtractorStructure {
projectFolder: string;
mainEntryPointFilePath: string;
dtsRollup: {
untrimmedFilePath: string;
};
}
Loading

0 comments on commit e3270e1

Please sign in to comment.