Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

When available, use resolve data already present in most modules #114

Merged
merged 3 commits into from Jan 22, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/FileHandler.ts
Expand Up @@ -4,6 +4,8 @@ interface FileHandler {
getModule(
filename: string | null | undefined
): LicenseIdentifiedModule | null;
isBuildRoot(filename: string): boolean;
isInModuleDirectory(filename: string): boolean;
}

export { FileHandler };
6 changes: 3 additions & 3 deletions src/LicenseIdentifiedModule.ts
Expand Up @@ -2,9 +2,9 @@ import { Module } from './Module';
import { PackageJson } from './PackageJson';

interface LicenseIdentifiedModule extends Module {
packageJson: PackageJson;
licenseId: string | null;
licenseText: string | null;
packageJson?: PackageJson;
licenseId?: string | null;
licenseText?: string | null;
}

export { LicenseIdentifiedModule };
73 changes: 53 additions & 20 deletions src/PluginChunkReadHandler.ts
@@ -1,23 +1,23 @@
import { WebpackChunkHandler } from './WebpackChunkHandler';
import { WebpackChunk } from './WebpackChunk';
import { WebpackChunkModule } from './WebpackChunkModule';
import { WebpackChunkModuleIterator } from './WebpackChunkModuleIterator';
import { WebpackModuleFileIterator } from './WebpackModuleFileIterator';
import { WebpackInnerModuleIterator } from './WebpackInnerModuleIterator';
import { FileHandler } from './FileHandler';
import { LicenseTypeIdentifier } from './LicenseTypeIdentifier';
import { FileSystem } from './FileSystem';
import { PackageJson } from './PackageJson';
import { LicenseTextReader } from './LicenseTextReader';
import { ModuleCache } from './ModuleCache';
import { LicensePolicy } from './LicensePolicy';
import { Module } from './Module';
import { LicenseIdentifiedModule } from './LicenseIdentifiedModule';
import { WebpackCompilation } from './WebpackCompilation';
import { Logger } from './Logger';
import { WebpackStats } from './WebpackStats';

