Summary
Add an extends property to the BrightScript debug configuration that lets developers define shared base launch configs in external files, which are then inherited and overridden by the local launch.json. Modeled after brighterscript's bsconfig.json extends concept.
Related: #346
Motivation
Developers working across multiple Roku projects or environments (dev/QA/prod) often have large amounts of duplicated launch config. There's currently no way to extract shared values into a base file and inherit from it.
Behavior
Basic usage
In .vscode/launch.json:
{
"type": "brightscript",
"extends": "../shared/roku-launch.json",
"host": "192.168.1.100"
}
The referenced file is loaded first, then all values from the current config are merged overtop (shallow merge — arrays are fully replaced, not concatenated).
Chaining
Chains are supported: c extends b which extends a. The merge order is a → b → c, with c winning.
Optional extends (? prefix)
Prefix the path with ? to silently skip if the file doesn't exist:
"extends": "?../shared/roku-launch.qa.json"
Without the ?, a missing file throws a descriptive error.
Path resolution
The extends path is resolved relative to the directory containing the config file that declares it. For the root launch.json, that is .vscode/. For extended files, it is relative to that file's own location.
Relative paths in base files
${workspaceFolder} and other VSCode variable substitutions in base files are passed through as-is and resolved downstream by VSCode — no special handling needed. Plain relative paths (e.g. rootDir: "./src") in base files will resolve relative to the workspace folder when consumed, same as any other config value.
Workspace settings
extends will also be available as the brightscript.debug.extends workspace setting (synced automatically by the existing sync-launch-settings script). When used there, relative paths should use ${workspaceFolder} as an anchor since there's no launch.json file to resolve against.
Schema / IntelliSense for base files
- A
dist/launch-schema.json is generated at build time from the existing configurationAttributes.launch.properties in package.json (via a new scripts/generate-launch-schema.ts script).
- This file is not committed — it's generated as part of
npm run build and npm run watch.
package.json jsonValidation maps roku-launch*.json → ./dist/launch-schema.json, providing full IntelliSense for base config files following this naming convention (e.g. roku-launch.json, roku-launch.qa.json, roku-launch-ci.json).
Edge cases & validation
- Missing required file: throws with the resolved path in the error message
- Missing optional file (
? prefix): silently skipped, launch proceeds normally
- Circular dependency: detected via ancestor path tracking (case-insensitive on Windows); throws
Circular dependency detected: "a.json" => "b.json" => "a.json"
- JSONC: base files support comments and trailing commas (parsed via
jsonc-parser)
- Array values: child arrays fully replace parent arrays (no concatenation)
Summary
Add an
extendsproperty to the BrightScript debug configuration that lets developers define shared base launch configs in external files, which are then inherited and overridden by the local launch.json. Modeled after brighterscript'sbsconfig.jsonextends concept.Related: #346
Motivation
Developers working across multiple Roku projects or environments (dev/QA/prod) often have large amounts of duplicated launch config. There's currently no way to extract shared values into a base file and inherit from it.
Behavior
Basic usage
In
.vscode/launch.json:{ "type": "brightscript", "extends": "../shared/roku-launch.json", "host": "192.168.1.100" }The referenced file is loaded first, then all values from the current config are merged overtop (shallow merge — arrays are fully replaced, not concatenated).
Chaining
Chains are supported:
cextendsbwhich extendsa. The merge order isa → b → c, withcwinning.Optional extends (
?prefix)Prefix the path with
?to silently skip if the file doesn't exist:Without the
?, a missing file throws a descriptive error.Path resolution
The
extendspath is resolved relative to the directory containing the config file that declares it. For the root launch.json, that is.vscode/. For extended files, it is relative to that file's own location.Relative paths in base files
${workspaceFolder}and other VSCode variable substitutions in base files are passed through as-is and resolved downstream by VSCode — no special handling needed. Plain relative paths (e.g.rootDir: "./src") in base files will resolve relative to the workspace folder when consumed, same as any other config value.Workspace settings
extendswill also be available as thebrightscript.debug.extendsworkspace setting (synced automatically by the existingsync-launch-settingsscript). When used there, relative paths should use${workspaceFolder}as an anchor since there's no launch.json file to resolve against.Schema / IntelliSense for base files
dist/launch-schema.jsonis generated at build time from the existingconfigurationAttributes.launch.propertiesinpackage.json(via a newscripts/generate-launch-schema.tsscript).npm run buildandnpm run watch.package.jsonjsonValidationmapsroku-launch*.json→./dist/launch-schema.json, providing full IntelliSense for base config files following this naming convention (e.g.roku-launch.json,roku-launch.qa.json,roku-launch-ci.json).Edge cases & validation
?prefix): silently skipped, launch proceeds normallyCircular dependency detected: "a.json" => "b.json" => "a.json"jsonc-parser)