Welcome to the second chapter of the Plugins project! In the previous chapter, Built-in Plugin Registry, we created a specific place in memory to store our official features.
Now, we face a new challenge: Identity.
Imagine our CLI has a built-in plugin called calculator.
Later, a community developer creates an amazing calculator plugin and also names it calculator.
If a user installs the community version, we have two plugins with the exact same name.
@official), we need a way to verify the origin of a plugin.
This is Plugin Namespacing. By adding a specific suffix (like @builtin) to the ID, we ensure our internal features never clash with external ones.
We want to distinguish between the official git-helper (shipped with the app) and a community git-helper (downloaded from the internet).
To solve this, we use two simple logical rules:
@ symbol as a separator. Everything after it tells us where the plugin came from.We rarely type these names manually. Instead, the code constructs them automatically when loading plugins.
When we load a built-in plugin from our registry, we don't just use its name. We append the namespace.
// builtinPlugins.ts
export const BUILTIN_MARKETPLACE_NAME = 'builtin'
// Example: "git-helper" becomes "git-helper@builtin"
const pluginId = `${name}@${BUILTIN_MARKETPLACE_NAME}`
Explanation: We define a constant string 'builtin'. By attaching this to the name, we create a globally unique ID.
Later, when the system needs to find code for a plugin, it checks this suffix.
import { isBuiltinPluginId } from './builtinPlugins'
const idToCheck = 'git-helper@builtin'
if (isBuiltinPluginId(idToCheck)) {
console.log('Look in local memory!')
} else {
console.log('Look in the database!')
}
Explanation: If the ID ends in @builtin, we skip the internet/database search entirely and look directly in the registry we built in Chapter 1.
Let's look at how the system uses this logic to route requests.
When the CLI starts, or when a user wants to configure a plugin, the system looks at the ID to decide where to go.
isBuiltinPluginId().BUILTIN_PLUGINS Map.
Let's look at the implementation in builtinPlugins.ts.
This is the most critical logic. It prevents the system from confusing external plugins with internal ones.
// builtinPlugins.ts
export const BUILTIN_MARKETPLACE_NAME = 'builtin'
// Determines if we should look in the Map or the Database
export function isBuiltinPluginId(pluginId: string): boolean {
return pluginId.endsWith(`@${BUILTIN_MARKETPLACE_NAME}`)
}
Explanation: We use the standard string method .endsWith. This is efficient and safe. If we ever change the constant BUILTIN_MARKETPLACE_NAME, the logic automatically updates.
In the previous chapter, we saw getBuiltinPlugins. Now let's focus specifically on how it applies the name.
// inside getBuiltinPlugins()...
for (const [name, definition] of BUILTIN_PLUGINS) {
// 1. Create the Unique ID
const pluginId = `${name}@${BUILTIN_MARKETPLACE_NAME}`
// 2. Use the Unique ID to check settings
const userSetting = settings?.enabledPlugins?.[pluginId]
// ... rest of logic
}
Explanation:
git-helper) from the Map.git-helper@builtin)."git-helper@builtin", not just "git-helper". This allows a user to have "git-helper@builtin": true AND "git-helper@npm": false at the same time!In this chapter, we learned:
@builtin to mark our internal plugins.isBuiltinPluginId acts as a traffic director, telling the system where to look for the plugin's code.Now that we have unique IDs for our plugins, we can safely save user preferences (like "Enabled" or "Disabled") without worrying about mixing up plugins.
Next Chapter: Runtime Plugin State
Generated by Code IQ