Skip to content

Commit d27c22a

Browse files
committed
Scan extension transitive deps for LICENSE files
CG deliberately skips built-in extensions ('represents a built-in VS Code extension. This package will not be registered.'). Our script was only checking direct extension deps from package.json, missing transitives like chevrotain (a dependency of mermaid). New step 5b2 scans ALL packages in extension node_modules/ directories, catching transitive deps that have LICENSE files. This finds ~70 additional packages including the entire chevrotain family, langium, @mermaid-js/parser, and vscode-*-languageservice packages. Dynamic coverage: 75 -> 145 packages. Total: 1084 -> 1168.
1 parent e53c4c7 commit d27c22a

1 file changed

Lines changed: 85 additions & 0 deletions

File tree

build/azure-pipelines/oss/generate-notices.ts

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -646,6 +646,91 @@ function main(): void {
646646
}
647647
}
648648

649+
// 5b2: Scan ALL packages in extension node_modules (catches transitive deps)
650+
console.log('');
651+
console.log(' --- Extension transitive dependencies ---');
652+
console.log(' CG skips built-in extensions entirely. Scanning all packages in');
653+
console.log(' extension node_modules/ directories to catch transitive deps');
654+
console.log(' like chevrotain (transitive of mermaid) that have LICENSE files.');
655+
if (fs.existsSync(extensionsDir)) {
656+
for (const ext of fs.readdirSync(extensionsDir)) {
657+
const extNmDirs = [
658+
path.join(extensionsDir, ext, 'node_modules'),
659+
path.join(extensionsDir, ext, 'server', 'node_modules'),
660+
path.join(extensionsDir, ext, 'server', 'lib', 'node_modules'),
661+
];
662+
663+
for (const nmDir of extNmDirs) {
664+
if (!fs.existsSync(nmDir)) {
665+
continue;
666+
}
667+
668+
try {
669+
for (const entry of fs.readdirSync(nmDir)) {
670+
if (entry.startsWith('.')) {
671+
continue;
672+
}
673+
674+
const full = path.join(nmDir, entry);
675+
if (!fs.statSync(full).isDirectory()) {
676+
continue;
677+
}
678+
679+
// Handle scoped packages (@scope/name)
680+
if (entry.startsWith('@')) {
681+
try {
682+
for (const sub of fs.readdirSync(full)) {
683+
const scopedName = `${entry}/${sub}`;
684+
const key = scopedName.toLowerCase();
685+
if (mergedMap.has(key)) {
686+
continue;
687+
}
688+
689+
const licenseResult = findLicenseInNodeModules(scopedName, repoRoot);
690+
if (licenseResult) {
691+
const pkgInfo = readPackageJson(scopedName, repoRoot);
692+
mergedMap.set(key, {
693+
name: scopedName,
694+
version: pkgInfo?.version || '',
695+
license: pkgInfo?.license || '',
696+
url: pkgInfo?.repository || '',
697+
licenseText: licenseResult.licenseText,
698+
});
699+
dynamicCoverageList.push(`${scopedName} — LICENSE from extension ${ext} (transitive)`);
700+
console.log(` DYNAMIC (transitive): ${scopedName} — extension ${ext}`);
701+
}
702+
}
703+
} catch {
704+
// Can't read scoped dir
705+
}
706+
} else {
707+
const key = entry.toLowerCase();
708+
if (mergedMap.has(key)) {
709+
continue;
710+
}
711+
712+
const licenseResult = findLicenseInNodeModules(entry, repoRoot);
713+
if (licenseResult) {
714+
const pkgInfo = readPackageJson(entry, repoRoot);
715+
mergedMap.set(key, {
716+
name: entry,
717+
version: pkgInfo?.version || '',
718+
license: pkgInfo?.license || '',
719+
url: pkgInfo?.repository || '',
720+
licenseText: licenseResult.licenseText,
721+
});
722+
dynamicCoverageList.push(`${entry} — LICENSE from extension ${ext} (transitive)`);
723+
console.log(` DYNAMIC (transitive): ${entry} — extension ${ext}`);
724+
}
725+
}
726+
}
727+
} catch {
728+
// Can't read extension node_modules
729+
}
730+
}
731+
}
732+
}
733+
649734
// 5c: Check cgmanifest.json entries
650735
console.log('');
651736
console.log(' --- Vendored code (cgmanifest.json) ---');

0 commit comments

Comments
 (0)