Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
dd01418
feat: add `Settings` interface to allow intellisense & full type safety.
yCodeTech Jan 11, 2026
d3e9bac
fix: `overrideDefaultLanguageMultiLineComments` setting type.
yCodeTech Jan 11, 2026
dce0661
fix: remove `SupportUnsupportedLanguages` interface import.
yCodeTech Jan 11, 2026
00db701
fix: removed the generic typing in extension.ts
yCodeTech Jan 11, 2026
16e481d
ci: change job name from `deploy` to `check-ts`
yCodeTech Jan 11, 2026
b5d1bcb
refactor: merge `createExtensionData` into `setExtensionData` method
yCodeTech Jan 17, 2026
83c51ed
feat: add new `ExtensionMetaData` interface for better typings
yCodeTech Jan 17, 2026
81f797b
refactor: `setBladeComments` method and fix typings.
yCodeTech Jan 21, 2026
8af89da
fix: parameter type `any` to `unknown` in `updateConfigurationValue`
yCodeTech Jan 21, 2026
21bfecb
fix: language config types to vscode's `LanguageConfiguration`
yCodeTech Jan 21, 2026
2821c58
refactor: the `lineComment` style check to use strict equality checks
yCodeTech Jan 21, 2026
f2504bc
fix: types for line comments in `setSingleLineCommentLanguageDefiniti…
yCodeTech Jan 21, 2026
5965287
fix: ts type error while trying to set blade comments.
yCodeTech Jan 21, 2026
0b776fc
remove: the unused duplicate `style` variable.
yCodeTech Jan 21, 2026
1365c46
fix: the missing imports for `LineComment` & `SingleLineCommentStyle`
yCodeTech Jan 21, 2026
824ce9b
fix: `data` param in logger's `debug` method to be optional
yCodeTech Jan 23, 2026
6534893
feat: add a dedicated `namespace` property for the `extensionData`.
yCodeTech Jan 23, 2026
07def7e
docs: add docblocks to the `ExtensionMetaData` interface.
yCodeTech Jan 23, 2026
be9d972
refactor: paths to installed extensions into a separate method
yCodeTech Jan 24, 2026
2b0ce9a
refactor: move creation of the extension ID into `setExtensionData`.
yCodeTech Jan 25, 2026
6f77cc5
refactor: move `settingsNamespace` creation into `setExtensionData`.
yCodeTech Jan 25, 2026
c2711eb
fix: JSON file reading with optional `null` return for missing files.
yCodeTech Jan 26, 2026
ea401c8
feat: add `extensionPath` property to the `ExtensionData` class.
yCodeTech Jan 26, 2026
b693795
fix: add `null` check for `packageJsonData` before setting extensionData
yCodeTech Jan 26, 2026
279d3b4
refactor: allow the `extensionData` Map for any extension's data.
yCodeTech Jan 26, 2026
9ff0857
fix: remove the testing only code mistakenly added in commit be9d972
yCodeTech Jan 26, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/check-ts.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ on:

name: Compile TypeScript to check for errors
jobs:
deploy:
check-ts:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
Expand Down
140 changes: 73 additions & 67 deletions src/configuration.ts

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@ export function activate(context: vscode.ExtensionContext) {

disposables.push(...configureCommentBlocksDisposable, ...registerCommandsDisposable);

const extensionName = extensionData.get("name");
const extensionName = extensionData.get("namespace");

const extensionDisplayName = extensionData.get("displayName");

let disabledLangConfig: string[] = configuration.getConfigurationValue<string[]>("disabledLanguages");
let disabledLangConfig: string[] = configuration.getConfigurationValue("disabledLanguages");

if (disabledLangConfig.length > 0) {
vscode.window.showInformationMessage(`${disabledLangConfig.join(", ")} languages are disabled for ${extensionDisplayName}.`);
Expand All @@ -41,7 +41,7 @@ export function activate(context: vscode.ExtensionContext) {
// If the affected setting is bladeOverrideComments...
if (event.affectsConfiguration(`${extensionName}.bladeOverrideComments`)) {
// Get the setting.
let bladeOverrideComments: boolean = configuration.getConfigurationValue<boolean>("bladeOverrideComments");
let bladeOverrideComments: boolean = configuration.getConfigurationValue("bladeOverrideComments");

configuration.setBladeComments(bladeOverrideComments);

Expand Down
157 changes: 97 additions & 60 deletions src/extensionData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,29 @@ import isWsl from "is-wsl";
import {IPackageJson} from "package-json-type";

import {readJsonFile} from "./utils";
import {ExtensionMetaData, ExtensionPaths, ExtensionMetaDataValue} from "./interfaces/extensionMetaData";

export class ExtensionData {
/**
* This extension details in the form of a key:value Map object.
* Extension data in the form of a key:value Map object.
*
* @type {Map<string, string>}
* @type {Map<keyof ExtensionMetaData, ExtensionMetaDataValue>}
*/
private extensionData = new Map<string, string>();
private extensionData = new Map<keyof ExtensionMetaData, ExtensionMetaDataValue>();

/**
* Extension discovery paths in the form of a key:value Map object.
*
* @type {Map<keyof ExtensionPaths, string>}
*/
private extensionDiscoveryPaths = new Map<keyof ExtensionPaths, string>();

/**
* The absolute path of the requested extension.
*
* @type {string}
*/
private readonly extensionPath: string;

/**
* The package.json data for this extension.
Expand All @@ -20,93 +35,115 @@ export class ExtensionData {
*/
private packageJsonData: IPackageJson;

public constructor() {
public constructor(extensionPath: string | null = null) {
// Set the path if provided, otherwise default to this extension's path.
this.extensionPath = extensionPath ?? path.join(__dirname, "../../");

this.packageJsonData = this.getExtensionPackageJsonData();
this.setExtensionData();

// Only proceed with extension data setup if packageJsonData is NOT null.
if (this.packageJsonData !== null) {
this.setExtensionData();
}

this.setExtensionDiscoveryPaths();
}

/**
* Get the names, id, and version of this extension from package.json.
*
* @returns {IPackageJson} The package.json data for this extension, with extra custom keys.
* @returns {IPackageJson | null} The package.json data for this extension, with extra custom keys.
*/
private getExtensionPackageJsonData(): IPackageJson | null {
// Get the package.json file path.
const packageJSONPath = path.join(this.extensionPath, "package.json");
return readJsonFile(packageJSONPath, false);
}

/**
* Set the extension data into the extensionData Map.
*/
private getExtensionPackageJsonData(): IPackageJson {
const extensionPath = path.join(__dirname, "../../");
private setExtensionData() {
// Create the extension ID (publisher.name).
const id = `${this.packageJsonData.publisher}.${this.packageJsonData.name}`;

// Set each key-value pair directly into the Map
this.extensionData.set("id", id);
this.extensionData.set("name", this.packageJsonData.name);

// Only set the namespace if it dealing with this extension.
if (this.packageJsonData.name === "automatic-comment-blocks") {
// The configuration settings namespace is a shortened version of the extension name.
// We just need to replace "automatic" with "auto" in the name.
const settingsNamespace: string = this.packageJsonData.name.replace("automatic", "auto");

this.extensionData.set("namespace", settingsNamespace);
}

const packageJSON: IPackageJson = readJsonFile(path.join(extensionPath, "package.json"));
this.extensionData.set("displayName", this.packageJsonData.displayName);
this.extensionData.set("version", this.packageJsonData.version);
this.extensionData.set("extensionPath", this.extensionPath);
this.extensionData.set("packageJSON", this.packageJsonData);
}

// Set the id (publisher.name) into the packageJSON object as a new `id` key.
packageJSON.id = `${packageJSON.publisher}.${packageJSON.name}`;
packageJSON.extensionPath = extensionPath;
private setExtensionDiscoveryPaths() {
// The path to the user extensions.
const userExtensionsPath = isWsl ? path.join(vscode.env.appRoot, "../../", "extensions") : path.join(this.extensionPath, "../");

// The configuration settings namespace is a shortened version of the extension name.
// We just need to replace "automatic" with "auto" in the name.
const settingsNamespace: string = packageJSON.name.replace("automatic", "auto");
// Set the namespace to the packageJSON `configuration` object as a new `namespace` key.
packageJSON.contributes.configuration.namespace = settingsNamespace;
this.extensionDiscoveryPaths.set("userExtensionsPath", userExtensionsPath);
// The path to the built-in extensions.
// This env variable changes when on WSL to it's WSL-built-in extensions path.
this.extensionDiscoveryPaths.set("builtInExtensionsPath", path.join(vscode.env.appRoot, "extensions"));

return packageJSON;
// Only set these if running in WSL
if (isWsl) {
this.extensionDiscoveryPaths.set("WindowsUserExtensionsPathFromWsl", path.dirname(process.env.VSCODE_WSL_EXT_LOCATION!));
this.extensionDiscoveryPaths.set("WindowsBuiltInExtensionsPathFromWsl", path.join(process.env.VSCODE_CWD!, "resources/app/extensions"));
}
}

/**
* Set the extension data into the extensionData Map.
* Get the extension's data by a specified key.
*
* @param {K} key The key of the extension detail to get.
*
* @returns {ExtensionMetaData[K] | undefined} The value of the extension detail, or undefined if the key does not exist.
*/
private setExtensionData() {
// Set all entries in the extensionData Map.
Object.entries(this.createExtensionData()).forEach(([key, value]) => {
this.extensionData.set(key, value);
});
public get<K extends keyof ExtensionMetaData>(key: K): ExtensionMetaData[K] | undefined {
return this.extensionData.get(key) as ExtensionMetaData[K] | undefined;
}

/**
* Create the extension data object for the extensionData Map.
* It also helps for type inference intellisense in the get method.
* Get all extension data as a plain object.
*
* @returns The extension data object with keys and values.
* @returns {ExtensionMetaData} A plain object containing all extension details.
*/
private createExtensionData() {
// The path to the user extensions.
const userExtensionsPath = isWsl
? path.join(vscode.env.appRoot, "../../", "extensions")
: path.join(this.packageJsonData.extensionPath, "../");

// Set the keys and values for the Map.
// The keys will also be used for type inference in VSCode intellisense.
return {
id: this.packageJsonData.id,
name: this.packageJsonData.contributes.configuration.namespace,
displayName: this.packageJsonData.displayName,
version: this.packageJsonData.version,
userExtensionsPath: userExtensionsPath,
// The path to the built-in extensions.
// This env variable changes when on WSL to it's WSL-built-in extensions path.
builtInExtensionsPath: path.join(vscode.env.appRoot, "extensions"),

// Only set these if running in WSL.
...(isWsl && {
WindowsUserExtensionsPathFromWsl: path.dirname(process.env.VSCODE_WSL_EXT_LOCATION!),
WindowsBuiltInExtensionsPathFromWsl: path.join(process.env.VSCODE_CWD!, "resources/app/extensions"),
}),
} as const;
public getAll(): ExtensionMetaData | null {
// If no data, return null
if (this.extensionData.size === 0) {
return null;
}

return Object.fromEntries(this.extensionData) as unknown as ExtensionMetaData;
}

/**
* Get the extension's data by a specified key.
* Get the extension discovery paths by a specified key.
*
* @param {K} key The key of the extension detail to get.
* @param {K} key The key of the specific path to get.
*
* @returns {ReturnType<typeof this.createExtensionData>[K] | undefined} The value of the extension detail, or undefined if the key does not exist.
* @returns {ExtensionPaths[K] | undefined} The value of the extension detail, or undefined if the key does not exist.
*/
public get<K extends keyof ReturnType<typeof this.createExtensionData>>(key: K): ReturnType<typeof this.createExtensionData>[K] | undefined {
return this.extensionData.get(key) as ReturnType<typeof this.createExtensionData>[K] | undefined;
public getExtensionDiscoveryPath<K extends keyof ExtensionPaths>(key: K): ExtensionPaths[K] | undefined {
return this.extensionDiscoveryPaths.get(key) as ExtensionPaths[K] | undefined;
}

/**
* Get all extension data.
* Get all extension discovery paths.
*
* @returns {ReadonlyMap<string, string>} A read-only Map containing all extension details.
* @returns {ReadonlyMap<keyof ExtensionPaths, string>} A read-only Map containing all extension discovery paths.
*/
public getAll(): ReadonlyMap<string, string> {
return this.extensionData;
public getAllExtensionDiscoveryPaths(): ReadonlyMap<keyof ExtensionPaths, string> {
return this.extensionDiscoveryPaths;
}
}
33 changes: 33 additions & 0 deletions src/interfaces/commentStyles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
export type SingleLineCommentStyle = "//" | "#" | ";";

/**
* Line Comments
*
* Taken directly from VScode's commit in June 2025 that changed the line comment config.
* https://github.com/microsoft/vscode/commit/d9145a291dcef0bad3ace81a3d55727ca294c122#diff-0dfa7db579eface8250affb76bc88717725a121401d4d8598bc36b92b0b6ef62
*
* The @types/vscode package does not yet have these changes.
* So until they're added, we define them manually.
*/

/**
* The line comment token, like `// this is a comment`.
* Can be a string, an object with comment and optional noIndent properties, or null.
*/
export type LineComment = string | LineCommentConfig | null;

