From 473719fc5d5ffd3d02ebc378ddf974ebffbf6e63 Mon Sep 17 00:00:00 2001 From: yCodeTech Date: Tue, 25 Aug 2026 08:44:24 +0100 Subject: [PATCH 01/10] style: auto formatting --- tsconfig.json | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/tsconfig.json b/tsconfig.json index 27594a4..786deeb 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -3,13 +3,20 @@ "module": "commonjs", "target": "es2022", "outDir": "out", - "lib": ["es2022"], + "lib": [ + "es2022" + ], "sourceMap": true, "rootDir": ".", - "typeRoots": ["./node_modules/@types"] + "typeRoots": [ + "./node_modules/@types" + ] }, "typeAcquisition": { - "enable": true, + "enable": true }, - "exclude": ["node_modules", ".vscode-test"] + "exclude": [ + "node_modules", + ".vscode-test" + ] } From 067b8d4c85555fddc794550d39bfdd4a44e666b6 Mon Sep 17 00:00:00 2001 From: yCodeTech Date: Tue, 25 Aug 2026 08:47:55 +0100 Subject: [PATCH 02/10] build: version bump typescript v7. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 604c9b6..1dd83ec 100644 --- a/package.json +++ b/package.json @@ -137,7 +137,7 @@ "@types/vscode": "^1.130", "prettier": "^3.9.6", "prettier-plugin-multiline-arrays": "^4.1.11", - "typescript": "^5.7" + "typescript": "^7.0.0" }, "dependencies": { "is-wsl": "^3.1.0", From 9ba5ff4ba90f32f0e889ed152024e1304a189eb5 Mon Sep 17 00:00:00 2001 From: yCodeTech Date: Tue, 25 Aug 2026 09:08:54 +0100 Subject: [PATCH 03/10] build: add `types` to tsconfig to explicitly include type modules. From Node v6, you have to explicitly include type modules, otherwise they will not be added globally to the project like `process` for Node, and module imports will error like `Cannot find name 'node:fs'`. - Added `types` array to tsconfig and included the `node` and `vscode` modules to fix import and usage errors. Ref: http://typescriptlang.org/tsconfig/#types --- tsconfig.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tsconfig.json b/tsconfig.json index 786deeb..cf48f0b 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -10,6 +10,10 @@ "rootDir": ".", "typeRoots": [ "./node_modules/@types" + ], + "types": [ + "node", + "vscode" ] }, "typeAcquisition": { From 08b99a93d732d16adf2221903d1a35759090e733 Mon Sep 17 00:00:00 2001 From: yCodeTech Date: Fri, 4 Sep 2026 16:34:47 +0100 Subject: [PATCH 04/10] build: change TypeScript compiler to use `es2025` spec and types. --- tsconfig.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tsconfig.json b/tsconfig.json index cf48f0b..b37a283 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,10 +1,10 @@ { "compilerOptions": { "module": "commonjs", - "target": "es2022", + "target": "es2025", "outDir": "out", "lib": [ - "es2022" + "es2025" ], "sourceMap": true, "rootDir": ".", From b23c850dc5c93130314665dae8d40b08a9586999 Mon Sep 17 00:00:00 2001 From: yCodeTech Date: Sat, 5 Sep 2026 05:51:45 +0100 Subject: [PATCH 05/10] fix: ts 7.0 type errors. Fixed TS 7.0 errors by ensuring: - Variables don't have `undefined` or `null` values before accessing them and providing fallback values if they are undefined with the null coalescing operator (??) and conditional ternary operator (? .. : .. ). - Values from methods are satisfying their expected return types using the `as` keyword and generic typed method calls. - Object keys aren't accessed if the object itself is `undefined` with the optional chaining operator (?.) and proper undefined type guards and conditionals. - `reconstructRegex` util function infers the correct type from the passed `obj` param. - Error stack logging has a fallback of the error message in case the stack is null/undefined. - `convertMapToReversedObject` util function has properly typed `result` instead of implicit `any` type and changed the reverse object mapping to mutate the existing array instead of rebuilding a new one on every iteration. --- src/configuration.ts | 60 ++++++++++++++++++++++++-------------------- src/utils.ts | 42 ++++++++++++++++--------------- 2 files changed, 55 insertions(+), 47 deletions(-) diff --git a/src/configuration.ts b/src/configuration.ts index 8c52848..be257ec 100644 --- a/src/configuration.ts +++ b/src/configuration.ts @@ -95,7 +95,7 @@ export class Configuration { // Read the default multi-line config from the JSON file and cache it for later use. this.defaultMultiLineConfig = utils.readJsonFile(`${configPath}/default-multi-line-config.json`) as vscode.LanguageConfiguration; // Read the languages to skip from the JSON file and cache it for later use. - this.languagesToSkip = utils.readJsonFile(`${configPath}/skip-languages.jsonc`); + this.languagesToSkip = utils.readJsonFile(`${configPath}/skip-languages.jsonc`) ?? {}; this.findAllLanguageConfigFilePaths(); this.setLanguageConfigDefinitions(); @@ -255,7 +255,7 @@ export class Configuration { * ``` */ public getConfigurationValue(key: K): Settings[K] { - return this.getConfiguration().get(key); + return this.getConfiguration().get(key) as Settings[K]; } /** @@ -343,8 +343,8 @@ export class Configuration { const builtInExtensionsPath = this.extensionData.getExtensionDiscoveryPath("builtInExtensionsPath"); // Read the paths and create arrays of the extensions. - const userExtensions = this.readExtensionsFromDirectory(userExtensionsPath); - const builtInExtensions = this.readExtensionsFromDirectory(builtInExtensionsPath); + const userExtensions = userExtensionsPath ? this.readExtensionsFromDirectory(userExtensionsPath) : []; + const builtInExtensions = builtInExtensionsPath ? this.readExtensionsFromDirectory(builtInExtensionsPath) : []; // Add all installed extensions (including built-in ones) into the extensions array. // If running WSL, these will be the WSL-installed extensions. @@ -372,7 +372,7 @@ export class Configuration { // If the langId already exists... if (this.languageConfigFilePaths.has(langId)) { // Push the new config path into the array of the existing langId. - this.languageConfigFilePaths.get(langId).push(configPath); + this.languageConfigFilePaths.get(langId)?.push(configPath); } // Otherwise, if the langId doesn't exist... else { @@ -412,7 +412,7 @@ export class Configuration { // Define a new array as the new AutoClosingPair. const autoClosingPairsArray: vscode.AutoClosingPair[] = []; // Loop through the config's autoClosingPairs... - config.autoClosingPairs.forEach((item) => { + (config.autoClosingPairs ?? []).forEach((item) => { // If the item is an array... if (Array.isArray(item)) { // Create a new object with the 1st array element [0] as the @@ -439,7 +439,7 @@ export class Configuration { const existingConfig = this.languageConfigs.get(langId); // Only merge if both configs have comments - if (existingConfig.comments && config.comments) { + if (existingConfig?.comments && config.comments) { // Start with existing comments as base const mergedComments = {...existingConfig.comments}; @@ -449,7 +449,9 @@ export class Configuration { if (Array.isArray(value) && value.length === 0) { return; } - mergedComments[key] = value; + if (key === "lineComment" || key === "blockComment") { + mergedComments[key] = value; + } }); // Update the config with merged comments @@ -555,7 +557,7 @@ export class Configuration { this.languageConfigs.forEach((config: vscode.LanguageConfiguration, langId: LanguageId) => { // 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")) { + if (config.comments && Object.hasOwn(config.comments, "blockComment") && config.comments.blockComment) { // If the blockComment array includes the multi-line start of "/*"... if (config.comments.blockComment.includes("/*")) { // console.log(langId, config.comments); @@ -627,7 +629,7 @@ export class Configuration { // 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")) { + if (config.comments && Object.hasOwn(config.comments, "lineComment")) { let lineComment = config.comments.lineComment; // Line comments can be a string or an object with a "comment" key. @@ -752,21 +754,19 @@ export class Configuration { // Deep-clone the internalLangConfig so modifications never write back // into the cached `languageConfigs` Map by accident. - let langConfig: vscode.LanguageConfiguration = internalLangConfig - ? structuredClone(internalLangConfig) - : {}; + let langConfig: vscode.LanguageConfiguration = internalLangConfig ? structuredClone(internalLangConfig) : {}; if (multiLine) { langConfig.autoClosingPairs = utils.mergeArraysBy( - this.defaultMultiLineConfig.autoClosingPairs, - internalLangConfig?.autoClosingPairs, + this.defaultMultiLineConfig.autoClosingPairs ?? [], + internalLangConfig?.autoClosingPairs ?? [], "open" ); // Add the multi-line onEnter rules to the langConfig. langConfig.onEnterRules = utils.mergeArraysBy( Rules.multilineEnterRules, - internalLangConfig?.onEnterRules, + internalLangConfig?.onEnterRules ?? [], "beforeText" ); @@ -780,7 +780,7 @@ export class Configuration { if (this.isLangIdMultiLineCommentOverridden(langId) && langConfig.comments?.blockComment) { langConfig.comments.blockComment = [ this.getOverriddenMultiLineComment(langId), - langConfig.comments.blockComment[1] + langConfig.comments.blockComment[1], ]; } @@ -792,6 +792,7 @@ export class Configuration { // If bladeComments has a value... if (bladeComments) { + langConfig.comments ??= {}; langConfig.comments.blockComment = bladeComments; } } @@ -805,22 +806,26 @@ export class Configuration { if (isOnEnter && singleLineStyle) { // //-style comments if (singleLineStyle === "//") { - langConfig.onEnterRules = utils.mergeArraysBy(Rules.slashEnterRules, langConfig?.onEnterRules, "beforeText"); + langConfig.onEnterRules = utils.mergeArraysBy(Rules.slashEnterRules, langConfig.onEnterRules ?? [], "beforeText"); } // #-style comments else if (singleLineStyle === "#") { - langConfig.onEnterRules = utils.mergeArraysBy(Rules.hashEnterRules, langConfig?.onEnterRules, "beforeText"); + langConfig.onEnterRules = utils.mergeArraysBy(Rules.hashEnterRules, langConfig.onEnterRules ?? [], "beforeText"); } // ;-style comments else if (singleLineStyle === ";") { - langConfig.onEnterRules = utils.mergeArraysBy(Rules.semicolonEnterRules, langConfig?.onEnterRules, "beforeText"); + langConfig.onEnterRules = utils.mergeArraysBy( + Rules.semicolonEnterRules, + langConfig.onEnterRules ?? [], + "beforeText" + ); } } // If isOnEnter is false AND singleLineStyle isn't false, i.e. a string. else if (!isOnEnter && singleLineStyle) { // If langConfig does NOT have a comments key OR // the comments key exists but does NOT have the lineComment key... - if (!Object.hasOwn(langConfig, "comments") || !Object.hasOwn(langConfig.comments, "lineComment")) { + if (!langConfig.comments || !Object.hasOwn(langConfig.comments, "lineComment")) { // Add the singleLineStyle to the lineComments key and make sure any // blockComments aren't overwritten. langConfig.comments = {...langConfig.comments, lineComment: singleLineStyle}; @@ -838,7 +843,7 @@ export class Configuration { // Check if isOnEnter OR multiline is true. if (isOnEnter || multiLine) { - langConfig.onEnterRules.forEach((item) => { + (langConfig.onEnterRules ?? []).forEach((item) => { // Check if the item has a "beforeText" property and reconstruct its regex pattern. if (Object.hasOwn(item, "beforeText")) { item.beforeText = utils.reconstructRegex(item, "beforeText"); @@ -934,19 +939,20 @@ export class Configuration { * @param {vscode.TextEditor} textEditor The text editor. * @param {vscode.TextEditorEdit} edit The text editor edits. */ - private handleSingleLineBlock(textEditor: vscode.TextEditor, edit: vscode.TextEditorEdit) { + private handleSingleLineBlock(textEditor: vscode.TextEditor, edit?: vscode.TextEditorEdit) { let langId: LanguageId = textEditor.document.languageId; const singleLineLangs = this.getSingleLineLanguages("supportedLanguages"); const customSingleLineLangs = this.getSingleLineLanguages("customSupportedLanguages"); // Get the langId from the auto-supported langs. If it doesn't exist, try getting it from // the custom-supported langs instead. - let style: SingleLineCommentStyle | ExtraSingleLineCommentStyles = singleLineLangs.get(langId) ?? customSingleLineLangs.get(langId); + let style: SingleLineCommentStyle | ExtraSingleLineCommentStyles | undefined = + singleLineLangs.get(langId) ?? customSingleLineLangs.get(langId); if (style && textEditor.selection.isEmpty) { let line = textEditor.document.lineAt(textEditor.selection.active); let isCommentLine = true; - let indentRegex: RegExp; + let indentRegex: RegExp | undefined; if (style === "//" && line.text.search(/^\s*\/\/\s*/) !== -1) { indentRegex = /\//; @@ -972,7 +978,7 @@ export class Configuration { isCommentLine = false; } - if (!isCommentLine) { + if (!isCommentLine || !indentRegex) { return; } @@ -982,7 +988,7 @@ export class Configuration { indentedNewLine += style + " "; } - edit.insert(textEditor.selection.active, indentedNewLine); + edit?.insert(textEditor.selection.active, indentedNewLine); } } diff --git a/src/utils.ts b/src/utils.ts index 3e5f2d6..97f7374 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -23,7 +23,7 @@ export function readJsonFile(filepath: string, // If throwOnFileMissing param is true, throw an error. if (throwOnFileMissing) { const error = new Error(`JSON file not found: "${filepath}"`); - logger.error(error.stack); + logger.error(error.stack ?? error.message); throw error; } // Otherwise just return null. @@ -60,7 +60,7 @@ function parseJsonContent(filepath: string, fi const errorMsg = "Failed to parse a required JSON file"; const error = new Error(`${errorMsg}: "${filepath}"\n\n\tParse Errors:\n\n${errorMessages}\n\tStack Trace:`); - logger.error(error.stack); + logger.error(error.stack ?? error.message); window .showErrorMessage( @@ -137,18 +137,20 @@ export function ensureDirExists(dir: string) { * Reconstruct the regex pattern because vscode doesn't like the regex pattern as a string, * or some patterns are not working as expected. * - * @param {unknown} obj The object + * @param {T} obj The object * @param {string} key The key to check in the object * @returns {RegExp} The reconstructed regex pattern. */ -export function reconstructRegex(obj: unknown, key: string): RegExp { +export function reconstructRegex(obj: T, key: K): RegExp { + const value = obj[key]; + // If key has a "pattern" key, then it's an object... - if (Object.hasOwn(obj[key], "pattern")) { - return new RegExp(obj[key].pattern); + if (typeof value === "object" && value !== null && Object.hasOwn(value, "pattern")) { + return new RegExp((value as unknown as {pattern: string}).pattern); } // Otherwise it's a string. else { - return new RegExp(obj[key]); + return new RegExp(value as string); } } @@ -185,7 +187,7 @@ export function reconstructRegex(obj: unknown, key: string): RegExp { * } */ export function convertMapToReversedObject(m: Map>): T { - const result = {}; + const result: Record> = {}; // Convert a nested key:value Map from inside another Map into an key:array object, // while reversing/switching the keys and values. The Map's values are now the keys of @@ -199,15 +201,15 @@ export function convertMapToReversedObject(m: // Reverse the inner object mapping. // - // Loop through the object (o) keys, assigns a new object (r) with the value of the - // object key (k) as the new key (eg. "//") and the new value is an array of all - // the original object keys (o[k]) (eg. "php"). - // If the key (o[k]) already exists in the new object (r), then just add the - // original key to the array, otherwise start a new array ([]) with the original - // key as value ( (r[o[k]] || []).concat(k) ). - // Add this new reversed object to the result object with the outer map key - // as the key. - result[key] = Object.keys(o).reduce((r, k) => Object.assign(r, {[o[k]]: (r[o[k]] || []).concat(k)}), {}); + // Loop through the object (o) keys, and for each one, push the key (itemKey, eg. "php") + // onto the array keyed by its value (o[itemKey], eg. "//") in the reversed object, + // creating that array on first use. Add this reversed object to the result object + // with the outer map key as the key. + result[key] = Object.keys(o).reduce>((reversed, itemKey) => { + const value = o[itemKey]; + (reversed[value] ??= []).push(itemKey); + return reversed; + }, {}); } return result as T; } @@ -279,9 +281,9 @@ function validateDevEnvVariables() { // Trim whitespace and resolve the path to an absolute path let devPath = path.resolve(process.env.DEV_USER_EXTENSIONS_PATH.trim()); - let stats: fs.Stats; + let stats: fs.Stats | undefined; let errorMsg: string = ""; - let errorData: Error; + let errorData: Error | undefined; // Get the file system stats for the path to check if it exists. // statSync throws an exception if the no file system data exists for the path, @@ -293,7 +295,7 @@ function validateDevEnvVariables() { const errorCode = nodeError.code || "UNKNOWN"; // Handle specific file system errors with user-friendly messages. - const errorMessages = { + const errorMessages: Record = { ENOENT: "Path from env variable 'DEV_USER_EXTENSIONS_PATH' does not exist", EACCES: "Permission denied accessing path from env variable 'DEV_USER_EXTENSIONS_PATH'", UNKNOWN: "Unknown error accessing the path from env variable 'DEV_USER_EXTENSIONS_PATH'", From 3c36b0649754c6c0a15cc63a866c7022d0366118 Mon Sep 17 00:00:00 2001 From: yCodeTech Date: Sat, 5 Sep 2026 06:53:38 +0100 Subject: [PATCH 06/10] fix: ts null error for `packageJsonData`. - Changed type of `packageJsonData` property to allow it to be `null`. - Moved the null check from the `constructor` to the `setExtensionData` method, and use the check to narrow the type and assert that it's not null/falsy, and return early if it is. Using a local variable instead of accessing the property directly ensures TS doesn't keep spitting out null possibility errors. --- src/extensionData.ts | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/src/extensionData.ts b/src/extensionData.ts index dbdeac4..b37efe7 100644 --- a/src/extensionData.ts +++ b/src/extensionData.ts @@ -61,9 +61,9 @@ export class ExtensionData { /** * The package.json data for this extension. * - * @type {IPackageJson} + * @type {IPackageJson | null} */ - private packageJsonData: IPackageJson; + private packageJsonData: IPackageJson | null; /** * Create an instance of the ExtensionData class, which retrieves and stores metadata @@ -90,10 +90,7 @@ export class ExtensionData { this.packageJsonData = this.getExtensionPackageJsonData(); - // Only proceed with extension data setup if packageJsonData is NOT null. - if (this.packageJsonData !== null) { - this.setExtensionData(); - } + this.setExtensionData(); this.setExtensionDiscoveryPaths(); } @@ -101,7 +98,7 @@ export class ExtensionData { /** * Get the names, id, and version of this extension from package.json. * - * @returns {IPackageJson | null} The package.json data for this extension, with extra custom keys. + * @returns {IPackageJson | null} The package.json data for this extension. */ private getExtensionPackageJsonData(): IPackageJson | null { // Get the package.json file path. @@ -113,26 +110,32 @@ export class ExtensionData { * Set the extension data into the extensionData Map. */ private setExtensionData() { + // Only proceed if packageJsonData is NOT falsy, otherwise return early. + const packageJsonData = this.packageJsonData; + if (!packageJsonData) { + return; + } + // Create the extension ID (publisher.name). - const id = `${this.packageJsonData.publisher}.${this.packageJsonData.name}`; + const id = `${packageJsonData.publisher}.${packageJsonData.name}`; // Set each key-value pair directly into the Map this.extensionData.set("id", id); - this.extensionData.set("name", this.packageJsonData.name); + this.extensionData.set("name", packageJsonData.name); // Only set the namespace if it dealing with this extension. - if (this.packageJsonData.name === "automatic-comment-blocks") { + if (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"); + const settingsNamespace: string = packageJsonData.name.replace("automatic", "auto"); this.extensionData.set("namespace", settingsNamespace); } - this.extensionData.set("displayName", this.packageJsonData.displayName); - this.extensionData.set("version", this.packageJsonData.version); + this.extensionData.set("displayName", packageJsonData.displayName); + this.extensionData.set("version", packageJsonData.version); this.extensionData.set("extensionPath", this.extensionPath); - this.extensionData.set("packageJSON", this.packageJsonData); + this.extensionData.set("packageJSON", packageJsonData); } /** From 20032b5e7c518b565a03039e3fba154a1ae02649 Mon Sep 17 00:00:00 2001 From: yCodeTech Date: Sun, 6 Sep 2026 17:35:23 +0100 Subject: [PATCH 07/10] fix: ts error `outputChannel` property has no initializer in a constructor. - Fixed the TS error "Property 'outputChannel' has no initializer and is not definitely assigned in the constructor." in Logger by adding a `constructor` and initialise the output channel inside it. --- src/logger.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/logger.ts b/src/logger.ts index 6f8bee2..d6fdcdd 100644 --- a/src/logger.ts +++ b/src/logger.ts @@ -40,6 +40,14 @@ class Logger { * Methods * ***********/ + /** + * Constructor for the Logger class, which + * initialises the output channel for logging. + */ + constructor() { + this.outputChannel = window.createOutputChannel("Auto Comment Blocks", "log"); + } + /** * Override the output channel * From 276724d2af743cc46b98f0e1d4fa569404bc08fa Mon Sep 17 00:00:00 2001 From: yCodeTech Date: Sun, 6 Sep 2026 17:39:48 +0100 Subject: [PATCH 08/10] remove: the redundant `setupOutputChannel` method in Logger. - Removed the now redundant `setupOutputChannel` Logger method and it's references, this is because the output channel is now setup in the `constructor` so we have no need for this method now. - Removed the redundant `outputChannel` property null check in `showChannel` method since it's never null as it's initialised in `constructor`. --- src/extension.ts | 3 --- src/logger.ts | 23 +++-------------------- 2 files changed, 3 insertions(+), 23 deletions(-) diff --git a/src/extension.ts b/src/extension.ts index 9de99ed..ca89b93 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -9,9 +9,6 @@ import {addDevEnvVariables} from "./utils"; import {LogLevel} from "./interfaces/utils"; export function activate(context: vscode.ExtensionContext) { - // Setup logger first - logger.setupOutputChannel(); - const initialLogLevel = vscode.workspace.getConfiguration("auto-comment-blocks").get("logLevel", "debug"); logger.setLogLevel(initialLogLevel); diff --git a/src/logger.ts b/src/logger.ts index d6fdcdd..328ae01 100644 --- a/src/logger.ts +++ b/src/logger.ts @@ -5,6 +5,7 @@ import {LogLevel, logLevels} from "./interfaces/utils"; /** * Logger class for the Auto Comment Blocks extension. * This class handles logging messages of differing log levels to the output channel. + * Logger is a singleton class, and should only be instantiated once (in this file). * * @class Logger */ @@ -48,19 +49,6 @@ class Logger { this.outputChannel = window.createOutputChannel("Auto Comment Blocks", "log"); } - /** - * Override the output channel - * - * @param {OutputChannel} channelOverride A vscode output channel. - */ - public setupOutputChannel(channelOverride?: OutputChannel): void { - if (channelOverride) { - this.outputChannel = channelOverride; - return; - } - this.outputChannel = window.createOutputChannel("Auto Comment Blocks", "log"); - } - /** * Set the log level. * @@ -98,9 +86,7 @@ class Logger { * Show the output channel to the user. */ public showChannel(): void { - if (this.outputChannel) { - this.outputChannel.show(); - } + this.outputChannel.show(); } /** @@ -198,10 +184,6 @@ class Logger { * @param {unknown} meta Extra data as needed. */ private logMessage(level: string, message: string, meta?: unknown): void { - if (!this.outputChannel) { - this.setupOutputChannel(); - } - message = this.redactUsername(message); const time = new Date().toLocaleTimeString(); @@ -318,4 +300,5 @@ class Logger { } } +// Create and export the singleton instance of the Logger class. export const logger = new Logger(); From 9342b5a9722496bbc9097790d883763a7847a339 Mon Sep 17 00:00:00 2001 From: yCodeTech Date: Sun, 6 Sep 2026 23:59:44 +0100 Subject: [PATCH 09/10] fix: make `edit` param required in `CommandRegistration` interface. - Reverted the `edit` param in the `handleSingleLineBlock` Configuration method back to be required instead of optional because it otherwise insinuates the method can work without the `edit` param which is not true. It must have the param set to work. Also removed the optional chaining operator on the `edit.insert` call. The TS error that the optional operators fixed will return: "Type '(textEditor: TextEditor, edit: TextEditorEdit) => void' is not assignable to type '(textEditor: TextEditor, edit?: TextEditorEdit | undefined) => void'. Types of parameters 'edit' and 'edit' are incompatible. Type 'TextEditorEdit | undefined' is not assignable to type 'TextEditorEdit'. Type 'undefined' is not assignable to type 'TextEditorEdit'." - Fixed the returning TS error above by making the `edit` param required instead of optional in the `handler` function in `CommandRegistration` interface, which the `handleSingleLineBlock` method has to satisfy. --- src/configuration.ts | 4 ++-- src/interfaces/commands.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/configuration.ts b/src/configuration.ts index be257ec..79ef468 100644 --- a/src/configuration.ts +++ b/src/configuration.ts @@ -939,7 +939,7 @@ export class Configuration { * @param {vscode.TextEditor} textEditor The text editor. * @param {vscode.TextEditorEdit} edit The text editor edits. */ - private handleSingleLineBlock(textEditor: vscode.TextEditor, edit?: vscode.TextEditorEdit) { + private handleSingleLineBlock(textEditor: vscode.TextEditor, edit: vscode.TextEditorEdit) { let langId: LanguageId = textEditor.document.languageId; const singleLineLangs = this.getSingleLineLanguages("supportedLanguages"); const customSingleLineLangs = this.getSingleLineLanguages("customSupportedLanguages"); @@ -988,7 +988,7 @@ export class Configuration { indentedNewLine += style + " "; } - edit?.insert(textEditor.selection.active, indentedNewLine); + edit.insert(textEditor.selection.active, indentedNewLine); } } diff --git a/src/interfaces/commands.ts b/src/interfaces/commands.ts index f39d732..56bb138 100644 --- a/src/interfaces/commands.ts +++ b/src/interfaces/commands.ts @@ -18,10 +18,10 @@ export interface CommandRegistration { * command is executed. * * @param textEditor The text editor - * @param edit The text editor edits. Optional because some commands may not need it. + * @param edit The text editor edits. * @returns void */ - handler: (textEditor: vscode.TextEditor, edit?: vscode.TextEditorEdit) => void; + handler: (textEditor: vscode.TextEditor, edit: vscode.TextEditorEdit) => void; } /** From 8b5922927eb79288361bed45902d1888d44edb98 Mon Sep 17 00:00:00 2001 From: yCodeTech Date: Mon, 7 Sep 2026 00:26:21 +0100 Subject: [PATCH 10/10] fix: handling of missing error messages in `validateDevEnvVariables`. If an error code was caught but isn't listed in the messages map, then the `errorMsg` in `validateDevEnvVariables` utils function would return something like "ENOTDIR: undefined: ...". - Fixed by adding a fallback to the `UKNOWN` entry when an error code is not mapped. --- src/utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils.ts b/src/utils.ts index 97f7374..3135b51 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -301,7 +301,7 @@ function validateDevEnvVariables() { UNKNOWN: "Unknown error accessing the path from env variable 'DEV_USER_EXTENSIONS_PATH'", }; - errorMsg = `${errorCode}: ${errorMessages[errorCode]}: "${devPath}". Removing from environment.`; + errorMsg = `${errorCode}: ${errorMessages[errorCode] ?? errorMessages.UNKNOWN}: "${devPath}". Removing from environment.`; errorData = error as Error;