Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 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
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
110 changes: 60 additions & 50 deletions src/configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import {Rules} from "./rules";
import {logger} from "./logger";
import * as utils from "./utils";
import {ExtensionData} from "./extensionData";
import {Settings} from "./interfaces/settings";
import {LineComment, SingleLineCommentStyle} from "./interfaces/commentStyles";

export class Configuration {
/**************
Expand Down Expand Up @@ -74,6 +76,7 @@ export class Configuration {
public constructor() {
// Always output extension information to channel on activate.
logger.debug(`Extension details:`, this.extensionData.getAll());
logger.debug(`Extension Discovery Paths:`, this.extensionData.getAllExtensionDiscoveryPaths());

this.findAllLanguageConfigFilePaths();
this.setLanguageConfigDefinitions();
Expand Down Expand Up @@ -178,28 +181,34 @@ export class Configuration {
* If `true`, it returns the comments, if `false` (default), it sets the comments to
* the language directly.
*
* @returns {vscode.CharacterPair | void} Returns the blade comments if `onStart` is `true`, otherwise nothing.
*
*/
public setBladeComments(bladeOverrideComments: boolean, onStart: boolean = false): any {
public setBladeComments(bladeOverrideComments: boolean, onStart: boolean = false): vscode.CharacterPair | void {
// Is enabled AND blade langId is NOT set as disabled...
if (bladeOverrideComments === true && !this.isLangIdDisabled("blade")) {
const bladeComments: vscode.CharacterPair = ["{{--", "--}}"];

if (onStart) {
return ["{{--", "--}}"];
return bladeComments;
} else {
vscode.languages.setLanguageConfiguration("blade", {
comments: {
blockComment: ["{{--", "--}}"],
blockComment: bladeComments,
},
});
}
}
// Is disabled OR blade langId is set as disabled...
else if (!bladeOverrideComments || this.isLangIdDisabled("blade")) {
const htmlComments: vscode.CharacterPair = ["<!--", "-->"];

if (onStart) {
return ["<!--", "-->"];
return htmlComments;
} else {
vscode.languages.setLanguageConfiguration("blade", {
comments: {
blockComment: ["<!--", "-->"],
blockComment: htmlComments,
},
});
}
Expand All @@ -212,38 +221,36 @@ export class Configuration {
* @returns {vscode.WorkspaceConfiguration}
*/
public getConfiguration(): vscode.WorkspaceConfiguration {
return vscode.workspace.getConfiguration(this.extensionData.get("name"), null);
return vscode.workspace.getConfiguration(this.extensionData.get("namespace"), null);
}

/**
* Get value of the specified key from the extension's user configuration settings.
*
* @param {string} key The key of the specific setting.
*
* @returns {T} Returns the value of the `key`.
* @param {K} key The key of the specific setting.
*
* NOTE: Return is typed as `T`, which is a generic type that represents the type that is declared when called (as explained in this StackOverflow answer: https://stackoverflow.com/a/49622066/2358222)
* @returns {Settings[K]} Returns the value of the `key` with proper typing.
*
* @example ```ts
* this.getConfigurationValue<string[]>("disabledLanguages");
* this.getConfigurationValue("disabledLanguages"); // Returns string[] with full type safety
* ```
*/
public getConfigurationValue<T>(key: string): T {
return this.getConfiguration().get<T>(key);
public getConfigurationValue<K extends keyof Settings>(key: K): Settings[K] {
return this.getConfiguration().get<Settings[K]>(key);
}

/**
* Update value of the specified key from the extension's user configuration settings.
*
* @param {string} key The key of the specific setting.

* @param {any} value The value to update the setting with.
* @param {unknown} value The value to update the setting with.
*
* @example ```ts
* this.updateConfigurationValue("bladeOverrideComments", true);
* ```
*/
public updateConfigurationValue(key: string, value: any) {
public updateConfigurationValue(key: string, value: unknown) {
// .update(config key, new value, global)
this.getConfiguration().update(key, value, true);
}
Expand All @@ -254,7 +261,7 @@ export class Configuration {
* @returns {boolean}
*/
public isLangIdDisabled(langId: string): boolean {
return this.getConfigurationValue<string[]>("disabledLanguages").includes(langId);
return this.getConfigurationValue("disabledLanguages").includes(langId);
}

/**
Expand All @@ -264,7 +271,7 @@ export class Configuration {
* @returns {boolean}
*/
private isLangIdMultiLineCommentOverridden(langId: string): boolean {
const overriddenList = this.getConfigurationValue<string[]>("overrideDefaultLanguageMultiLineComments");
const overriddenList = this.getConfigurationValue("overrideDefaultLanguageMultiLineComments");

return overriddenList.hasOwnProperty(langId);
}
Expand All @@ -276,7 +283,7 @@ export class Configuration {
* @returns {string}
*/
private getOverriddenMultiLineComment(langId: string) {
const overriddenList = this.getConfigurationValue<string[]>("overrideDefaultLanguageMultiLineComments");
const overriddenList = this.getConfigurationValue("overrideDefaultLanguageMultiLineComments");

return overriddenList[langId];
}
Expand All @@ -303,8 +310,8 @@ export class Configuration {
// If running in WSL...
if (isWsl) {
// Get the Windows user and built-in extensions paths.
const windowsUserExtensionsPath = this.extensionData.get("WindowsUserExtensionsPathFromWsl");
const windowsBuiltInExtensionsPath = this.extensionData.get("WindowsBuiltInExtensionsPathFromWsl");
const windowsUserExtensionsPath = this.extensionData.getExtensionDiscoveryPath("WindowsUserExtensionsPathFromWsl");
const windowsBuiltInExtensionsPath = this.extensionData.getExtensionDiscoveryPath("WindowsBuiltInExtensionsPathFromWsl");

// Read the paths and create arrays of the extensions.
const windowsBuiltInExtensions = this.readExtensionsFromDirectory(windowsBuiltInExtensionsPath);
Expand All @@ -314,8 +321,8 @@ export class Configuration {
extensions.push(...windowsBuiltInExtensions, ...windowsUserExtensions);
}

const userExtensionsPath = this.extensionData.get("userExtensionsPath");
const builtInExtensionsPath = this.extensionData.get("builtInExtensionsPath");
const userExtensionsPath = this.extensionData.getExtensionDiscoveryPath("userExtensionsPath");
const builtInExtensionsPath = this.extensionData.getExtensionDiscoveryPath("builtInExtensionsPath");

// Read the paths and create arrays of the extensions.
const userExtensions = this.readExtensionsFromDirectory(userExtensionsPath);
Expand Down Expand Up @@ -528,9 +535,9 @@ export class Configuration {
* Set the multi-line comments language definitions.
*/
private setMultiLineCommentLanguageDefinitions() {
let langArray = [];
let langArray: string[] = [];

this.languageConfigs.forEach((config: any, langId: string) => {
this.languageConfigs.forEach((config: vscode.LanguageConfiguration, langId: string) => {
// If the config object has own property of comments AND the comments key has
// own property of blockComment...
if (Object.hasOwn(config, "comments") && Object.hasOwn(config.comments, "blockComment")) {
Expand All @@ -552,7 +559,7 @@ export class Configuration {
// for sanity reasons.
this.multiLineBlocksMap.set("supportedLanguages", langArray.sort());

const multiLineStyleBlocksLangs = this.getConfigurationValue<string[]>("multiLineStyleBlocks");
const multiLineStyleBlocksLangs = this.getConfigurationValue("multiLineStyleBlocks");

// Empty the langArray to reuse it.
langArray = [];
Expand All @@ -574,20 +581,19 @@ export class Configuration {
* Set the single-line comments language definitions.
*/
private setSingleLineCommentLanguageDefinitions() {
let style: string;
const tempMap: Map<string, string> = new Map();
this.languageConfigs.forEach((config: any, langId: string) => {
this.languageConfigs.forEach((config: vscode.LanguageConfiguration, langId: string) => {
// console.log(langId, config.comments.lineComment);
let style: string = "";
let style: SingleLineCommentStyle | null = null;

// If the config object has own property of comments AND the comments key has
// own property of lineComment...
if (Object.hasOwn(config, "comments") && Object.hasOwn(config.comments, "lineComment")) {
let lineComment = config.comments.lineComment;
let lineComment: LineComment = config.comments.lineComment as LineComment;

// Line comments can be a string or an object with a "comment" key.
// If the lineComment is an object, get the "comment" key value.
if (Object.hasOwn(lineComment, "comment")) {
if (typeof lineComment === "object" && lineComment !== null && Object.hasOwn(lineComment, "comment")) {
lineComment = lineComment.comment;
}

Expand All @@ -599,15 +605,15 @@ export class Configuration {
else if (lineComment === "#") {
style = "#";
}
// If the lineComment includes a ";" (; or ;;)...
else if (lineComment.includes(";")) {
// If the lineComment is ";" or ";;"...
else if (lineComment === ";" || lineComment === ";;") {
style = ";";
}

// If style is NOT an empty string, (i.e. not an unsupported single-line
// If style is NOT null, (i.e. not an unsupported single-line
// comment like bat's @rem), AND
// the langId isn't set as disabled...
if (style != "" && !this.isLangIdDisabled(langId)) {
if (style !== null && !this.isLangIdDisabled(langId)) {
// Set the langId and it's style into the Map.
tempMap.set(langId, style);
}
Expand All @@ -622,7 +628,7 @@ export class Configuration {
tempMap.clear();

// Get user-customized langIds for the //-style and add to the map.
let customSlashLangs = this.getConfigurationValue<string[]>("slashStyleBlocks");
let customSlashLangs = this.getConfigurationValue("slashStyleBlocks");
for (let langId of customSlashLangs) {
// If langId is exists (ie. not NULL or empty string) AND
// the langId is longer than 0, AND
Expand All @@ -633,7 +639,7 @@ export class Configuration {
}

// Get user-customized langIds for the #-style and add to the map.
let customHashLangs = this.getConfigurationValue<string[]>("hashStyleBlocks");
let customHashLangs = this.getConfigurationValue("hashStyleBlocks");
for (let langId of customHashLangs) {
// If langId is exists (ie. not NULL or empty string) AND
// the langId is longer than 0, AND
Expand All @@ -644,7 +650,7 @@ export class Configuration {
}

// Get user-customized langIds for the ;-style and add to the map.
let customSemicolonLangs = this.getConfigurationValue<string[]>("semicolonStyleBlocks");
let customSemicolonLangs = this.getConfigurationValue("semicolonStyleBlocks");
for (let langId of customSemicolonLangs) {
// If langId is exists (ie. not NULL or empty string) AND
// the langId is longer than 0, AND
Expand Down Expand Up @@ -697,7 +703,7 @@ export class Configuration {
*/
private setLanguageConfiguration(langId: string, multiLine?: boolean, singleLineStyle?: string): vscode.Disposable {
const internalLangConfig: vscode.LanguageConfiguration = this.getLanguageConfig(langId);
const defaultMultiLineConfig: any = utils.readJsonFile(`${__dirname}/../../config/default-multi-line-config.json`);
const defaultMultiLineConfig: vscode.LanguageConfiguration = utils.readJsonFile(`${__dirname}/../../config/default-multi-line-config.json`);

let langConfig = {...internalLangConfig};

Expand All @@ -721,12 +727,16 @@ export class Configuration {
* Get the user settings/configuration and set the blade or html comments accordingly.
*/
if (langId === "blade") {
langConfig.comments.blockComment = this.setBladeComments(this.getConfigurationValue<boolean>("bladeOverrideComments"), true);
const bladeComments = this.setBladeComments(this.getConfigurationValue("bladeOverrideComments"), true);

// If bladeComments is has a value...
if (bladeComments) {
langConfig.comments.blockComment = bladeComments;
}
}
}

let isOnEnter = this.getConfigurationValue<boolean>("singleLineBlockOnEnter");

let isOnEnter = this.getConfigurationValue("singleLineBlockOnEnter");
// Add the single-line onEnter rules to the langConfig.
//
// If isOnEnter is true AND singleLineStyle isn't false, i.e. is a string,
Expand Down Expand Up @@ -906,7 +916,7 @@ export class Configuration {
}

var indentedNewLine = "\n" + line.text.substring(0, line.text.search(indentRegex));
let isOnEnter = this.getConfigurationValue<boolean>("singleLineBlockOnEnter");
let isOnEnter = this.getConfigurationValue("singleLineBlockOnEnter");
if (!isOnEnter) {
indentedNewLine += style + " ";
}
Expand All @@ -923,12 +933,12 @@ export class Configuration {
*/
private handleChangeBladeMultiLineBlock(textEditor: vscode.TextEditor) {
let langId = textEditor.document.languageId;
const extensionName = this.extensionData.get("name");
const extensionName = this.extensionData.get("namespace");

// Only carry out function if languageId is blade.
if (langId === "blade" && !this.isLangIdDisabled(langId)) {
// Read current value
let isOverridden = this.getConfigurationValue<boolean>("bladeOverrideComments");
let isOverridden = this.getConfigurationValue("bladeOverrideComments");

if (isOverridden === false) {
// Update to true
Expand All @@ -938,7 +948,7 @@ export class Configuration {
this.updateConfigurationValue("bladeOverrideComments", false);
}
// Read new value
let bladeOverrideComments = this.getConfigurationValue<boolean>("bladeOverrideComments");
let bladeOverrideComments = this.getConfigurationValue("bladeOverrideComments");

// Set the comments for blade language.
this.setBladeComments(bladeOverrideComments);
Expand All @@ -962,25 +972,25 @@ export class Configuration {
private logDebugInfo() {
// The path to the built-in extensions. The env variable changes when on WSL.
// So we can use it for both Windows and WSL.
const builtInExtensionsPath = this.extensionData.get("builtInExtensionsPath");
const builtInExtensionsPath = this.extensionData.getExtensionDiscoveryPath("builtInExtensionsPath");

let extensionsPaths = {};

if (isWsl) {
// Get the Windows user and built-in extensions paths.
const windowsUserExtensionsPath = this.extensionData.get("WindowsUserExtensionsPathFromWsl");
const windowsBuiltInExtensionsPath = this.extensionData.get("WindowsBuiltInExtensionsPathFromWsl");
const windowsUserExtensionsPath = this.extensionData.getExtensionDiscoveryPath("WindowsUserExtensionsPathFromWsl");
const windowsBuiltInExtensionsPath = this.extensionData.getExtensionDiscoveryPath("WindowsBuiltInExtensionsPathFromWsl");

extensionsPaths = {
"Windows-installed Built-in Extensions Path": windowsBuiltInExtensionsPath,
"Windows-installed User Extensions Path": windowsUserExtensionsPath,
"WSL-installed Built-in Extensions Path": builtInExtensionsPath,
"WSL-installed User Extensions Path": this.extensionData.get("userExtensionsPath"),
"WSL-installed User Extensions Path": this.extensionData.getExtensionDiscoveryPath("userExtensionsPath"),
};
} else {
extensionsPaths = {
"Built-in Extensions Path": builtInExtensionsPath,
"User Extensions Path": this.extensionData.get("userExtensionsPath"),
"User Extensions Path": this.extensionData.getExtensionDiscoveryPath("userExtensionsPath"),
};
}

Expand Down
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
Loading