@@ -3,21 +3,24 @@ import { dirname, resolve } from "node:path";
33import { fileURLToPath } from "node:url" ;
44import { describe , expect , it } from "vitest" ;
55import { classifyBundledExtensionSourcePath } from "../../../../scripts/lib/extension-source-classifier.mjs" ;
6- import {
7- BUNDLED_PLUGIN_PATH_PREFIX ,
8- BUNDLED_PLUGIN_ROOT_DIR ,
9- bundledPluginFile ,
10- } from "../../../../test/helpers/bundled-plugin-paths.js" ;
6+ import { loadPluginManifestRegistry } from "../../../plugins/manifest-registry.js" ;
117import { GUARDED_EXTENSION_PUBLIC_SURFACE_BASENAMES } from "../../../plugins/public-artifacts.js" ;
128
139const ROOT_DIR = resolve ( dirname ( fileURLToPath ( import . meta. url ) ) , "../../.." ) ;
1410const REPO_ROOT = resolve ( ROOT_DIR , ".." ) ;
1511const ALLOWED_EXTENSION_PUBLIC_SURFACES = new Set ( GUARDED_EXTENSION_PUBLIC_SURFACE_BASENAMES ) ;
1612ALLOWED_EXTENSION_PUBLIC_SURFACES . add ( "test-api.js" ) ;
17- const BUNDLED_EXTENSION_IDS = readdirSync ( resolve ( REPO_ROOT , "extensions" ) , { withFileTypes : true } )
18- . filter ( ( entry ) => entry . isDirectory ( ) && entry . name !== "shared" )
19- . map ( ( entry ) => entry . name )
20- . toSorted ( ( left , right ) => right . length - left . length ) ;
13+ const BUNDLED_PLUGIN_ROOT_DIR = "extensions" ;
14+ const bundledPluginRecords = loadPluginManifestRegistry ( {
15+ cache : true ,
16+ config : { } ,
17+ } ) . plugins . filter ( ( plugin ) => plugin . origin === "bundled" ) ;
18+ const bundledPluginRoots = new Map (
19+ bundledPluginRecords . map ( ( plugin ) => [ plugin . id , plugin . rootDir ] as const ) ,
20+ ) ;
21+ const BUNDLED_EXTENSION_IDS = [ ...bundledPluginRoots . keys ( ) ] . toSorted (
22+ ( left , right ) => right . length - left . length ,
23+ ) ;
2124const GUARDED_CHANNEL_EXTENSIONS = new Set ( [
2225 "bluebubbles" ,
2326 "discord" ,
@@ -44,6 +47,14 @@ const GUARDED_CHANNEL_EXTENSIONS = new Set([
4447// Shared config validation intentionally consumes this curated Telegram contract.
4548const ALLOWED_CORE_CHANNEL_SDK_SUBPATHS = new Set ( [ "telegram-command-config" ] ) ;
4649
50+ function bundledPluginFile ( pluginId : string , relativePath : string ) : string {
51+ const rootDir = bundledPluginRoots . get ( pluginId ) ;
52+ if ( ! rootDir ) {
53+ throw new Error ( `missing bundled plugin root for ${ pluginId } ` ) ;
54+ }
55+ return normalizePath ( resolve ( rootDir , relativePath ) ) ;
56+ }
57+
4758type GuardedSource = {
4859 path : string ;
4960 forbiddenPatterns : RegExp [ ] ;
@@ -320,18 +331,18 @@ function readSetupBarrelImportBlock(path: string): string {
320331}
321332
322333function collectExtensionSourceFiles ( ) : string [ ] {
323- const extensionsDir = normalizePath ( resolve ( ROOT_DIR , ".." , "extensions" ) ) ;
324- const sharedExtensionsDir = normalizePath ( resolve ( extensionsDir , "shared" ) ) ;
325- extensionSourceFilesCache = collectSourceFiles ( extensionSourceFilesCache , {
326- rootDir : resolve ( ROOT_DIR , ".." , "extensions" ) ,
327- shouldSkipPath : ( normalizedFullPath ) =>
328- normalizedFullPath . includes ( sharedExtensionsDir ) ||
329- normalizedFullPath . includes ( ` ${ extensionsDir } /shared/` ) ,
330- shouldSkipEntry : ( { entryName , normalizedFullPath } ) =>
331- classifyBundledExtensionSourcePath ( normalizedFullPath ) . isTestLike ||
332- entryName === "api.ts" ||
333- entryName === "runtime-api.ts" ,
334- } ) ;
334+ if ( extensionSourceFilesCache ) {
335+ return extensionSourceFilesCache ;
336+ }
337+ extensionSourceFilesCache = bundledPluginRecords . flatMap ( ( plugin ) =>
338+ collectSourceFiles ( undefined , {
339+ rootDir : plugin . rootDir ,
340+ shouldSkipEntry : ( { entryName , normalizedFullPath } ) =>
341+ classifyBundledExtensionSourcePath ( normalizedFullPath ) . isTestLike ||
342+ entryName === "api.ts" ||
343+ entryName === "runtime- api.ts" ,
344+ } ) ,
345+ ) ;
335346 return extensionSourceFilesCache ;
336347}
337348
@@ -361,8 +372,12 @@ function collectCoreSourceFiles(): string[] {
361372
362373function collectExtensionFiles ( extensionId : string ) : string [ ] {
363374 const cached = extensionFilesCache . get ( extensionId ) ;
375+ const rootDir = bundledPluginRoots . get ( extensionId ) ;
376+ if ( ! rootDir ) {
377+ return [ ] ;
378+ }
364379 const files = collectSourceFiles ( cached , {
365- rootDir : resolve ( ROOT_DIR , ".." , "extensions" , extensionId ) ,
380+ rootDir,
366381 shouldSkipEntry : ( { entryName, normalizedFullPath } ) =>
367382 classifyBundledExtensionSourcePath ( normalizedFullPath ) . isTestLike ||
368383 entryName === "runtime-api.ts" ,
@@ -406,7 +421,7 @@ function getSourceAnalysis(path: string): SourceAnalysis {
406421 text,
407422 importSpecifiers,
408423 extensionImports : importSpecifiers . filter ( ( specifier ) =>
409- specifier . includes ( BUNDLED_PLUGIN_PATH_PREFIX ) ,
424+ specifier . includes ( `/ ${ BUNDLED_PLUGIN_ROOT_DIR } /` ) ,
410425 ) ,
411426 } satisfies SourceAnalysis ;
412427 sourceAnalysisCache . set ( fullPath , analysis ) ;
0 commit comments