Skip to content

Commit f0149c8

Browse files
committed
build: add CI check to ensure consistent exports for MDC packages
Adds a new script that checks whether an MDC package exports the same set of symbols as its non-MDC counterpart. Also fixes all of the failures.
1 parent f7d7502 commit f0149c8

File tree

21 files changed

+162
-13
lines changed

21 files changed

+162
-13
lines changed

.circleci/config.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,7 @@ jobs:
348348
- run: yarn stylelint
349349
- run: yarn tslint
350350
- run: yarn -s ts-circular-deps:check
351+
- run: yarn check-mdc-exports
351352

352353
- *slack_notify_on_failure
353354
- *save_cache

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@
4646
"integration-tests": "bazel test --test_tag_filters=-view-engine-only --build_tests_only -- //integration/... -//integration/size-test/...",
4747
"integration-tests:view-engine": "bazel test --test_tag_filters=view-engine-only --build_tests_only -- //integration/... -//integration/size-test/...",
4848
"integration-tests:size-test": "bazel test //integration/size-test/...",
49-
"check-mdc-tests": "ts-node --project scripts/tsconfig.json scripts/check-mdc-tests.ts"
49+
"check-mdc-tests": "ts-node --project scripts/tsconfig.json scripts/check-mdc-tests.ts",
50+
"check-mdc-exports": "ts-node --project scripts/tsconfig.json scripts/check-mdc-exports.ts"
5051
},
5152
"version": "11.1.0-next.0",
5253
"dependencies": {

scripts/check-mdc-exports.ts

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
import {join} from 'path';
2+
import {readdirSync, existsSync} from 'fs';
3+
import * as ts from 'typescript';
4+
import chalk from 'chalk';
5+
6+
const excludedPackages = new Set(['sidenav']);
7+
let hasFailed = false;
8+
9+
readdirSync(join(__dirname, '../src/material'), {withFileTypes: true})
10+
.filter(entity => entity.isDirectory())
11+
.map(entity => entity.name)
12+
.filter(name => !excludedPackages.has(name))
13+
.filter(name => existsSync(join(__dirname, '../src/material-experimental', 'mdc-' + name)))
14+
.forEach(name => {
15+
const missingSymbols = getMissingSymbols(name);
16+
17+
if (missingSymbols.length > 0) {
18+
console.log(chalk.redBright(`\nMissing symbols from mdc-${name}:`));
19+
console.log(missingSymbols.join('\n'));
20+
hasFailed = true;
21+
}
22+
});
23+
24+
if (hasFailed) {
25+
console.log(chalk.redBright(
26+
'\nDetected one or more MDC packages do not export the same set of symbols from\n' +
27+
'public-api.ts as their non-MDC counterpart.\nEither implement the missing symbols or ' +
28+
're-export them from the Material package.'
29+
));
30+
process.exit(1);
31+
} else {
32+
console.log(chalk.green(
33+
'All MDC packages export the same public API symbols as their non-MDC counterparts.'));
34+
process.exit(0);
35+
}
36+
37+
/**
38+
* Gets the names of symbols that are present in a Material package,
39+
* but not its MDC counterpart.
40+
*/
41+
function getMissingSymbols(name: string): string[] {
42+
const mdcExports = getExports(`material-experimental/mdc-${name}`);
43+
const materialExports = getExports(`material/${name}`);
44+
45+
if (!mdcExports.length) {
46+
throw Error(`Could not resolve exports in mdc-${name}`);
47+
}
48+
49+
if (!materialExports.length) {
50+
throw Error(`Could not resolve exports in ${name}`);
51+
}
52+
53+
return materialExports.filter(exportName => !mdcExports.includes(exportName));
54+
}
55+
56+
/**
57+
* Gets the name of the exported symbols from a particular package.
58+
* Based on https://github.com/angular/angular/blob/master/tools/ts-api-guardian/lib/serializer.ts
59+
*/
60+
function getExports(name: string): string[] {
61+
const entryPoint = join(__dirname, '../src', name, 'public-api.ts');
62+
const program = ts.createProgram([entryPoint], {
63+
// This is a bit faster than the default and seems to produce identical results.
64+
moduleResolution: ts.ModuleResolutionKind.Classic
65+
});
66+
const sourceFile = program.getSourceFiles().find(f => f.fileName.endsWith('public-api.ts'))!;
67+
const typeChecker = program.getTypeChecker();
68+
const mainSymbol = typeChecker.getSymbolAtLocation(sourceFile);
69+
70+
return (mainSymbol ? (typeChecker.getExportsOfModule(mainSymbol) || []) : []).map(symbol => {
71+
// tslint:disable-next-line:no-bitwise
72+
if (symbol.flags & ts.SymbolFlags.Alias) {
73+
const resolvedSymbol = typeChecker.getAliasedSymbol(symbol);
74+
return (!resolvedSymbol.valueDeclaration && !resolvedSymbol.declarations) ?
75+
symbol : resolvedSymbol;
76+
} else {
77+
return symbol;
78+
}
79+
}).map(symbol => symbol.name);
80+
}

src/material-experimental/mdc-autocomplete/public-api.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,7 @@ export {
2424
MatAutocompleteActivatedEvent,
2525
MatAutocompleteDefaultOptions,
2626
MatAutocompleteSelectedEvent,
27+
_MatAutocompleteBase,
28+
_MatAutocompleteTriggerBase,
29+
_MatAutocompleteOriginBase
2730
} from '@angular/material/autocomplete';

src/material-experimental/mdc-checkbox/public-api.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9-
import {_MatCheckboxRequiredValidatorModule} from '@angular/material/checkbox';
10-
119
export * from './checkbox';
1210
export * from './module';
1311

@@ -21,4 +19,7 @@ export {
2119
* @breaking-change 9.0.0
2220
*/
2321
TransitionCheckState,
22+
MAT_CHECKBOX_DEFAULT_OPTIONS_FACTORY,
23+
MatCheckboxDefaultOptions,
24+
MAT_CHECKBOX_DEFAULT_OPTIONS,
2425
} from '@angular/material/checkbox';

src/material-experimental/mdc-chips/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ ng_module(
2222
deps = [
2323
"//src:dev_mode_types",
2424
"//src/material-experimental/mdc-core",
25+
"//src/material/chips",
2526
"//src/material/form-field",
2627
"@npm//@angular/animations",
2728
"@npm//@angular/common",

src/material-experimental/mdc-chips/public-api.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,8 @@ export * from './chip-default-options';
1818
export * from './chip-icons';
1919
export * from './chip-text-control';
2020
export * from './chip-edit-input';
21+
22+
export {
23+
MatChipListChange,
24+
MatChipList,
25+
} from '@angular/material/chips';

src/material-experimental/mdc-core/public-api.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,5 +62,7 @@ export {
6262
setLines,
6363
ShowOnDirtyErrorStateMatcher,
6464
ThemePalette,
65-
VERSION
65+
VERSION,
66+
_MatOptionBase,
67+
_MatOptgroupBase,
6668
} from '@angular/material/core';

src/material-experimental/mdc-dialog/public-api.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,8 @@ export {
1919
throwMatDialogContentAlreadyAttachedError,
2020
DialogRole,
2121
DialogPosition,
22+
MAT_DIALOG_SCROLL_STRATEGY_FACTORY,
23+
_MatDialogBase,
24+
_MatDialogContainerBase,
25+
_closeDialogVia,
2226
} from '@angular/material/dialog';

src/material-experimental/mdc-form-field/public-api.ts

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,21 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9-
export {
10-
MAT_FORM_FIELD,
11-
MatFormFieldControl,
12-
getMatFormFieldDuplicatedHintError,
13-
getMatFormFieldMissingControlError,
14-
} from '@angular/material/form-field';
15-
169
export * from './directives/label';
1710
export * from './directives/error';
1811
export * from './directives/hint';
1912
export * from './directives/prefix';
2013
export * from './directives/suffix';
2114
export * from './form-field';
2215
export * from './module';
16+
17+
export {
18+
MAT_FORM_FIELD,
19+
MatFormFieldControl,
20+
getMatFormFieldDuplicatedHintError,
21+
getMatFormFieldMissingControlError,
22+
getMatFormFieldPlaceholderConflictError,
23+
_MAT_HINT,
24+
MatPlaceholder,
25+
matFormFieldAnimations,
26+
} from '@angular/material/form-field';

0 commit comments

Comments
 (0)