1+ /**
2+ * @license
3+ * Copyright Google LLC
4+ *
5+ * Use of this source code is governed by an MIT-style license that can be
6+ * found in the LICENSE file at https://angular.io/license
7+ */
8+
19import fs from 'node:fs/promises' ;
210import path from 'node:path' ;
311import ts from 'typescript' ;
412import { createDiagnostic } from './diagnostic.mjs' ;
513import { StrictDepsManifest } from './manifest.mjs' ;
614import { getImportsInSourceFile } from './visitor.mjs' ;
15+ import { readTsConfig } from './tsconfig.mjs' ;
716
817const [ manifestExecPath , expectedFailureRaw ] = process . argv . slice ( 2 ) ;
918const expectedFailure = expectedFailureRaw === 'true' ;
@@ -13,22 +22,45 @@ const manifest: StrictDepsManifest = JSON.parse(await fs.readFile(manifestExecPa
1322/**
1423 * Regex matcher to extract a npm package name, potentially with scope from a subpackage import path.
1524 */
16- const moduleSpeciferMatcher = / ^ ( @ [ \w \d - _ ] + \/ ) ? ( [ \w \d - _ ] + ) / ;
17- const extensionRemoveRegex = / \. [ m c ] ? ( j s | ( d \. ) ? [ m c ] ? t s ) $ / ;
18- const allowedModuleNames = new Set < string > ( manifest . allowedModuleNames ) ;
25+ const moduleSpeciferMatcher = / ^ ( @ [ \w \d - _ \. ] + \/ ) ? ( [ \w \d - _ \. ] + ) / ;
26+ const extensionRemoveRegex = / \. [ m c ] ? ( j s | ( d \. ) ? [ m c ] ? t s x ? ) $ / ;
27+ const allowedModuleNames = new Set < string > (
28+ manifest . allowedModuleNames . map ( ( m ) => {
29+ return (
30+ m
31+ // Scoped types from DefinitelyTyped are split using a __ delimiter, so we put it back together.
32+ . replace ( / (?: @ t y p e s \/ ) ( .* ) _ _ ( .* ) / , '@$1/$2' )
33+ // Replace any unscoped types package from DefinitelyTyped with just to package name.
34+ . replace ( / (?: @ t y p e s \/ ) ( .* ) / , '$1' )
35+ ) ;
36+ } ) ,
37+ ) ;
1938const allowedSources = new Set < string > (
2039 manifest . allowedSources . map ( ( s ) => s . replace ( extensionRemoveRegex , '' ) ) ,
2140) ;
22-
41+ const tsconfig = readTsConfig ( path . join ( process . cwd ( ) , manifest . tsconfigPath ) ) ;
2342const diagnostics : ts . Diagnostic [ ] = [ ] ;
2443
44+ /** Check if the moduleSpecifier matches any of the provided paths. */
45+ function checkPathsForMatch ( moduleSpecifier : string , paths ?: ts . MapLike < string [ ] > ) : boolean {
46+ for ( const matcher of Object . keys ( paths || { } ) ) {
47+ if ( moduleSpecifier . match ( matcher ) ) {
48+ return true ;
49+ }
50+ }
51+ return false ;
52+ }
53+
2554for ( const fileExecPath of manifest . testFiles ) {
2655 const content = await fs . readFile ( fileExecPath , 'utf8' ) ;
2756 const sf = ts . createSourceFile ( fileExecPath , content , ts . ScriptTarget . ESNext , true ) ;
2857 const imports = getImportsInSourceFile ( sf ) ;
2958
3059 for ( const i of imports ) {
31- const moduleSpecifier = i . moduleSpecifier . replace ( extensionRemoveRegex , '' ) ;
60+ const moduleSpecifier =
61+ i . moduleSpecifier === 'zone.js'
62+ ? 'zone.js'
63+ : i . moduleSpecifier . replace ( extensionRemoveRegex , '' ) ;
3264 // When the module specified is the file itself this is always a valid dep.
3365 if ( i . moduleSpecifier === '' ) {
3466 continue ;
@@ -44,16 +76,24 @@ for (const fileExecPath of manifest.testFiles) {
4476 }
4577 }
4678
47- if ( moduleSpecifier . startsWith ( 'node:' ) && allowedModuleNames . has ( '@types/node' ) ) {
79+ if (
80+ moduleSpecifier . startsWith ( 'node:' ) &&
81+ ( allowedModuleNames . has ( 'node' ) || tsconfig . options . types ?. includes ( 'node' ) )
82+ ) {
4883 continue ;
4984 }
5085
5186 if (
52- allowedModuleNames . has ( moduleSpecifier . match ( moduleSpeciferMatcher ) ?. [ 0 ] || moduleSpecifier )
87+ allowedModuleNames . has ( moduleSpecifier . match ( moduleSpeciferMatcher ) ?. [ 0 ] || '' ) ||
88+ allowedModuleNames . has ( moduleSpecifier )
5389 ) {
5490 continue ;
5591 }
5692
93+ if ( checkPathsForMatch ( moduleSpecifier , tsconfig . options . paths ) ) {
94+ continue ;
95+ }
96+
5797 diagnostics . push (
5898 createDiagnostic ( `No explicit Bazel dependency for this module.` , i . diagnosticNode ) ,
5999 ) ;
0 commit comments