class PluginChunkReadHandler implements WebpackChunkHandler {
private moduleIterator = new WebpackChunkModuleIterator();
private fileIterator = new WebpackModuleFileIterator(require.resolve);
private innerModuleIterator = new WebpackInnerModuleIterator(require.resolve);

constructor(
private logger: Logger,
Expand All @@ -34,15 +34,51 @@ class PluginChunkReadHandler implements WebpackChunkHandler {
moduleCache: ModuleCache,
stats: WebpackStats | undefined
) {
this.moduleIterator.iterateModules(compilation, chunk, stats, module => {
this.fileIterator.iterateFiles(
module,
(filename: string | null | undefined) => {
const module = this.fileHandler.getModule(filename);
this.processModule(compilation, chunk, moduleCache, module);
}
);
});
this.moduleIterator.iterateModules(
compilation,
chunk,
stats,
chunkModule => {
this.innerModuleIterator.iterateModules(
chunkModule,
(module: WebpackChunkModule) => {
const identifiedModule =
this.extractIdentifiedModule(module) ||
this.fileHandler.getModule(module.resource);
if (identifiedModule) {
this.processModule(
compilation,
chunk,
moduleCache,
identifiedModule
);
}
}
);
}
);
}

private extractIdentifiedModule(
module: WebpackChunkModule
): LicenseIdentifiedModule | undefined {
const resolved = module.resourceResolveData;
if (!resolved) return undefined;
const {
descriptionFileRoot: directory,
descriptionFileData: packageJson
} = resolved;
if (
this.fileHandler.isInModuleDirectory(directory) &&
!this.fileHandler.isBuildRoot(directory)
) {
return {
directory,
packageJson,
name: packageJson.name
};
}
return undefined;
}

private getPackageJson(directory: string): PackageJson {
Expand All @@ -54,20 +90,17 @@ class PluginChunkReadHandler implements WebpackChunkHandler {
compilation: WebpackCompilation,
chunk: WebpackChunk,
moduleCache: ModuleCache,
module: Module | LicenseIdentifiedModule | null
module: LicenseIdentifiedModule
) {
if (module && !moduleCache.alreadySeenForChunk(chunk.name, module.name)) {
if (!moduleCache.alreadySeenForChunk(chunk.name, module.name)) {
const alreadyIncludedModule = moduleCache.getModule(module.name);
if (alreadyIncludedModule !== null) {
moduleCache.registerModule(chunk.name, alreadyIncludedModule);
} else {
// module not yet in cache
const packageJson: PackageJson =
(<LicenseIdentifiedModule>module).packageJson ??
this.getPackageJson(module.directory);
const licenseType:
| string
| null = this.licenseTypeIdentifier.findLicenseIdentifier(
const packageJson =
module.packageJson ?? this.getPackageJson(module.directory);
const licenseType = this.licenseTypeIdentifier.findLicenseIdentifier(
compilation,
module.name,
packageJson
Expand Down
42 changes: 22 additions & 20 deletions src/PluginFileHandler.ts
Expand Up @@ -20,28 +20,30 @@ class PluginFileHandler implements FileHandler {
: this.cache[filename];
}

isInModuleDirectory(filename: string) {
if (this.modulesDirectories === null) return true;
if (filename === null || filename === undefined) return false;
let foundInModuleDirectory = false;
const resolvedPath = this.fileSystem.resolvePath(filename);
for (const modulesDirectory of this.modulesDirectories) {
if (
resolvedPath.startsWith(this.fileSystem.resolvePath(modulesDirectory))
) {
foundInModuleDirectory = true;
}
}
return foundInModuleDirectory;
}

isBuildRoot(filename: string) {
return this.buildRoot === filename;
}

private getModuleInternal(
filename: string
): Partial<LicenseIdentifiedModule> | null {
if (filename === null || filename === undefined) {
return null;
}

if (this.modulesDirectories !== null) {
let foundInModuleDirectory = false;
for (const modulesDirectory of this.modulesDirectories) {
if (
this.fileSystem
.resolvePath(filename)
.startsWith(this.fileSystem.resolvePath(modulesDirectory))
) {
foundInModuleDirectory = true;
}
}
if (!foundInModuleDirectory) {
return null;
}
}
if (filename === null || filename === undefined) return null;
if (!this.isInModuleDirectory(filename)) return null;

const module = this.findModuleDir(filename);

Expand Down Expand Up @@ -78,7 +80,7 @@ class PluginFileHandler implements FileHandler {
}
}

if (this.buildRoot === dirOfModule) {
if (this.isBuildRoot(dirOfModule)) {
return null;
}

Expand Down
4 changes: 2 additions & 2 deletions src/WebpackChunkHandler.ts
@@ -1,6 +1,6 @@
import { WebpackChunk } from './WebpackChunk';
import { ModuleCache } from './ModuleCache';
import { Module } from './Module';
import { LicenseIdentifiedModule } from './LicenseIdentifiedModule';
import { WebpackCompilation } from './WebpackCompilation';
import { WebpackStats } from './WebpackStats';

Expand All @@ -15,7 +15,7 @@ interface WebpackChunkHandler {
compilation: WebpackCompilation,
chunk: WebpackChunk,
moduleCache: ModuleCache,
module: Module
module: LicenseIdentifiedModule
): void;
}

Expand Down
8 changes: 7 additions & 1 deletion src/WebpackChunkModule.ts
@@ -1,5 +1,7 @@
import { PackageJson } from './PackageJson';

export interface WebpackChunkModule {
resource: string;
resource?: string;
rootModule?: {
resource?: string;
};
Expand All @@ -8,4 +10,8 @@ export interface WebpackChunkModule {
};
fileDependencies?: string[];
dependencies?: WebpackChunkModule[];
resourceResolveData?: {
descriptionFileRoot: string;
descriptionFileData: PackageJson;
};
}
6 changes: 3 additions & 3 deletions src/WebpackFileSystem.ts
Expand Up @@ -18,8 +18,8 @@ class WebpackFileSystem implements FileSystem {

pathExists(filename: string): boolean {
try {
this.fs.statSync(filename);
return true;
const stat = this.fs.statSync(filename, { throwIfNoEntry: false });
return !!stat;
} catch (e) {
return false;
}
Expand All @@ -44,7 +44,7 @@ class WebpackFileSystem implements FileSystem {
isDirectory(dir: string): boolean {
let isDir = false;
try {
isDir = this.fs.statSync(dir).isDirectory();
isDir = this.fs.statSync(dir, { throwIfNoEntry: false }).isDirectory();
} catch (e) {}
return isDir;
}
Expand Down
@@ -1,35 +1,37 @@
import { WebpackChunkModule } from './WebpackChunkModule';

class WebpackModuleFileIterator {
class WebpackInnerModuleIterator {
constructor(private requireResolve: RequireResolve) {}

iterateFiles(
iterateModules(
chunkModule: WebpackChunkModule,
callback: (filename: string | null | undefined) => void
callback: (module: WebpackChunkModule) => void
) {
const internalCallback = this.internalCallback.bind(this, callback);
internalCallback(
chunkModule.resource ||
(chunkModule.rootModule && chunkModule.rootModule.resource)
chunkModule.resource ? chunkModule : chunkModule.rootModule
);
if (Array.isArray(chunkModule.fileDependencies)) {
const fileDependencies: string[] = chunkModule.fileDependencies;
fileDependencies.forEach(internalCallback);
fileDependencies.forEach(fileDependency =>
internalCallback({ resource: fileDependency })
);
}
if (Array.isArray(chunkModule.dependencies)) {
chunkModule.dependencies.forEach(module =>
internalCallback(module.originModule && module.originModule.resource)
internalCallback(module.originModule)
);
}
}

private internalCallback(
callback: (filename: string | null | undefined) => void,
filename: string | null | undefined
callback: (module: WebpackChunkModule) => void,
module: WebpackChunkModule | undefined
): void {
const actualFileName = this.getActualFilename(filename);
if (!module) return;
const actualFileName = this.getActualFilename(module.resource);
if (actualFileName) {
callback(actualFileName);
callback({ ...module, resource: actualFileName });
}
}

Expand Down Expand Up @@ -69,4 +71,4 @@ class WebpackModuleFileIterator {
}
}

export { WebpackModuleFileIterator };
export { WebpackInnerModuleIterator };
@@ -1,12 +1,12 @@
import { WebpackModuleFileIterator } from '../WebpackModuleFileIterator';
import { WebpackInnerModuleIterator } from '../WebpackInnerModuleIterator';
import {
fakeRequireResolve,
FAKE_REQUIRE_RESOLVE_OUTPUT
} from './FakeRequireResolve';

const iterator = new WebpackModuleFileIterator(fakeRequireResolve);
const iterator = new WebpackInnerModuleIterator(fakeRequireResolve);

describe('WebpackModuleFileIterator', () => {
describe('WebpackInnerModuleIterator', () => {
it('returns null for falsy filename', () => {
expect(iterator.getActualFilename('')).toBeNull();
expect(iterator.getActualFilename(null)).toBeNull();
Expand Down