/**
* Configuration for line comments.
*/
export interface LineCommentConfig {
/**
* The line comment token, like `//`
*/
comment: string;

/**
* Whether the comment token should not be indented and placed at the first column.
* Defaults to false.
*/
noIndent?: boolean;
}
77 changes: 77 additions & 0 deletions src/interfaces/extensionMetaData.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import {IPackageJson} from "package-json-type";

// Utility types for cleaner Map typing
export type ExtensionMetaDataValue = ExtensionMetaData[keyof ExtensionMetaData];

/**
* Extension metadata for a VSCode extension
*/
export interface ExtensionMetaData {
/**
* The unique ID in the form of `publisher.name`.
*/
id: string;

/**
* The name.
* Directly from package.json "name" key.
*/
name: string;

/**
* The namespace for this extension's configuration settings,
* which is a slightly shorter version of the name.
*/
namespace?: string;

/**
* The display name.
* Directly from package.json "displayName" key.
*/
displayName: string;

/**
* The version.
* Directly from package.json "version" key.
*/
version: string;

/**
* The absolute path to the extension.
*/
extensionPath: string;

/**
* The full package.json data
*/
packageJSON: IPackageJson;
}

/**
* Extension discovery paths configuration for this extension
*/
export interface ExtensionPaths {
/**
* The path to the user extensions.
*/
userExtensionsPath: string;

/**
* The path to the built-in extensions.
*/
builtInExtensionsPath: string;

/**
* The Windows path to the user extensions when running in WSL.
*
* Only set when running in WSL.
*/
WindowsUserExtensionsPathFromWsl?: string;

/**
* The Windows path to the built-in extensions when running in WSL.
*
* Only set when running in WSL.
*/
WindowsBuiltInExtensionsPathFromWsl?: string;
}
10 changes: 10 additions & 0 deletions src/interfaces/settings.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export interface Settings {
singleLineBlockOnEnter: boolean;
disabledLanguages: string[];
slashStyleBlocks: string[];
hashStyleBlocks: string[];
semicolonStyleBlocks: string[];
multiLineStyleBlocks: string[];
overrideDefaultLanguageMultiLineComments: Record<string, string>;
bladeOverrideComments: boolean;
}
4 changes: 2 additions & 2 deletions src/logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,9 @@ class Logger {
* This is helpful for logging objects and arrays.
*
* @param {string} message The message to be logged.
* @param {unknown} data Extra data that is useful for debugging, like an object or array.
* @param {unknown} data [Optional] Extra data that is useful for debugging, like an object or array.
*/
public debug(message: string, data: unknown): void {
public debug(message: string, data?: unknown): void {
if (this.debugMode) {
this.logMessage("DEBUG", message, data);
}
Expand Down
Loading