Expand description
§Extension Scanner (ExtensionManagement)
Contains the logic for scanning directories on the filesystem to discover
installed extensions by reading their package.json manifests, and for
collecting default configuration values from all discovered extensions.
§RESPONSIBILITIES
§1. Extension Discovery
- Scan registered extension paths for valid extensions
- Read and parse
package.jsonmanifest files - Validate extension metadata and structure
- Build
ExtensionDescriptionStateDTOfor each discovered extension
§2. Configuration Collection
- Extract default configuration values from extension
contributes.configuration - Merge configuration properties from all extensions
- Handle nested configuration objects recursively
- Detect and prevent circular references
§3. Error Handling
- Gracefully handle unreadable directories
- Skip extensions with invalid package.json
- Log warnings for partial scan failures
- Continue scanning even when some paths fail
§ARCHITECTURAL ROLE
The Extension Scanner is part of the Extension Management subsystem:
Startup ──► ScanPaths ──► Scanner ──► Extensions Map ──► ApplicationState§Position in Mountain
ExtensionManagementmodule: Extension discovery and metadata- Used during application startup to populate extension registry
- Provides data to
Cocoonfor extension host initialization
§Dependencies
CommonLibrary::FileSystem: ReadDirectory and ReadFile effectsCommonLibrary::Error::CommonError: Error handlingApplicationRunTime: Effect executionApplicationState: Extension storage
§Dependents
InitializationData::ConstructExtensionHostInitializationData: Sends extensions to CocoonMountainEnvironment::ScanForExtensions: Public API for extension scanningApplicationState::Internal::ScanExtensionsWithRecovery: Robust scanning wrapper
§SCANNING PROCESS
- Path Resolution: Get scan paths from
ApplicationState.Extension.Registry.ExtensionScanPaths - Directory Enumeration: For each path, read directory entries
- Manifest Detection: Look for
package.jsonin each subdirectory - Parsing: Deserialize
package.jsonintoExtensionDescriptionStateDTO - Augmentation: Add
ExtensionLocation(disk path) to metadata - Storage: Insert into
ApplicationState.Extension.ScannedExtensionsmap
§CONFIGURATION MERGING
CollectDefaultConfigurations() extracts default values from all
extensions’ contributes.configuration.properties and merges them into a
single JSON object:
- Handles nested
.notation (e.g.,editor.fontSize) - Recursively processes nested
propertiesobjects - Detects circular references to prevent infinite loops
- Returns a flat map of configuration keys to default values
§ERROR HANDLING
- Directory Read Failures: Logged as warnings, scanning continues
- Invalid package.json: Skipped with warning, scanning continues
- IO Errors: Logged, operation continues or fails gracefully
§PERFORMANCE
- Scans are performed asynchronously via
ApplicationRunTime - Each directory read is a separate filesystem operation
- Large extension directories may impact startup time
- Consider caching scan results for development workflows
§VS CODE REFERENCE
Borrowed from VS Code’s extension management:
vs/workbench/services/extensions/common/extensionPoints.ts- Configuration contributionvs/platform/extensionManagement/common/extensionManagementService.ts- Extension scanning
§TODO
- Implement concurrent scanning for multiple paths
- Add extension scan caching with invalidation
- Implement extension validation rules (required fields, etc.)
- Add scan progress reporting for UI feedback
- Support extension scanning in subdirectories (recursive)
§MODULE CONTENTS
ScanDirectoryForExtensions: Scan a single directory for extensionsCollectDefaultConfigurations: Merge configuration defaults from all extensionsprocess_configuration_properties: Recursive configuration property processor
Constants§
- EXTENSION_
SCAN_ 🔒DENY_ LIST - Directory names that are never extensions themselves even though they
sit at the top level of
extensions/. VS Code’s shipped tree keeps TypeScript type declarations intypes/, build output inout/, and a flatnode_modules/for shared dependencies. Scanning into those emits noise like[ExtensionScanner] Could not read package.json at .../out/package.jsonon every boot; callers useExtensionScanDenyListto skip them without losing the ability to scan nestednode_modulesinside a real extension (e.g. a language server’s bundled deps). - TEST_
ONLY_ 🔒EXTENSIONS - Test-only extensions that only serve the upstream VS Code test harness.
Excluded unless
Test=1is set, because they pollute the registry with events nobody listens for and drag down boot time on every user session.
Functions§
- Collect
Default Configurations - A helper function to extract default configuration values from all scanned extensions.
- Include
Test 🔒Extensions - IsDenied
Directory 🔒 - IsTest
Only 🔒Extension - IsUser
Extension 🔒Scan Path - Return
trueif the given scan path represents a user-writable extension directory (i.e. whereextensions:installdrops VSIX payloads), not a bundled “built-in” path that ships with the app. - LoadNLS
Bundle 🔒 - Load an extension’s NLS bundle (
package.nls.json) into a{key → string}map. ReturnsNoneif the bundle is absent or unreadable; placeholders stay as-is in that case. Entries can be bare strings or{message, comment}objects - we only keepmessage. - Manifest
ContainsNLS 🔒Placeholders - Walk a manifest value and return true as soon as any
%placeholder%string is encountered. Used to decide whether a missingpackage.nls.jsonbundle is a real problem or a shipped-as-English extension. - ResolveNLS
Placeholders 🔒Inner - Internal NLS walker that also counts substitutions made vs. unresolved placeholders it saw, so the outer scanner can log a one-line summary per extension.
- Scan
Directory ForExtensions - Scans a single directory for valid extensions.
- process_
configuration_ 🔒properties - RECURSIVE CONFIGURATION PROCESSING: Handle nested object structures