Skip to content

Commit

Permalink
Handle missing SCSS npm imports
Browse files Browse the repository at this point in the history
  • Loading branch information
noahtallen committed May 1, 2021
1 parent 9da5f79 commit f6ce5d1
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 17 deletions.
45 changes: 28 additions & 17 deletions packages/dependency-finder/src/lib/find-dependencies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import fs from 'fs';
import { findPackageJsonEntrypoints } from './entrypoints/packagejson.js';
import { findJestEntrypoints } from './entrypoints/jest.js';
import { findAdditionalEntryPoints } from './entrypoints/additional.js';
import { findMissingPackages } from './find-missing.js';

export const findDependencies = async ( {
pkg,
Expand All @@ -25,7 +26,7 @@ export const findDependencies = async ( {
packages: string[];
modules: string[];
} > => {
const missing: string[] = [];
let missing: string[] = [];
const visited: Tree = {};
const packages: Set< string > = new Set();
const modules: Set< string > = new Set();
Expand Down Expand Up @@ -58,33 +59,43 @@ export const findDependencies = async ( {

const absoluteAdditionalEntryPoints = await findAdditionalEntryPoints( additionalEntryPoints );

// Handles monorepo and npm results from parsed files.
const fileFilter = ( path: string ) => {
const isMonorepo = monorepoPackages.some(
( monorepoPackage ) => ! path.startsWith( pkg ) && path.startsWith( monorepoPackage )
);
const isNodeModules = path.includes( 'node_modules' );

if ( isMonorepo || isNodeModules ) {
const { version, name } = ( readPackageUpSync( {
cwd: path,
} ) as NormalizedReadResult ).packageJson;
packages.add( `${ name }@${ version }` );
return false;
}

return true;
};

for ( const entrypoint of [ ...entrypoints, ...jestTests, ...absoluteAdditionalEntryPoints ] ) {
const tree = dependencyTree.toList( {
filename: entrypoint,
directory: path.dirname( entrypoint ),
tsConfig: tsConfig ?? undefined,
visited,
filter: ( path ) => {
const isMonorepo = monorepoPackages.some(
( monorepoPackage ) => ! path.startsWith( pkg ) && path.startsWith( monorepoPackage )
);
const isNodeModules = path.includes( 'node_modules' );

if ( isMonorepo || isNodeModules ) {
const { version, name } = ( readPackageUpSync( {
cwd: path,
} ) as NormalizedReadResult ).packageJson;
packages.add( `${ name }@${ version }` );
return false;
}

return true;
},
filter: fileFilter,
nonExistent: missing,
} );
tree.forEach( ( module ) => modules.add( module ) );
}

// Handle missing files which do exist, but are weird enough for dependencyTree to miss.
const { foundPackages, resolvedFiles } = findMissingPackages( missing );
resolvedFiles.forEach( fileFilter );
missing = missing.filter(
( missingModule ) => ! foundPackages.some( ( foundModule ) => foundModule === missingModule )
);

return {
missing,
packages: Array.from( packages ).sort(),
Expand Down
53 changes: 53 additions & 0 deletions packages/dependency-finder/src/lib/find-missing.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/**
* External dependencies
*/
import { resolve, basename, dirname } from 'path';
import { existsSync } from 'fs';

type FoundPackages = {
foundPackages: Array< string >;
resolvedFiles: Array< string >;
};

/**
* Resolves dependencies which dependency-tree has trouble finding. For example,
* it is unable to parse sass imports such as `~@wordpress/base-styles/mixins`.
* This format is accepted by webpack to resolve style imports from node_modules,
* but dependency-tree does not support it. In this case, we translate that to
* node_modules/@wordpress/base-styles/_mixins.scss, if it exists.
*
* @param missingDependencies An array of dependencies that dependencyTree couldn't find.
* @returns An array of absolute paths to the location of any dependencies that were found.
*/
export function findMissingPackages( missingDependencies: Array< string > ): FoundPackages {
return missingDependencies.reduce< FoundPackages >(
( acc, file ) => {
if ( file.startsWith( '~' ) ) {
// Without the tilde.
const correctFile = file.substring( 1 );
const dirName = dirname( correctFile );
const fileName = basename( correctFile );

// Webpack can resolve a few variations of the file, so check them all.
const fileNameVariations = [
fileName,
fileName + '.scss',
'_' + fileName,
'_' + fileName + '.scss',
];

// Add the first variation which exists to the accumulator.
for ( const possibleFile of fileNameVariations ) {
const packagePath = resolve( 'node_modules', dirName, possibleFile );
if ( existsSync( packagePath ) ) {
acc.resolvedFiles.push( packagePath );
acc.foundPackages.push( file );
break;
}
}
}
return acc;
},
{ foundPackages: [], resolvedFiles: [] }
);
}

0 comments on commit f6ce5d1

Please sign in to comment.