From 1139488627753e620975c2d913e6132737223c09 Mon Sep 17 00:00:00 2001 From: William Killerud Date: Thu, 19 Sep 2024 19:34:06 +0200 Subject: [PATCH 01/23] feat: handle all features for css and scss by default BREAKING CHANGE: See (issue number) --- vscode-extension/package.json | 3 ++- vscode-extension/src/client.ts | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/vscode-extension/package.json b/vscode-extension/package.json index f57f0b74..a82226a4 100644 --- a/vscode-extension/package.json +++ b/vscode-extension/package.json @@ -27,6 +27,7 @@ "Programming Languages" ], "activationEvents": [ + "onLanguage:css", "onLanguage:scss", "onLanguage:sass", "onLanguage:vue", @@ -176,4 +177,4 @@ "publisherId": "02638283-c13a-4acf-9f26-24bdcfdfce24", "isPreReleaseVersion": false } -} \ No newline at end of file +} diff --git a/vscode-extension/src/client.ts b/vscode-extension/src/client.ts index f1add4ec..0b958cb4 100644 --- a/vscode-extension/src/client.ts +++ b/vscode-extension/src/client.ts @@ -36,6 +36,8 @@ export function log(message: string): void { export function createLanguageClientOptions( currentWorkspace?: WorkspaceFolder, ): LanguageClientOptions { + // TODO: also include CSS if opted in + let documentSelector: DocumentSelector = [ { scheme: "untitled", language: "scss" }, { scheme: "untitled", language: "sass" }, From 0d1d3aa949baa306b182c29761b54f661b5d2e14 Mon Sep 17 00:00:00 2001 From: William Killerud Date: Thu, 19 Sep 2024 21:34:36 +0200 Subject: [PATCH 02/23] feat: add a more customisable logger --- packages/language-server/package.json | 4 +- packages/language-server/src/logger.ts | 95 +++++++++++++++++++ packages/language-server/src/server.ts | 47 +++++---- packages/language-server/src/settings.ts | 7 +- .../src/language-services-types.ts | 10 ++ 5 files changed, 137 insertions(+), 26 deletions(-) create mode 100644 packages/language-server/src/logger.ts diff --git a/packages/language-server/package.json b/packages/language-server/package.json index 41bbe69c..417b808d 100644 --- a/packages/language-server/package.json +++ b/packages/language-server/package.json @@ -48,16 +48,16 @@ "coverage": "vitest run --coverage" }, "devDependencies": { - "@vitest/coverage-v8": "2.0.5", "@somesass/language-services": "1.7.1", "@types/node": "20.16.5", + "@vitest/coverage-v8": "2.0.5", "fast-glob": "3.3.2", "merge-options": "3.0.4", "path-browserify": "1.0.1", "process": "0.11.10", "shx": "0.3.4", - "util": "0.12.5", "url": "0.11.4", + "util": "0.12.5", "vscode-languageserver": "9.0.1", "vscode-languageserver-textdocument": "1.0.12", "vscode-languageserver-types": "3.17.5", diff --git a/packages/language-server/src/logger.ts b/packages/language-server/src/logger.ts new file mode 100644 index 00000000..538abdc7 --- /dev/null +++ b/packages/language-server/src/logger.ts @@ -0,0 +1,95 @@ +import type { Connection } from "vscode-languageserver"; + +export interface Logger { + fatal(message: string): void; + error(message: string): void; + warn(message: string): void; + info(message: string): void; + debug(message: string): void; + trace(message: string): void; + /** + * Accepts the same levels as [pino](https://getpino.io/#/docs/api?id=level-string) + */ + setLogLevel(level: string): void; +} + +const fatal = 1; +const error = 2; +const warn = 3; +const info = 4; +const debug = 5; +const trace = 6; +const silent = 0; + +function levelToRank(level: string): number { + switch (level) { + case "fatal": + return fatal; + case "error": + return error; + case "warn": + return warn; + case "info": + return info; + case "debug": + return debug; + case "trace": + return trace; + case "silent": + default: + return silent; + } +} + +class LoggerImpl implements Logger { + #connection: Connection; + #level: number = levelToRank("info"); + + constructor(connection: Connection) { + this.#connection = connection; + } + + setLogLevel(level: string): void { + this.#level = levelToRank(level); + } + + fatal(message: string): void { + if (this.#level <= fatal) { + this.#connection.console.error(message); + } + } + + error(message: string): void { + if (this.#level <= error) { + this.#connection.console.error(message); + } + } + + warn(message: string): void { + if (this.#level <= warn) { + this.#connection.console.warn(message); + } + } + + info(message: string): void { + if (this.#level <= info) { + this.#connection.console.info(message); + } + } + + debug(message: string): void { + if (this.#level <= debug) { + this.#connection.console.debug(message); + } + } + + trace(message: string): void { + if (this.#level <= trace) { + this.#connection.console.debug(message); + } + } +} + +export function createLogger(connection: Connection): Logger { + return new LoggerImpl(connection); +} diff --git a/packages/language-server/src/server.ts b/packages/language-server/src/server.ts index 79b755b9..2b42df3a 100644 --- a/packages/language-server/src/server.ts +++ b/packages/language-server/src/server.ts @@ -24,14 +24,17 @@ import { RuntimeEnvironment } from "./runtime"; import { defaultSettings, IEditorSettings, ISettings } from "./settings"; import { getSassRegionsDocument } from "./utils/embedded"; import WorkspaceScanner from "./workspace-scanner"; +import { createLogger, type Logger } from "./logger"; export class SomeSassServer { private readonly connection: Connection; private readonly runtime: RuntimeEnvironment; + private readonly logger: Logger; constructor(connection: Connection, runtime: RuntimeEnvironment) { this.connection = connection; this.runtime = runtime; + this.logger = createLogger(connection); } public listen(): void { @@ -49,13 +52,13 @@ export class SomeSassServer { // Make the text document manager listen on the connection // _for open, change and close text document events documents.listen(this.connection); - this.connection.console.log(`[Server(${process.pid})] Listening`); + this.logger.info(`[Server(${process.pid})] Listening`); // After the server has started the client sends an initilize request. The server receives // _in the passed params the rootPath of the workspace plus the client capabilites this.connection.onInitialize((params) => { - this.connection.console.debug( - `[Server${process.pid ? `(${process.pid})` : ""} ${workspaceRoot}] received`, + this.logger.trace( + `[Server${process.pid ? `(${process.pid})` : ""} ${workspaceRoot}] got initialize request`, ); clientCapabilities = params.capabilities; @@ -65,6 +68,7 @@ export class SomeSassServer { ls = getLanguageService({ clientCapabilities, fileSystemProvider, + logger: this.logger, }); // TODO: migrate to workspace folders. Workspace was an unnecessary older workaround of mine. @@ -72,10 +76,6 @@ export class SomeSassServer { params.initializationOptions?.workspace || params.rootUri!, ); - this.connection.console.debug( - `[Server${process.pid ? `(${process.pid})` : ""} ${workspaceRoot}] returning server capabilities`, - ); - return { capabilities: { textDocumentSync: TextDocumentSyncKind.Incremental, @@ -130,12 +130,16 @@ export class SomeSassServer { }; }); - function applySettings( + const applySettings = ( editorSettings: IEditorSettings, settings: ISettings, - ) { + ) => { if (!ls) return; + if (settings.logLevel) { + this.logger.setLogLevel(settings.logLevel); + } + ls.configure({ editorSettings, workspaceRoot, @@ -148,11 +152,11 @@ export class SomeSassServer { settings.suggestFunctionsInStringContextAfterSymbols, }, }); - } + }; this.connection.onInitialized(async () => { - this.connection.console.debug( - `[Server${process.pid ? `(${process.pid})` : ""} ${workspaceRoot}] received`, + this.logger.debug( + `[Server${process.pid ? `(${process.pid})` : ""} ${workspaceRoot}] got initialized notification`, ); try { initialScan = new Promise((resolve, reject) => { @@ -191,8 +195,8 @@ export class SomeSassServer { applySettings(editorSettings, settings); - this.connection.console.debug( - `[Server${process.pid ? `(${process.pid})` : ""} ${workspaceRoot}] scanning workspace for files`, + this.logger.debug( + `[Server${process.pid ? `(${process.pid})` : ""} ${workspaceRoot}] scanning workspace for files`, ); return fileSystemProvider @@ -201,8 +205,8 @@ export class SomeSassServer { settings.scannerExclude, ) .then((files) => { - this.connection.console.debug( - `[Server${process.pid ? `(${process.pid})` : ""} ${workspaceRoot}] found ${files.length} files, starting parse`, + this.logger.debug( + `[Server${process.pid ? `(${process.pid})` : ""} ${workspaceRoot}] found ${files.length} files, starting parse`, ); workspaceScanner = new WorkspaceScanner( @@ -217,8 +221,8 @@ export class SomeSassServer { return workspaceScanner.scan(files); }) .then((promises) => { - this.connection.console.debug( - `[Server${process.pid ? `(${process.pid})` : ""} ${workspaceRoot}] parsed ${promises.length} files`, + this.logger.debug( + `[Server${process.pid ? `(${process.pid})` : ""} ${workspaceRoot}] parsed ${promises.length} files`, ); resolve(); }); @@ -227,7 +231,7 @@ export class SomeSassServer { }); await initialScan; } catch (error) { - this.connection.console.log(String(error)); + this.logger.fatal(String(error)); } }); @@ -238,6 +242,9 @@ export class SomeSassServer { try { ls.onDocumentChanged(params.document); + + // TODO: look into this so we can get diagnostics on first open, not working properly + // Check that no new version has been made while we waited, // in which case the diagnostics may no longer be valid. let latest = documents.get(params.document.uri); @@ -448,6 +455,8 @@ export class SomeSassServer { for (const action of actions) { if (action.kind?.startsWith("refactor.extract")) { + // TODO: can we detect support for the custom command here before we do this? + // Replace with a custom command that immediately starts a rename after applying the edit. // If this causes problems for other clients, look into passing some kind of client identifier (optional) // with initOptions that indicate this command exists in the client. diff --git a/packages/language-server/src/settings.ts b/packages/language-server/src/settings.ts index acf0d3f3..6e8b47dd 100644 --- a/packages/language-server/src/settings.ts +++ b/packages/language-server/src/settings.ts @@ -8,6 +8,7 @@ export interface ISettings { readonly suggestFromUseOnly: boolean; readonly suggestFunctionsInStringContextAfterSymbols: " (+-*%"; readonly triggerPropertyValueCompletion: boolean; + readonly logLevel: string; } export interface IEditorSettings { @@ -19,11 +20,7 @@ export interface IEditorSettings { export const defaultSettings: ISettings = Object.freeze({ loadPaths: [], - scannerExclude: [ - "**/.git/**", - "**/node_modules/**", - "**/bower_components/**", - ], + scannerExclude: ["**/.git/**", "**/node_modules/**"], scannerDepth: 30, scanImportedFiles: true, // This setting is essentially "VS Code Compat Mode" if set to false. diff --git a/packages/language-services/src/language-services-types.ts b/packages/language-services/src/language-services-types.ts index c1cc3a2b..6aca5761 100644 --- a/packages/language-services/src/language-services-types.ts +++ b/packages/language-services/src/language-services-types.ts @@ -269,6 +269,15 @@ export interface ClientCapabilities { }; } +export type Logger = { + fatal(message: string): void; + error(message: string): void; + warn(message: string): void; + info(message: string): void; + debug(message: string): void; + trace(message: string): void; +}; + export interface LanguageServiceOptions { clientCapabilities: ClientCapabilities; /** @@ -280,6 +289,7 @@ export interface LanguageServiceOptions { */ fileSystemProvider: FileSystemProvider; languageModelCache?: LanguageModelCacheOptions; + logger?: Logger; } export type LanguageModelCacheOptions = { From d4082cb66cc26b1480454b821699d6fb3b4ef809 Mon Sep 17 00:00:00 2001 From: William Killerud Date: Sat, 21 Sep 2024 11:48:56 +0200 Subject: [PATCH 03/23] feat: adopt all non-formating settings from Code --- package-lock.json | 18 +- packages/language-server/src/configuration.ts | 88 ++ packages/language-server/src/server.ts | 220 ++-- packages/language-server/src/settings.ts | 32 - .../language-server/src/workspace-scanner.ts | 2 +- packages/language-services/package.json | 2 + .../language-services/src/configuration.ts | 249 ++++ .../src/features/code-actions.ts | 14 +- .../src/features/find-colors.ts | 2 +- .../language-services/src/language-feature.ts | 35 +- .../src/language-services-types.ts | 140 ++- .../src/language-services.ts | 8 +- packages/language-services/tsconfig.json | 1 + .../src/services/lintRules.ts | 6 +- vscode-extension/package.json | 1023 +++++++++++++++-- vscode-extension/schemas/package.schema.json | 19 + 16 files changed, 1571 insertions(+), 288 deletions(-) create mode 100644 packages/language-server/src/configuration.ts delete mode 100644 packages/language-server/src/settings.ts create mode 100644 packages/language-services/src/configuration.ts create mode 100644 vscode-extension/schemas/package.schema.json diff --git a/package-lock.json b/package-lock.json index 4074be6c..ebeac1c3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6079,6 +6079,21 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/lodash": { + "version": "4.17.7", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.7.tgz", + "integrity": "sha512-8wTvZawATi/lsmNu10/j2hk1KEP0IvjubqPE3cu1Xz7xfXXt5oCq3SNUz4fMIP4XGF9Ky+Ue2tBA3hcS7LSBlA==", + "license": "MIT" + }, + "node_modules/@types/lodash.merge": { + "version": "4.6.9", + "resolved": "https://registry.npmjs.org/@types/lodash.merge/-/lodash.merge-4.6.9.tgz", + "integrity": "sha512-23sHDPmzd59kUgWyKGiOMO2Qb9YtqRO/x4IhkgNUiPQ1+5MUVqi6bCZeq9nBJ17msjIMbEIO5u+XW4Kz6aGUhQ==", + "license": "MIT", + "dependencies": { + "@types/lodash": "*" + } + }, "node_modules/@types/mime": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", @@ -14906,7 +14921,6 @@ "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true, "license": "MIT" }, "node_modules/lodash.mergewith": { @@ -22931,7 +22945,9 @@ "license": "MIT", "dependencies": { "@somesass/vscode-css-languageservice": "1.7.0", + "@types/lodash.merge": "4.6.9", "colorjs.io": "0.5.2", + "lodash.merge": "4.6.2", "sassdoc-parser": "3.4.0" }, "devDependencies": { diff --git a/packages/language-server/src/configuration.ts b/packages/language-server/src/configuration.ts new file mode 100644 index 00000000..d576762c --- /dev/null +++ b/packages/language-server/src/configuration.ts @@ -0,0 +1,88 @@ +import { + defaultConfiguration, + type LanguageServerConfiguration, +} from "@somesass/language-services"; + +export function toNewConfiguration( + v1: Partial, +): LanguageServerConfiguration { + const newSettings = Object.assign({}, defaultConfiguration); + if (v1.loadPaths) newSettings.workspace.loadPaths = v1.loadPaths; + if (v1.scannerExclude) newSettings.workspace.exclude = v1.scannerExclude; + + if (typeof v1.suggestAllFromOpenDocument !== "undefined") { + newSettings.css.completions.includeFromCurrentDocument = + v1.suggestAllFromOpenDocument; + } + if (typeof v1.suggestionStyle !== "undefined") { + newSettings.css.completions.mixinStyle = v1.suggestionStyle; + } + if (typeof v1.suggestFromUseOnly !== "undefined") { + newSettings.css.completions.suggestFromUseOnly = v1.suggestFromUseOnly; + } + if (typeof v1.triggerPropertyValueCompletion !== "undefined") { + newSettings.css.completions.triggerPropertyValueCompletion = + v1.triggerPropertyValueCompletion; + } + + if (typeof v1.suggestAllFromOpenDocument !== "undefined") { + newSettings.sass.completions.includeFromCurrentDocument = + v1.suggestAllFromOpenDocument; + } + if (typeof v1.suggestionStyle !== "undefined") { + newSettings.sass.completions.mixinStyle = v1.suggestionStyle; + } + if (typeof v1.suggestFromUseOnly !== "undefined") { + newSettings.sass.completions.suggestFromUseOnly = v1.suggestFromUseOnly; + } + if (typeof v1.triggerPropertyValueCompletion !== "undefined") { + newSettings.sass.completions.triggerPropertyValueCompletion = + v1.triggerPropertyValueCompletion; + } + + if (typeof v1.suggestAllFromOpenDocument !== "undefined") { + newSettings.scss.completions.includeFromCurrentDocument = + v1.suggestAllFromOpenDocument; + } + if (typeof v1.suggestionStyle !== "undefined") { + newSettings.scss.completions.mixinStyle = v1.suggestionStyle; + } + if (typeof v1.suggestFromUseOnly !== "undefined") { + newSettings.scss.completions.suggestFromUseOnly = v1.suggestFromUseOnly; + } + if (typeof v1.triggerPropertyValueCompletion !== "undefined") { + newSettings.scss.completions.triggerPropertyValueCompletion = + v1.triggerPropertyValueCompletion; + } + + return newSettings; +} + +export function isOldConfiguration( + maybeV1: Partial, +) { + const asV1 = maybeV1 as Partial; + if (typeof asV1.loadPaths !== "undefined") return true; + if (typeof asV1.scannerExclude !== "undefined") return true; + if (typeof asV1.scannerDepth !== "undefined") return true; + if (typeof asV1.scanImportedFiles !== "undefined") return true; + if (typeof asV1.suggestionStyle !== "undefined") return true; + if (typeof asV1.suggestAllFromOpenDocument !== "undefined") return true; + if (typeof asV1.suggestFromUseOnly !== "undefined") return true; + if (typeof asV1.suggestFunctionsInStringContextAfterSymbols !== "undefined") + return true; + if (typeof asV1.triggerPropertyValueCompletion !== "undefined") return true; + return false; +} + +export interface ConfigurationV1 { + readonly loadPaths: string[]; + readonly scannerExclude: string[]; + readonly scannerDepth: number; + readonly scanImportedFiles: boolean; + readonly suggestionStyle: "all" | "nobracket" | "bracket"; + readonly suggestAllFromOpenDocument: boolean; + readonly suggestFromUseOnly: boolean; + readonly suggestFunctionsInStringContextAfterSymbols: " (+-*%"; + readonly triggerPropertyValueCompletion: boolean; +} diff --git a/packages/language-server/src/server.ts b/packages/language-server/src/server.ts index 2b42df3a..807c16f8 100644 --- a/packages/language-server/src/server.ts +++ b/packages/language-server/src/server.ts @@ -21,7 +21,14 @@ import { URI } from "vscode-uri"; import type { FileSystemProvider } from "./file-system"; import { getFileSystemProvider } from "./file-system-provider"; import { RuntimeEnvironment } from "./runtime"; -import { defaultSettings, IEditorSettings, ISettings } from "./settings"; +import { + defaultSettings, + EditorSettings as EditorConfiguration, + isOldConfiguration, + LanguageServerConfiguration as Configuration, + ConfigurationV1 as ConfigurationV1, + toNewConfiguration, +} from "./configuration"; import { getSassRegionsDocument } from "./utils/embedded"; import WorkspaceScanner from "./workspace-scanner"; import { createLogger, type Logger } from "./logger"; @@ -29,12 +36,14 @@ import { createLogger, type Logger } from "./logger"; export class SomeSassServer { private readonly connection: Connection; private readonly runtime: RuntimeEnvironment; - private readonly logger: Logger; + private readonly log: Logger; constructor(connection: Connection, runtime: RuntimeEnvironment) { this.connection = connection; this.runtime = runtime; - this.logger = createLogger(connection); + this.log = createLogger(connection); + this.log.info(`Some Sass language server is starting`); + this.log.trace(`Process ID ${process.pid}`); } public listen(): void { @@ -52,15 +61,10 @@ export class SomeSassServer { // Make the text document manager listen on the connection // _for open, change and close text document events documents.listen(this.connection); - this.logger.info(`[Server(${process.pid})] Listening`); // After the server has started the client sends an initilize request. The server receives // _in the passed params the rootPath of the workspace plus the client capabilites this.connection.onInitialize((params) => { - this.logger.trace( - `[Server${process.pid ? `(${process.pid})` : ""} ${workspaceRoot}] got initialize request`, - ); - clientCapabilities = params.capabilities; fileSystemProvider = getFileSystemProvider(this.connection, this.runtime); @@ -68,13 +72,14 @@ export class SomeSassServer { ls = getLanguageService({ clientCapabilities, fileSystemProvider, - logger: this.logger, + logger: this.log, }); // TODO: migrate to workspace folders. Workspace was an unnecessary older workaround of mine. workspaceRoot = URI.parse( params.initializationOptions?.workspace || params.rootUri!, ); + this.log.info(`Workspace root ${workspaceRoot}`); return { capabilities: { @@ -130,108 +135,116 @@ export class SomeSassServer { }; }); - const applySettings = ( - editorSettings: IEditorSettings, - settings: ISettings, - ) => { - if (!ls) return; + const applyConfiguration = ( + somesass: Partial, + editor: Partial, + ): Configuration => { + if (isOldConfiguration(somesass)) { + this.log.warn( + `Your somesass configuration uses old setting names. They will continue to work for some time, but it's recommended you change your settings to the new names. See https://wkillerud.github.io/some-sass/user-guide/settings.html`, + ); + somesass = toNewConfiguration(somesass as Partial); + } + + const settings: Configuration = { + ...defaultSettings, + ...somesass, + }; + + const editorSettings: EditorConfiguration = { + insertSpaces: false, + indentSize: undefined, + tabSize: 2, + ...editor, + }; if (settings.logLevel) { - this.logger.setLogLevel(settings.logLevel); + this.log.setLogLevel(settings.logLevel); } - ls.configure({ - editorSettings, - workspaceRoot, - loadPaths: settings.loadPaths, - completionSettings: { - suggestAllFromOpenDocument: settings.suggestAllFromOpenDocument, - suggestFromUseOnly: settings.suggestFromUseOnly, - suggestionStyle: settings.suggestionStyle, - suggestFunctionsInStringContextAfterSymbols: - settings.suggestFunctionsInStringContextAfterSymbols, - }, - }); + if (ls) { + ls.configure({ + editorSettings, + workspaceRoot, + loadPaths: settings.workspace.loadPaths, + completionSettings: { + suggestAllFromOpenDocument: settings.suggestAllFromOpenDocument, + suggestFromUseOnly: settings.suggestFromUseOnly, + suggestionStyle: settings.suggestionStyle, + suggestFunctionsInStringContextAfterSymbols: + settings.suggestFunctionsInStringContextAfterSymbols, + }, + }); + } + + return settings; }; this.connection.onInitialized(async () => { - this.logger.debug( - `[Server${process.pid ? `(${process.pid})` : ""} ${workspaceRoot}] got initialized notification`, - ); try { + // Let other methods await the result of the initial scan before proceeding initialScan = new Promise((resolve, reject) => { - Promise.all([ + const configurationRequests = [ this.connection.workspace.getConfiguration("somesass"), this.connection.workspace.getConfiguration("editor"), - ]).then( - ([somesassConfiguration, editorConfiguration]: [ - Partial, - Partial, - ]) => { - const settings = { - ...defaultSettings, - ...somesassConfiguration, - }; - - const editorSettings: IEditorSettings = { - insertSpaces: false, - indentSize: undefined, - tabSize: 2, - ...editorConfiguration, - }; - - if ( - !ls || - !clientCapabilities || - !workspaceRoot || - !fileSystemProvider - ) { - return reject( - new Error( - "Got onInitialized without onInitialize readying up all required globals", - ), - ); - } + ]; + + Promise.all(configurationRequests).then((configs) => { + if ( + !ls || + !clientCapabilities || + !workspaceRoot || + !fileSystemProvider + ) { + return reject( + new Error( + "Got onInitialized without onInitialize readying up all required globals", + ), + ); + } - applySettings(editorSettings, settings); + let [somesass, editor] = configs as [ + Partial, + Partial, + ]; + + const configuration: Configuration = applyConfiguration( + somesass, + editor, + ); + + this.log.debug( + `[Server${process.pid ? `(${process.pid})` : ""} ${workspaceRoot}] scanning workspace for files`, + ); + + return fileSystemProvider + .findFiles( + "**/*.{css,scss,sass,svelte,astro,vue}", + configuration.workspace.exclude, + ) + .then((files) => { + this.log.debug( + `[Server${process.pid ? `(${process.pid})` : ""} ${workspaceRoot}] found ${files.length} files, starting parse`, + ); - this.logger.debug( - `[Server${process.pid ? `(${process.pid})` : ""} ${workspaceRoot}] scanning workspace for files`, - ); + workspaceScanner = new WorkspaceScanner( + ls!, + fileSystemProvider!, + ); - return fileSystemProvider - .findFiles( - "**/*.{scss,sass,svelte,astro,vue}", - settings.scannerExclude, - ) - .then((files) => { - this.logger.debug( - `[Server${process.pid ? `(${process.pid})` : ""} ${workspaceRoot}] found ${files.length} files, starting parse`, - ); - - workspaceScanner = new WorkspaceScanner( - ls!, - fileSystemProvider!, - { - scanImportedFiles: settings.scanImportedFiles, - scannerDepth: settings.scannerDepth, - }, - ); - - return workspaceScanner.scan(files); - }) - .then((promises) => { - this.logger.debug( - `[Server${process.pid ? `(${process.pid})` : ""} ${workspaceRoot}] parsed ${promises.length} files`, - ); - resolve(); - }); - }, - ); + return workspaceScanner.scan(files); + }) + .then((promises) => { + this.log.debug( + `[Server${process.pid ? `(${process.pid})` : ""} ${workspaceRoot}] parsed ${promises.length} files`, + ); + resolve(); + }); + }); }); await initialScan; } catch (error) { - this.logger.fatal(String(error)); + this.log.fatal(String(error)); } }); @@ -270,25 +283,13 @@ export class SomeSassServer { this.connection.onDidChangeConfiguration((params) => { if (!ls) return; - const somesassConfiguration: Partial = + const somesassConfiguration: Partial = params.settings.somesass; - const editorConfiguration: Partial = + const editorConfiguration: Partial = params.settings.editor; - const settings: ISettings = { - ...defaultSettings, - ...somesassConfiguration, - }; - - const editorSettings: IEditorSettings = { - insertSpaces: false, - indentSize: undefined, - tabSize: 2, - ...editorConfiguration, - }; - - applySettings(editorSettings, settings); + applyConfiguration(somesassConfiguration, editorConfiguration); }); this.connection.onDidChangeWatchedFiles(async (event) => { @@ -577,5 +578,6 @@ export class SomeSassServer { }); this.connection.listen(); + this.log.debug(`Some Sass language server is listening`); } } diff --git a/packages/language-server/src/settings.ts b/packages/language-server/src/settings.ts deleted file mode 100644 index 6e8b47dd..00000000 --- a/packages/language-server/src/settings.ts +++ /dev/null @@ -1,32 +0,0 @@ -export interface ISettings { - readonly loadPaths: string[]; - readonly scannerExclude: string[]; - readonly scannerDepth: number; - readonly scanImportedFiles: boolean; - readonly suggestionStyle: "all" | "nobracket" | "bracket"; - readonly suggestAllFromOpenDocument: boolean; - readonly suggestFromUseOnly: boolean; - readonly suggestFunctionsInStringContextAfterSymbols: " (+-*%"; - readonly triggerPropertyValueCompletion: boolean; - readonly logLevel: string; -} - -export interface IEditorSettings { - insertSpaces: boolean; - /** Introduced in 1.74 */ - indentSize: number | undefined; - tabSize: number; -} - -export const defaultSettings: ISettings = Object.freeze({ - loadPaths: [], - scannerExclude: ["**/.git/**", "**/node_modules/**"], - scannerDepth: 30, - scanImportedFiles: true, - // This setting is essentially "VS Code Compat Mode" if set to false. - suggestAllFromOpenDocument: true, - suggestionStyle: "all", - suggestFromUseOnly: false, - suggestFunctionsInStringContextAfterSymbols: " (+-*%", - triggerPropertyValueCompletion: true, -}); diff --git a/packages/language-server/src/workspace-scanner.ts b/packages/language-server/src/workspace-scanner.ts index 7599c70e..8e8585f9 100644 --- a/packages/language-server/src/workspace-scanner.ts +++ b/packages/language-server/src/workspace-scanner.ts @@ -14,7 +14,7 @@ export default class WorkspaceScanner { constructor( ls: LanguageService, fs: FileSystemProvider, - settings = { scannerDepth: 30, scanImportedFiles: true }, + settings = { scannerDepth: 256, scanImportedFiles: true }, ) { this.#ls = ls; this.#fs = fs; diff --git a/packages/language-services/package.json b/packages/language-services/package.json index cb9aa5d3..f553987b 100644 --- a/packages/language-services/package.json +++ b/packages/language-services/package.json @@ -49,7 +49,9 @@ }, "dependencies": { "@somesass/vscode-css-languageservice": "1.7.0", + "@types/lodash.merge": "4.6.9", "colorjs.io": "0.5.2", + "lodash.merge": "4.6.2", "sassdoc-parser": "3.4.0" }, "devDependencies": { diff --git a/packages/language-services/src/configuration.ts b/packages/language-services/src/configuration.ts new file mode 100644 index 00000000..e9603224 --- /dev/null +++ b/packages/language-services/src/configuration.ts @@ -0,0 +1,249 @@ +import { LanguageServerConfiguration } from "./language-services-types"; + +export const defaultConfiguration: LanguageServerConfiguration = { + logLevel: "info", + workspace: { + exclude: ["**/.git/**", "**/node_modules/**"], + importAliases: {}, + loadPaths: [], + }, + editor: { + colorDecoratorsLimit: 500, + insertSpaces: false, + indentSize: undefined, + tabSize: 2, + }, + css: { + codeAction: { + enabled: true, + }, + completion: { + enabled: true, + completePropertyWithSemicolon: true, + triggerPropertyValueCompletion: true, + }, + colors: { + enabled: true, + }, + definition: { + enabled: true, + }, + diagnostics: { + enabled: true, + deprecation: { + enabled: true, + }, + lint: { + enabled: true, + compatibleVendorPrefixes: "ignore", + vendorPrefix: "warning", + duplicateProperties: "ignore", + emptyRules: "warning", + importStatement: "ignore", + boxModel: "ignore", + universalSelector: "ignore", + zeroUnits: "ignore", + fontFaceProperties: "warning", + hexColorLength: "error", + argumentsInColorFunction: "error", + unknownProperties: "warning", + validProperties: [], + ieHack: "ignore", + unknownVendorSpecificProperties: "ignore", + propertyIgnoredDueToDisplay: "warning", + important: "ignore", + float: "ignore", + idSelector: "ignore", + unknownAtRules: "warning", + }, + }, + foldingRanges: { + enabled: true, + }, + highlights: { + enabled: true, + }, + hover: { + enabled: true, + documentation: true, + references: true, + }, + links: { + enabled: true, + }, + references: { + enabled: true, + }, + rename: { + enabled: true, + }, + selectionRanges: { + enabled: true, + }, + semanticTokens: { + enabled: true, + }, + signatureHelp: { + enabled: true, + }, + workspaceSymbol: { + enabled: true, + }, + }, + sass: { + codeAction: { + enabled: true, + }, + completion: { + enabled: true, + mixinStyle: "all", + suggestFromUseOnly: false, + triggerPropertyValueCompletion: true, + }, + colors: { + enabled: true, + }, + definition: { + enabled: true, + }, + diagnostics: { + enabled: true, + deprecation: { + enabled: true, + }, + lint: { + enabled: true, + compatibleVendorPrefixes: "ignore", + vendorPrefix: "warning", + duplicateProperties: "ignore", + emptyRules: "warning", + importStatement: "ignore", + boxModel: "ignore", + universalSelector: "ignore", + zeroUnits: "ignore", + fontFaceProperties: "warning", + hexColorLength: "error", + argumentsInColorFunction: "error", + unknownProperties: "warning", + validProperties: [], + ieHack: "ignore", + unknownVendorSpecificProperties: "ignore", + propertyIgnoredDueToDisplay: "warning", + important: "ignore", + float: "ignore", + idSelector: "ignore", + unknownAtRules: "warning", + }, + }, + foldingRanges: { + enabled: true, + }, + highlights: { + enabled: true, + }, + hover: { + enabled: true, + documentation: true, + references: true, + }, + links: { + enabled: true, + }, + references: { + enabled: true, + }, + rename: { + enabled: true, + }, + selectionRanges: { + enabled: true, + }, + semanticTokens: { + enabled: true, + }, + signatureHelp: { + enabled: true, + }, + workspaceSymbol: { + enabled: true, + }, + }, + scss: { + codeAction: { + enabled: true, + }, + completion: { + enabled: true, + mixinStyle: "all", + suggestFromUseOnly: false, + triggerPropertyValueCompletion: true, + }, + colors: { + enabled: true, + }, + definition: { + enabled: true, + }, + diagnostics: { + enabled: true, + deprecation: { + enabled: true, + }, + lint: { + enabled: true, + compatibleVendorPrefixes: "ignore", + vendorPrefix: "warning", + duplicateProperties: "ignore", + emptyRules: "warning", + importStatement: "ignore", + boxModel: "ignore", + universalSelector: "ignore", + zeroUnits: "ignore", + fontFaceProperties: "warning", + hexColorLength: "error", + argumentsInColorFunction: "error", + unknownProperties: "warning", + validProperties: [], + ieHack: "ignore", + unknownVendorSpecificProperties: "ignore", + propertyIgnoredDueToDisplay: "warning", + important: "ignore", + float: "ignore", + idSelector: "ignore", + unknownAtRules: "warning", + }, + }, + foldingRanges: { + enabled: true, + }, + highlights: { + enabled: true, + }, + hover: { + enabled: true, + documentation: true, + references: true, + }, + links: { + enabled: true, + }, + references: { + enabled: true, + }, + rename: { + enabled: true, + }, + selectionRanges: { + enabled: true, + }, + semanticTokens: { + enabled: true, + }, + signatureHelp: { + enabled: true, + }, + workspaceSymbol: { + enabled: true, + }, + }, +}; diff --git a/packages/language-services/src/features/code-actions.ts b/packages/language-services/src/features/code-actions.ts index 18feee26..5d07db0c 100644 --- a/packages/language-services/src/features/code-actions.ts +++ b/packages/language-services/src/features/code-actions.ts @@ -3,7 +3,7 @@ import { CodeAction, CodeActionContext, CodeActionKind, - LanguageServiceConfiguration, + LanguageServerConfiguration, Position, Range, TextDocument, @@ -271,14 +271,14 @@ const tab = " "; function indentText( text: string, - settings: LanguageServiceConfiguration, + settings: LanguageServerConfiguration, ): string { - if (settings.editorSettings?.insertSpaces) { + if (settings.editor?.insertSpaces) { const numberOfSpaces: number = - typeof settings.editorSettings?.indentSize === "number" - ? settings.editorSettings?.indentSize - : typeof settings.editorSettings?.tabSize === "number" - ? settings.editorSettings?.tabSize + typeof settings.editor?.indentSize === "number" + ? settings.editor?.indentSize + : typeof settings.editor?.tabSize === "number" + ? settings.editor?.tabSize : 2; return `${space.repeat(numberOfSpaces)}${text}`; } diff --git a/packages/language-services/src/features/find-colors.ts b/packages/language-services/src/features/find-colors.ts index 0931d7df..4306468b 100644 --- a/packages/language-services/src/features/find-colors.ts +++ b/packages/language-services/src/features/find-colors.ts @@ -33,7 +33,7 @@ export class FindColors extends LanguageFeature { if ( variables.length > - (this.configuration.editorSettings?.colorDecoratorsLimit || 500) + (this.configuration.editor?.colorDecoratorsLimit || 500) ) { // skip color decorators for large documents return []; diff --git a/packages/language-services/src/language-feature.ts b/packages/language-services/src/language-feature.ts index a9187e4e..37e4d30c 100644 --- a/packages/language-services/src/language-feature.ts +++ b/packages/language-services/src/language-feature.ts @@ -5,12 +5,14 @@ import { Scanner, SassScanner, } from "@somesass/vscode-css-languageservice"; +import merge from "lodash.merge"; +import { defaultConfiguration } from "./configuration"; import { LanguageModelCache } from "./language-model-cache"; import { LanguageServiceOptions, TextDocument, LanguageService, - LanguageServiceConfiguration, + LanguageServerConfiguration, NodeType, Range, SassDocumentSymbol, @@ -26,7 +28,7 @@ import { asDollarlessVariable } from "./utils/sass"; export type LanguageFeatureInternal = { cache: LanguageModelCache; - sassLs: VSCodeLanguageService; + vscodeLs: VSCodeLanguageService; }; type FindOptions = { @@ -39,16 +41,6 @@ type FindOptions = { depth?: number; }; -const defaultConfiguration: LanguageServiceConfiguration = { - completionSettings: { - suggestAllFromOpenDocument: false, - suggestFromUseOnly: false, - suggestFunctionsInStringContextAfterSymbols: " (+-*%", - suggestionStyle: "all", - triggerPropertyValueCompletion: true, - }, -}; - /** * Base class for features. Provides helpers to do the navigation * between modules. @@ -57,7 +49,7 @@ export abstract class LanguageFeature { protected ls; protected options; protected clientCapabilities: ClientCapabilities; - protected configuration: LanguageServiceConfiguration = {}; + protected configuration: LanguageServerConfiguration = defaultConfiguration; private _internal: LanguageFeatureInternal; @@ -76,20 +68,15 @@ export abstract class LanguageFeature { this._internal = _internal; } - configure(configuration: LanguageServiceConfiguration): void { - this.configuration = { - ...defaultConfiguration, - ...configuration, - completionSettings: { - ...defaultConfiguration.completionSettings, - ...(configuration.completionSettings || {}), - }, - }; - this._internal.sassLs.configure(configuration); + configure(configuration: LanguageServerConfiguration): void { + this.configuration = merge(defaultConfiguration, configuration); + this._internal.vscodeLs.configure({ + validate: false, + }); } protected getUpstreamLanguageServer(): VSCodeLanguageService { - return this._internal.sassLs; + return this._internal.vscodeLs; } protected getDocumentContext() { diff --git a/packages/language-services/src/language-services-types.ts b/packages/language-services/src/language-services-types.ts index 6aca5761..d288f051 100644 --- a/packages/language-services/src/language-services-types.ts +++ b/packages/language-services/src/language-services-types.ts @@ -81,7 +81,7 @@ export interface LanguageService { clearCache(): void; /** * You may want to use this to set the workspace root. - * @param settings {@link LanguageServiceConfiguration} + * @param settings {@link LanguageServerConfiguration} * * @example * ```js @@ -90,7 +90,7 @@ export interface LanguageService { * }); * ``` */ - configure(settings: LanguageServiceConfiguration): void; + configure(settings: LanguageServerConfiguration): void; doComplete( document: TextDocument, position: Position, @@ -175,21 +175,23 @@ export type Rename = | { range: Range; placeholder: string } | { defaultBehavior: boolean }; -export interface LanguageServiceConfiguration { +export type LintLevel = "ignore" | "warning" | "error"; + +export interface LanguageSettings { /** - * Pass in [load paths](https://sass-lang.com/documentation/cli/dart-sass/#load-path) that will be used in addition to `node_modules`. + * A list of relative file paths pointing to JSON files following the custom data format. + * Some Sass loads custom data on startup to enhance its CSS support for CSS custom properties (variables), at-rules, pseudo-classes, and pseudo-elements you specify in the JSON files. + * The file paths are relative to workspace and only workspace folder settings are considered. */ - loadPaths?: string[]; - completionSettings?: { - /** - * Essentially "Visual Studio Code compat mode". - * - * If false, Some Sass will not give code suggestions based on contents from the current document. - * - * If you use this server as well as vscode-css-languageserver you can set this setting to avoid duplicates. - * Has no effect for Sass Indented. - */ - suggestAllFromOpenDocument?: boolean; + customData?: string[]; + codeAction: { + enabled: boolean; + }; + colors: { + enabled: boolean; + }; + completion: { + enabled: boolean; /** * Mixins with `@content` SassDoc annotations and `%placeholders` get two suggestions by default: * - One without `{ }`. @@ -199,38 +201,110 @@ export interface LanguageServiceConfiguration { * - All suggestions (default). * - No brackets. * - Only brackets. This still includes other suggestions, where there are no brackets to begin with. - * - * @default "all" */ - suggestionStyle?: "all" | "nobracket" | "bracket"; + mixinStyle?: "all" | "nobracket" | "bracket"; /** - * Recommended if you don't rely on `@import`. With this setting turned on, + * Recommended if you don't rely on `@import` in Sass. With this setting turned on, * Some Sass will only suggest variables, mixins and functions from the * namespaces that are in use in the open document. */ suggestFromUseOnly?: boolean; - /** - * Suggest functions after the specified symbols when in a string context. - * For example, if you add the `/` symbol to this setting, then `background: url(images/he|)` - * could suggest a `hello()` function (`|` in this case indicates cursor position). - * - * @default " (+-*%" - */ - suggestFunctionsInStringContextAfterSymbols?: string; /** * By default, Some Sass triggers property value completion after selecting a CSS property. * Use this setting to disable this behavior. - * - * @default true */ - triggerPropertyValueCompletion?: boolean; - includePrefixDot?: boolean; + triggerPropertyValueCompletion: boolean; + completePropertyWithSemicolon?: boolean; + }; + definition: { + enabled: boolean; + }; + diagnostics: { + enabled: boolean; + deprecation: { + enabled: boolean; + }; + lint: { + enabled: boolean; + compatibleVendorPrefixes: LintLevel; + vendorPrefix: LintLevel; + duplicateProperties: LintLevel; + emptyRules: LintLevel; + importStatement: LintLevel; + boxModel: LintLevel; + universalSelector: LintLevel; + zeroUnits: LintLevel; + fontFaceProperties: LintLevel; + hexColorLength: LintLevel; + argumentsInColorFunction: LintLevel; + unknownProperties: LintLevel; + validProperties: string[]; + ieHack: LintLevel; + unknownVendorSpecificProperties: LintLevel; + propertyIgnoredDueToDisplay: LintLevel; + important: LintLevel; + float: LintLevel; + idSelector: LintLevel; + unknownAtRules: LintLevel; + [key: string]: any; + }; + }; + foldingRanges: { + enabled: boolean; }; - editorSettings?: EditorSettings; + highlights: { + enabled: boolean; + }; + hover: { + enabled: boolean; + documentation: boolean; + references: boolean; + }; + links: { + enabled: boolean; + }; + references: { + enabled: boolean; + }; + rename: { + enabled: boolean; + }; + selectionRanges: { + enabled: boolean; + }; + semanticTokens: { + enabled: boolean; + }; + signatureHelp: { + enabled: boolean; + }; + workspaceSymbol: { + enabled: boolean; + }; +} + +export interface WorkspaceConfiguration { + exclude: string[]; + importAliases: { + [key: string]: any; + }; + /** + * Pass in [load paths](https://sass-lang.com/documentation/cli/dart-sass/#load-path) that will be used in addition to `node_modules`. + */ + loadPaths: string[]; workspaceRoot?: URI; } -export interface EditorSettings { +export interface LanguageServerConfiguration { + css: LanguageSettings; + sass: LanguageSettings; + scss: LanguageSettings; + editor: EditorConfiguration; + workspace: WorkspaceConfiguration; + logLevel: "trace" | "debug" | "info" | "warn" | "error" | "fatal" | "silent"; +} + +export interface EditorConfiguration { /** * Insert spaces rather than tabs. */ diff --git a/packages/language-services/src/language-services.ts b/packages/language-services/src/language-services.ts index f53dcb92..850881c1 100644 --- a/packages/language-services/src/language-services.ts +++ b/packages/language-services/src/language-services.ts @@ -1,4 +1,5 @@ import { getSassLanguageService } from "@somesass/vscode-css-languageservice"; +import { defaultConfiguration } from "./configuration"; import { CodeActions } from "./features/code-actions"; import { DoComplete } from "./features/do-complete"; import { DoDiagnostics } from "./features/do-diagnostics"; @@ -17,7 +18,7 @@ import { LanguageModelCache as LanguageServerCache } from "./language-model-cach import { CodeActionContext, LanguageService, - LanguageServiceConfiguration, + LanguageServerConfiguration, LanguageServiceOptions, Position, TextDocument, @@ -32,8 +33,9 @@ import { import { mapFsProviders } from "./utils/fs-provider"; export { + defaultConfiguration, LanguageService, - LanguageServiceConfiguration, + LanguageServerConfiguration as LanguageServiceConfiguration, FileStat, FileSystemProvider, FileType, @@ -96,7 +98,7 @@ class LanguageServiceImpl implements LanguageService { this.#selectionRanges = new SelectionRanges(this, options, internal); } - configure(configuration: LanguageServiceConfiguration): void { + configure(configuration: LanguageServerConfiguration): void { this.#codeActions.configure(configuration); this.#doComplete.configure(configuration); this.#doDiagnostics.configure(configuration); diff --git a/packages/language-services/tsconfig.json b/packages/language-services/tsconfig.json index 2b0655a9..569a032c 100644 --- a/packages/language-services/tsconfig.json +++ b/packages/language-services/tsconfig.json @@ -7,6 +7,7 @@ "moduleResolution": "node", "declaration": true, "rootDir": "src", + "allowSyntheticDefaultImports": true, "outDir": "dist", "strict": true }, diff --git a/packages/vscode-css-languageservice/src/services/lintRules.ts b/packages/vscode-css-languageservice/src/services/lintRules.ts index c86311d0..a57036de 100644 --- a/packages/vscode-css-languageservice/src/services/lintRules.ts +++ b/packages/vscode-css-languageservice/src/services/lintRules.ts @@ -46,7 +46,11 @@ export const Rules = { ), DuplicateDeclarations: new Rule("duplicateProperties", l10n.t("Do not use duplicate style definitions"), Ignore), EmptyRuleSet: new Rule("emptyRules", l10n.t("Do not use empty rulesets"), Warning), - ImportStatemement: new Rule("importStatement", l10n.t("Import statements do not load in parallel"), Ignore), + ImportStatemement: new Rule( + "importStatement", + l10n.t("Import statements can lead to sequential loading of CSS"), + Ignore, + ), BewareOfBoxModelSize: new Rule("boxModel", l10n.t("Do not use width or height when using padding or border"), Ignore), UniversalSelector: new Rule("universalSelector", l10n.t("The universal selector (*) is known to be slow"), Ignore), ZeroWithUnit: new Rule("zeroUnits", l10n.t("No unit for zero needed"), Ignore), diff --git a/vscode-extension/package.json b/vscode-extension/package.json index a82226a4..14c5bf4b 100644 --- a/vscode-extension/package.json +++ b/vscode-extension/package.json @@ -1,6 +1,6 @@ { "name": "some-sass", - "displayName": "Some Sass: extended support for Sass and SassDoc", + "displayName": "Some Sass", "description": "Full support for @use and @forward, including aliases, prefixes and hiding. Rich documentation through SassDoc. Workspace-wide code navigation and refactoring.", "version": "3.9.3", "private": true, @@ -61,82 +61,953 @@ "path": "./languages/sass.tmLanguage.json" } ], - "configuration": { - "title": "Some Sass", - "properties": { - "somesass.loadPaths": { - "type": "array", - "items": { - "type": "string" - }, - "default": [], - "markdownDescription": "A list of paths relative to the workspace root where the language server should look for stylesheets loaded by `@use` and `@import`. `node_modules` is always included.\n\nNote that you will have to [configure your Sass compiler separately](https://sass-lang.com/documentation/cli/dart-sass/#load-path)." - }, - "somesass.scannerDepth": { - "type": "number", - "default": 30, - "description": "The maximum number of nested directories to scan." - }, - "somesass.scannerExclude": { - "type": "array", - "items": { - "type": "string" - }, - "default": [ - "**/.git/**", - "**/node_modules/**", - "**/bower_components/**" - ], - "description": "List of glob patterns for directories that are excluded when scanning." - }, - "somesass.scanImportedFiles": { - "type": "boolean", - "default": true, - "deprecationMessage": "Will be removed at some point after `@import` becomes CSS-only.", - "description": "Allows scan imported files. Turning this off will severely limit functionality, and is not recommended." - }, - "somesass.suggestionStyle": { - "type": "string", - "default": "all", - "description": "Controls the style of suggestions for mixins and placeholders.", - "enum": [ - "all", - "nobracket", - "bracket" - ], - "enumItemLabels": [ - "All", - "No brackets", - "Only brackets" - ], - "enumDescriptions": [ - "Show all suggestions", - "Only show suggestions without brackets", - "Where brackets are suggested, omit duplicates without brackets" - ] - }, - "somesass.suggestAllFromOpenDocument": { - "type": "boolean", - "default": false, - "description": "VS Code has built-in code suggestions for (S)CSS symbols declared in the open document. If you prefer the suggestions from Some Sass, you can opt in by turning on this setting. There will be duplicates. No effect for Sass Indented (always on)." - }, - "somesass.suggestFromUseOnly": { - "type": "boolean", - "default": false, - "description": "If your project uses the new module system with @use and @forward, you may want to only include suggestions from your used modules." - }, - "somesass.suggestFunctionsInStringContextAfterSymbols": { - "type": "string", - "default": " (+-*%", - "description": "Allows prompt Functions in String context after specified symbols." - }, - "somesass.triggerPropertyValueCompletion": { - "type": "boolean", - "default": false, - "description": "By default, Some Sass triggers property value completion after selecting a CSS property. Use this setting to disable this behavior." - } + "configuration": [ + { + "title": "CSS", + "properties": { + "somesass.css.customData": { + "type": "array", + "markdownDescription": "A list of relative file paths pointing to JSON files following the [custom data format](https://github.com/microsoft/vscode-css-languageservice/blob/master/docs/customData.md).\n\nSome Sass loads custom data on startup to enhance its CSS support for CSS custom properties (variables), at-rules, pseudo-classes, and pseudo-elements you specify in the JSON files.\n\nThe file paths are relative to workspace and only workspace folder settings are considered.", + "default": [], + "items": { + "type": "string" + }, + "scope": "resource" + }, + "somesass.css.codeAction.enabled": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Enables or disables all code actions." + }, + "somesass.css.colors.enabled": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Enables or disables all color decorators." + }, + "somesass.css.completion.enabled": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Enables or disables all completions (IntelliSense)." + }, + "somesass.css.completion.triggerPropertyValueCompletion": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "By default, Some Sass triggers property value completion after selecting a CSS property. Use this setting to disable this behavior." + }, + "somesass.css.completion.completePropertyWithSemicolon": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Insert semicolon at end of line when completing CSS properties." + }, + "somesass.css.definition.enabled": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Enables or disables Go to Definition." + }, + "somesass.css.diagnostics.enabled": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Enables or disables all diagnostics (deprecation, errors and lint rules)." + }, + "somesass.css.diagnostics.deprecation.enabled": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Enables or disables deprecation diagnostics (strike-through)." + }, + "somesass.css.diagnostics.lint.enabled": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Enables or disables all linting." + }, + "somesass.css.diagnostics.lint.compatibleVendorPrefixes": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "ignore", + "description": "When using a vendor-specific prefix make sure to also include all other vendor-specific properties." + }, + "somesass.css.diagnostics.lint.vendorPrefix": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "warning", + "description": "When using a vendor-specific prefix, also include the standard property." + }, + "somesass.css.diagnostics.lint.duplicateProperties": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "ignore", + "description": "Do not use duplicate style definitions." + }, + "somesass.css.diagnostics.lint.emptyRules": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "warning", + "description": "Do not use empty rulesets." + }, + "somesass.css.diagnostics.lint.importStatement": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "ignore", + "description": "Import statements can lead to sequential loading of CSS." + }, + "somesass.css.diagnostics.lint.boxModel": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "ignore", + "markdownDescription": "Do not use `width` or `height` when using `padding` or `border`." + }, + "somesass.css.diagnostics.lint.universalSelector": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "ignore", + "markdownDescription": "The universal selector (`*`) is known to be slow." + }, + "somesass.css.diagnostics.lint.zeroUnits": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "ignore", + "description": "No unit needed for zero." + }, + "somesass.css.diagnostics.lint.fontFaceProperties": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "warning", + "markdownDescription": "`@font-face` rule must define `src` and `font-family` properties." + }, + "somesass.css.diagnostics.lint.hexColorLength": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "error", + "description": "Hex colors must consist of 3, 4, 6 or 8 hex numbers." + }, + "somesass.css.diagnostics.lint.argumentsInColorFunction": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "error", + "description": "Invalid number of parameters." + }, + "somesass.css.diagnostics.lint.unknownProperties": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "warning", + "description": "Unknown vendor specific property." + }, + "somesass.css.diagnostics.lint.validProperties": { + "type": "array", + "uniqueItems": true, + "items": { + "type": "string" + }, + "scope": "resource", + "default": [], + "description": "A list of properties that are not validated against the `unknownProperties` rule." + }, + "somesass.css.diagnostics.lint.ieHack": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "ignore", + "description": "IE hacks are only necessary when supporting IE7 and older." + }, + "somesass.css.diagnostics.lint.unknownVendorSpecificProperties": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "ignore", + "description": "Unknown vendor specific property." + }, + "somesass.css.diagnostics.lint.propertyIgnoredDueToDisplay": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "warning", + "markdownDescription": "Property is ignored due to the display. E.g. with `display: inline`, the `width`, `height`, `margin-top`, `margin-bottom`, and `float` properties have no effect." + }, + "somesass.css.diagnostics.lint.important": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "ignore", + "markdownDescription": "Avoid using `!important`. It is an indication that the specificity of the entire CSS has gotten out of control and needs to be refactored." + }, + "somesass.css.diagnostics.lint.float": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "ignore", + "markdownDescription": "Avoid using `float`. Floats lead to fragile CSS that is easy to break if one aspect of the layout changes." + }, + "somesass.css.diagnostics.lint.idSelector": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "ignore", + "description": "Selectors should not contain IDs because these rules are too tightly coupled with the HTML." + }, + "somesass.css.diagnostics.lint.unknownAtRules": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "warning", + "description": "Unknown at-rule." + }, + "somesass.css.foldingRanges.enabled": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Enable or disable folding ranges." + }, + "somesass.css.highlights.enabled": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Enable or disable highlights." + }, + "somesass.css.hover.enabled": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Enable or disable all hover information." + }, + "somesass.css.hover.documentation": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Show property and value documentation in CSS hovers." + }, + "somesass.css.hover.references": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Show references to MDN in CSS hovers." + }, + "somesass.css.links.enabled": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Enable or disable the link provider that lets you click an import and open the file." + }, + "somesass.css.references.enabled": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Enable or disable Find all references." + }, + "somesass.css.rename.enabled": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Enable or disable Rename." + }, + "somesass.css.selectionRanges.enabled": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Enable or disable selection ranges." + }, + "somesass.css.signatureHelp.enabled": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Enable or disable selection ranges." + }, + "somesass.css.workspaceSymbol.enabled": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Enable or disable selection ranges." + } + } + }, + { + "title": "SCSS", + "properties": { + "somesass.scss.customData": { + "type": "array", + "markdownDescription": "A list of relative file paths pointing to JSON files following the [custom data format](https://github.com/microsoft/vscode-css-languageservice/blob/master/docs/customData.md).\n\nSome Sass loads custom data on startup to enhance its CSS support for CSS custom properties (variables), at-rules, pseudo-classes, and pseudo-elements you specify in the JSON files.\n\nThe file paths are relative to workspace and only workspace folder settings are considered.", + "default": [], + "items": { + "type": "string" + }, + "scope": "resource" + }, + "somesass.scss.codeAction.enabled": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Enables or disables all code actions." + }, + "somesass.scss.colors.enabled": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Enables or disables all color decorators." + }, + "somesass.scss.completion.enabled": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Enables or disables all completions (IntelliSense)." + }, + "somesass.scss.completion.mixinStyle": { + "type": "string", + "default": "all", + "description": "Controls the style of suggestions for mixins and placeholders.", + "enum": ["all", "nobracket", "bracket"], + "enumItemLabels": ["All", "No brackets", "Only brackets"], + "enumDescriptions": [ + "Show all suggestions", + "Only show suggestions without brackets", + "Where brackets are suggested, omit duplicates without brackets" + ] + }, + "somesass.scss.completion.suggestFromUseOnly": { + "type": "boolean", + "default": false, + "description": "If your project uses the new module system with @use and @forward, you may want to only include suggestions from your used modules." + }, + "somesass.scss.completion.triggerPropertyValueCompletion": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "By default, Some Sass triggers property value completion after selecting a CSS property. Use this setting to disable this behavior." + }, + "somesass.scss.completion.completePropertyWithSemicolon": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Insert semicolon at end of line when completing CSS properties." + }, + "somesass.scss.definition.enabled": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Enables or disables Go to Definition." + }, + "somesass.scss.diagnostics.enabled": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Enables or disables all diagnostics (deprecation, errors and lint rules)." + }, + "somesass.scss.diagnostics.deprecation.enabled": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Enables or disables deprecation diagnostics (strike-through)." + }, + "somesass.scss.diagnostics.lint.enabled": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Enables or disables all linting." + }, + "somesass.scss.diagnostics.lint.compatibleVendorPrefixes": { + "type": "string", + "scope": "resource", + "enum": ["ignore", "warning", "error"], + "default": "ignore", + "description": "When using a vendor-specific prefix make sure to also include all other vendor-specific properties." + }, + "somesass.scss.diagnostics.lint.vendorPrefix": { + "type": "string", + "scope": "resource", + "enum": ["ignore", "warning", "error"], + "default": "warning", + "description": "When using a vendor-specific prefix, also include the standard property." + }, + "somesass.scss.diagnostics.lint.duplicateProperties": { + "type": "string", + "scope": "resource", + "enum": ["ignore", "warning", "error"], + "default": "ignore", + "description": "Do not use duplicate style definitions." + }, + "somesass.scss.diagnostics.lint.emptyRules": { + "type": "string", + "scope": "resource", + "enum": ["ignore", "warning", "error"], + "default": "warning", + "description": "Do not use empty rulesets." + }, + "somesass.scss.diagnostics.lint.importStatement": { + "type": "string", + "scope": "resource", + "enum": ["ignore", "warning", "error"], + "default": "ignore", + "description": "Import statements can lead to sequential loading of CSS." + }, + "somesass.scss.diagnostics.lint.boxModel": { + "type": "string", + "scope": "resource", + "enum": ["ignore", "warning", "error"], + "default": "ignore", + "markdownDescription": "Do not use `width` or `height` when using `padding` or `border`." + }, + "somesass.scss.diagnostics.lint.universalSelector": { + "type": "string", + "scope": "resource", + "enum": ["ignore", "warning", "error"], + "default": "ignore", + "markdownDescription": "The universal selector (`*`) is known to be slow." + }, + "somesass.scss.diagnostics.lint.zeroUnits": { + "type": "string", + "scope": "resource", + "enum": ["ignore", "warning", "error"], + "default": "ignore", + "description": "No unit needed for zero." + }, + "somesass.scss.diagnostics.lint.fontFaceProperties": { + "type": "string", + "scope": "resource", + "enum": ["ignore", "warning", "error"], + "default": "warning", + "markdownDescription": "`@font-face` rule must define `src` and `font-family` properties." + }, + "somesass.scss.diagnostics.lint.hexColorLength": { + "type": "string", + "scope": "resource", + "enum": ["ignore", "warning", "error"], + "default": "error", + "description": "Hex colors must consist of 3, 4, 6 or 8 hex numbers." + }, + "somesass.scss.diagnostics.lint.argumentsInColorFunction": { + "type": "string", + "scope": "resource", + "enum": ["ignore", "warning", "error"], + "default": "error", + "description": "Invalid number of parameters." + }, + "somesass.scss.diagnostics.lint.unknownProperties": { + "type": "string", + "scope": "resource", + "enum": ["ignore", "warning", "error"], + "default": "warning", + "description": "Unknown vendor specific property." + }, + "somesass.scss.diagnostics.lint.validProperties": { + "type": "array", + "uniqueItems": true, + "items": { + "type": "string" + }, + "scope": "resource", + "default": [], + "description": "A list of properties that are not validated against the `unknownProperties` rule." + }, + "somesass.scss.diagnostics.lint.ieHack": { + "type": "string", + "scope": "resource", + "enum": ["ignore", "warning", "error"], + "default": "ignore", + "description": "IE hacks are only necessary when supporting IE7 and older." + }, + "somesass.scss.diagnostics.lint.unknownVendorSpecificProperties": { + "type": "string", + "scope": "resource", + "enum": ["ignore", "warning", "error"], + "default": "ignore", + "description": "Unknown vendor specific property." + }, + "somesass.scss.diagnostics.lint.propertyIgnoredDueToDisplay": { + "type": "string", + "scope": "resource", + "enum": ["ignore", "warning", "error"], + "default": "warning", + "markdownDescription": "Property is ignored due to the display. E.g. with `display: inline`, the `width`, `height`, `margin-top`, `margin-bottom`, and `float` properties have no effect." + }, + "somesass.scss.diagnostics.lint.important": { + "type": "string", + "scope": "resource", + "enum": ["ignore", "warning", "error"], + "default": "ignore", + "markdownDescription": "Avoid using `!important`. It is an indication that the specificity of the entire CSS has gotten out of control and needs to be refactored." + }, + "somesass.scss.diagnostics.lint.float": { + "type": "string", + "scope": "resource", + "enum": ["ignore", "warning", "error"], + "default": "ignore", + "markdownDescription": "Avoid using `float`. Floats lead to fragile CSS that is easy to break if one aspect of the layout changes." + }, + "somesass.scss.diagnostics.lint.idSelector": { + "type": "string", + "scope": "resource", + "enum": ["ignore", "warning", "error"], + "default": "ignore", + "description": "Selectors should not contain IDs because these rules are too tightly coupled with the HTML." + }, + "somesass.scss.diagnostics.lint.unknownAtRules": { + "type": "string", + "scope": "resource", + "enum": ["ignore", "warning", "error"], + "default": "warning", + "description": "Unknown at-rule." + }, + "somesass.scss.foldingRanges.enabled": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Enable or disable folding ranges." + }, + "somesass.scss.highlights.enabled": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Enable or disable highlights." + }, + "somesass.scss.hover.enabled": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Enable or disable all hover information." + }, + "somesass.scss.hover.documentation": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Show property and value documentation in CSS hovers." + }, + "somesass.scss.hover.references": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Show references to MDN in CSS hovers." + }, + "somesass.scss.links.enabled": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Enable or disable the link provider that lets you click an import and open the file." + }, + "somesass.scss.references.enabled": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Enable or disable Find all references." + }, + "somesass.scss.rename.enabled": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Enable or disable Rename." + }, + "somesass.scss.selectionRanges.enabled": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Enable or disable selection ranges." + }, + "somesass.scss.signatureHelp.enabled": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Enable or disable selection ranges." + }, + "somesass.scss.workspaceSymbol.enabled": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Enable or disable selection ranges." + } + } + }, + { + "title": "Sass (Indented)", + "properties": { + "somesass.sass.customData": { + "type": "array", + "markdownDescription": "A list of relative file paths pointing to JSON files following the [custom data format](https://github.com/microsoft/vscode-css-languageservice/blob/master/docs/customData.md).\n\nSome Sass loads custom data on startup to enhance its CSS support for CSS custom properties (variables), at-rules, pseudo-classes, and pseudo-elements you specify in the JSON files.\n\nThe file paths are relative to workspace and only workspace folder settings are considered.", + "default": [], + "items": { + "type": "string" + }, + "scope": "resource" + }, + "somesass.sass.codeAction.enabled": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Enables or disables all code actions." + }, + "somesass.sass.colors.enabled": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Enables or disables all color decorators." + }, + "somesass.sass.completion.enabled": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Enables or disables all completions (IntelliSense)." + }, + "somesass.sass.completion.mixinStyle": { + "type": "string", + "default": "all", + "description": "Controls the style of suggestions for mixins and placeholders.", + "enum": ["all", "nobracket", "bracket"], + "enumItemLabels": ["All", "No brackets", "Only brackets"], + "enumDescriptions": [ + "Show all suggestions", + "Only show suggestions without brackets", + "Where brackets are suggested, omit duplicates without brackets" + ] + }, + "somesass.sass.completion.suggestFromUseOnly": { + "type": "boolean", + "default": false, + "description": "If your project uses the new module system with @use and @forward, you may want to only include suggestions from your used modules." + }, + "somesass.sass.completion.triggerPropertyValueCompletion": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "By default, Some Sass triggers property value completion after selecting a CSS property. Use this setting to disable this behavior." + }, + "somesass.sass.definition.enabled": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Enables or disables Go to Definition." + }, + "somesass.sass.diagnostics.enabled": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Enables or disables all diagnostics (deprecation, errors and lint rules)." + }, + "somesass.sass.diagnostics.deprecation.enabled": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Enables or disables deprecation diagnostics (strike-through)." + }, + "somesass.sass.diagnostics.lint.enabled": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Enables or disables all linting." + }, + "somesass.sass.diagnostics.lint.compatibleVendorPrefixes": { + "type": "string", + "scope": "resource", + "enum": ["ignore", "warning", "error"], + "default": "ignore", + "description": "When using a vendor-specific prefix make sure to also include all other vendor-specific properties." + }, + "somesass.sass.diagnostics.lint.vendorPrefix": { + "type": "string", + "scope": "resource", + "enum": ["ignore", "warning", "error"], + "default": "warning", + "description": "When using a vendor-specific prefix, also include the standard property." + }, + "somesass.sass.diagnostics.lint.duplicateProperties": { + "type": "string", + "scope": "resource", + "enum": ["ignore", "warning", "error"], + "default": "ignore", + "description": "Do not use duplicate style definitions." + }, + "somesass.sass.diagnostics.lint.emptyRules": { + "type": "string", + "scope": "resource", + "enum": ["ignore", "warning", "error"], + "default": "warning", + "description": "Do not use empty rulesets." + }, + "somesass.sass.diagnostics.lint.importStatement": { + "type": "string", + "scope": "resource", + "enum": ["ignore", "warning", "error"], + "default": "ignore", + "description": "Import statements can lead to sequential loading of CSS." + }, + "somesass.sass.diagnostics.lint.boxModel": { + "type": "string", + "scope": "resource", + "enum": ["ignore", "warning", "error"], + "default": "ignore", + "markdownDescription": "Do not use `width` or `height` when using `padding` or `border`." + }, + "somesass.sass.diagnostics.lint.universalSelector": { + "type": "string", + "scope": "resource", + "enum": ["ignore", "warning", "error"], + "default": "ignore", + "markdownDescription": "The universal selector (`*`) is known to be slow." + }, + "somesass.sass.diagnostics.lint.zeroUnits": { + "type": "string", + "scope": "resource", + "enum": ["ignore", "warning", "error"], + "default": "ignore", + "description": "No unit needed for zero." + }, + "somesass.sass.diagnostics.lint.fontFaceProperties": { + "type": "string", + "scope": "resource", + "enum": ["ignore", "warning", "error"], + "default": "warning", + "markdownDescription": "`@font-face` rule must define `src` and `font-family` properties." + }, + "somesass.sass.diagnostics.lint.hexColorLength": { + "type": "string", + "scope": "resource", + "enum": ["ignore", "warning", "error"], + "default": "error", + "description": "Hex colors must consist of 3, 4, 6 or 8 hex numbers." + }, + "somesass.sass.diagnostics.lint.argumentsInColorFunction": { + "type": "string", + "scope": "resource", + "enum": ["ignore", "warning", "error"], + "default": "error", + "description": "Invalid number of parameters." + }, + "somesass.sass.diagnostics.lint.unknownProperties": { + "type": "string", + "scope": "resource", + "enum": ["ignore", "warning", "error"], + "default": "warning", + "description": "Unknown vendor specific property." + }, + "somesass.sass.diagnostics.lint.validProperties": { + "type": "array", + "uniqueItems": true, + "items": { + "type": "string" + }, + "scope": "resource", + "default": [], + "description": "A list of properties that are not validated against the `unknownProperties` rule." + }, + "somesass.sass.diagnostics.lint.ieHack": { + "type": "string", + "scope": "resource", + "enum": ["ignore", "warning", "error"], + "default": "ignore", + "description": "IE hacks are only necessary when supporting IE7 and older." + }, + "somesass.sass.diagnostics.lint.unknownVendorSpecificProperties": { + "type": "string", + "scope": "resource", + "enum": ["ignore", "warning", "error"], + "default": "ignore", + "description": "Unknown vendor specific property." + }, + "somesass.sass.diagnostics.lint.propertyIgnoredDueToDisplay": { + "type": "string", + "scope": "resource", + "enum": ["ignore", "warning", "error"], + "default": "warning", + "markdownDescription": "Property is ignored due to the display. E.g. with `display: inline`, the `width`, `height`, `margin-top`, `margin-bottom`, and `float` properties have no effect." + }, + "somesass.sass.diagnostics.lint.important": { + "type": "string", + "scope": "resource", + "enum": ["ignore", "warning", "error"], + "default": "ignore", + "markdownDescription": "Avoid using `!important`. It is an indication that the specificity of the entire CSS has gotten out of control and needs to be refactored." + }, + "somesass.sass.diagnostics.lint.float": { + "type": "string", + "scope": "resource", + "enum": ["ignore", "warning", "error"], + "default": "ignore", + "markdownDescription": "Avoid using `float`. Floats lead to fragile CSS that is easy to break if one aspect of the layout changes." + }, + "somesass.sass.diagnostics.lint.idSelector": { + "type": "string", + "scope": "resource", + "enum": ["ignore", "warning", "error"], + "default": "ignore", + "description": "Selectors should not contain IDs because these rules are too tightly coupled with the HTML." + }, + "somesass.sass.diagnostics.lint.unknownAtRules": { + "type": "string", + "scope": "resource", + "enum": ["ignore", "warning", "error"], + "default": "warning", + "description": "Unknown at-rule." + }, + "somesass.sass.foldingRanges.enabled": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Enable or disable folding ranges." + }, + "somesass.sass.highlights.enabled": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Enable or disable highlights." + }, + "somesass.sass.hover.enabled": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Enable or disable all hover information." + }, + "somesass.sass.hover.documentation": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Show property and value documentation in CSS hovers." + }, + "somesass.sass.hover.references": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Show references to MDN in CSS hovers." + }, + "somesass.sass.links.enabled": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Enable or disable the link provider that lets you click an import and open the file." + }, + "somesass.sass.references.enabled": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Enable or disable Find all references." + }, + "somesass.sass.rename.enabled": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Enable or disable Rename." + }, + "somesass.sass.selectionRanges.enabled": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Enable or disable selection ranges." + }, + "somesass.sass.signatureHelp.enabled": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Enable or disable selection ranges." + }, + "somesass.sass.workspaceSymbol.enabled": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Enable or disable selection ranges." + } + } + } + ], + "jsonValidation": [ + { + "fileMatch": "*.css-data.json", + "url": "https://raw.githubusercontent.com/microsoft/vscode-css-languageservice/master/docs/customData.schema.json" + }, + { + "fileMatch": "package.json", + "url": "./schemas/package.schema.json" } - } + ] }, "dependencies": { "fast-glob": "3.3.2", diff --git a/vscode-extension/schemas/package.schema.json b/vscode-extension/schemas/package.schema.json new file mode 100644 index 00000000..6c4b91fa --- /dev/null +++ b/vscode-extension/schemas/package.schema.json @@ -0,0 +1,19 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "contributes": { + "type": "object", + "properties": { + "css.customData": { + "type": "array", + "markdownDescription": "A list of relative file paths pointing to JSON files following the [custom data format](https://github.com/microsoft/vscode-css-languageservice/blob/master/docs/customData.md).\n\nVS Code loads custom data on startup to enhance its CSS support for the custom CSS properties, at directives, pseudo classes and pseudo elements you specify in the JSON files.\n\nThe file paths are relative to workspace and only workspace folder settings are considered.", + "items": { + "type": "string", + "description": "Relative path to a CSS custom data file" + } + } + } + } + } +} From 8a4a021af28996479e34cd7b714c792447be630e Mon Sep 17 00:00:00 2001 From: William Killerud Date: Sat, 21 Sep 2024 15:34:49 +0200 Subject: [PATCH 04/23] refactor: to use new settings --- package-lock.json | 4 + packages/language-server/package.json | 6 +- packages/language-server/src/configuration.ts | 30 ++-- packages/language-server/src/server.ts | 64 +++---- packages/language-server/tsconfig.json | 2 +- .../language-services/src/configuration.ts | 12 +- .../__tests__/code-actions-extract.test.ts | 25 ++- .../__tests__/do-complete-at-rules.test.ts | 33 +--- .../__tests__/do-complete-embedded.test.ts | 7 +- .../do-complete-interpolation.test.ts | 39 +++-- .../__tests__/do-complete-modules.test.ts | 165 ++++-------------- .../do-complete-node-modules.test.ts | 16 +- .../do-complete-placeholders.test.ts | 6 +- .../features/__tests__/do-complete.test.ts | 157 +---------------- .../src/features/code-actions.ts | 19 +- .../src/features/do-complete.ts | 38 ++-- .../src/features/do-diagnostics.ts | 10 +- .../src/features/do-hover.ts | 27 +-- .../src/features/do-signature-help.ts | 17 +- .../src/features/find-colors.ts | 41 ++--- .../src/features/find-definition.ts | 22 +-- .../src/features/find-document-highlights.ts | 2 +- .../src/features/find-document-links.ts | 7 +- .../src/features/find-references.ts | 2 +- .../src/features/find-symbols.ts | 5 +- .../src/features/folding-ranges.ts | 2 +- .../src/features/selection-ranges.ts | 2 +- .../language-services/src/language-feature.ts | 75 ++++++-- .../src/language-services-types.ts | 47 +++-- .../src/language-services.ts | 18 +- vscode-extension/package.json | 4 +- 31 files changed, 374 insertions(+), 530 deletions(-) diff --git a/package-lock.json b/package-lock.json index ebeac1c3..987544ee 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22886,6 +22886,10 @@ "name": "some-sass-language-server", "version": "1.8.3", "license": "MIT", + "dependencies": { + "@types/lodash.merge": "4.6.9", + "lodash.merge": "4.6.2" + }, "bin": { "some-sass-language-server": "bin/some-sass-language-server" }, diff --git a/packages/language-server/package.json b/packages/language-server/package.json index 417b808d..824a8d00 100644 --- a/packages/language-server/package.json +++ b/packages/language-server/package.json @@ -42,7 +42,7 @@ "author": "William Killerud (https://www.williamkillerud.com/)", "license": "MIT", "scripts": { - "build": "rspack", + "build": "tsc --noEmit && rspack", "clean": "shx rm -rf dist node_modules", "test": "vitest", "coverage": "vitest run --coverage" @@ -62,5 +62,9 @@ "vscode-languageserver-textdocument": "1.0.12", "vscode-languageserver-types": "3.17.5", "vscode-uri": "3.0.8" + }, + "dependencies": { + "@types/lodash.merge": "4.6.9", + "lodash.merge": "4.6.2" } } diff --git a/packages/language-server/src/configuration.ts b/packages/language-server/src/configuration.ts index d576762c..b3c08ea7 100644 --- a/packages/language-server/src/configuration.ts +++ b/packages/language-server/src/configuration.ts @@ -1,57 +1,57 @@ import { defaultConfiguration, - type LanguageServerConfiguration, + type LanguageServiceConfiguration, } from "@somesass/language-services"; export function toNewConfiguration( v1: Partial, -): LanguageServerConfiguration { +): LanguageServiceConfiguration { const newSettings = Object.assign({}, defaultConfiguration); if (v1.loadPaths) newSettings.workspace.loadPaths = v1.loadPaths; if (v1.scannerExclude) newSettings.workspace.exclude = v1.scannerExclude; if (typeof v1.suggestAllFromOpenDocument !== "undefined") { - newSettings.css.completions.includeFromCurrentDocument = + newSettings.css.completion.includeFromCurrentDocument = v1.suggestAllFromOpenDocument; } if (typeof v1.suggestionStyle !== "undefined") { - newSettings.css.completions.mixinStyle = v1.suggestionStyle; + newSettings.css.completion.mixinStyle = v1.suggestionStyle; } if (typeof v1.suggestFromUseOnly !== "undefined") { - newSettings.css.completions.suggestFromUseOnly = v1.suggestFromUseOnly; + newSettings.css.completion.suggestFromUseOnly = v1.suggestFromUseOnly; } if (typeof v1.triggerPropertyValueCompletion !== "undefined") { - newSettings.css.completions.triggerPropertyValueCompletion = + newSettings.css.completion.triggerPropertyValueCompletion = v1.triggerPropertyValueCompletion; } if (typeof v1.suggestAllFromOpenDocument !== "undefined") { - newSettings.sass.completions.includeFromCurrentDocument = + newSettings.sass.completion.includeFromCurrentDocument = v1.suggestAllFromOpenDocument; } if (typeof v1.suggestionStyle !== "undefined") { - newSettings.sass.completions.mixinStyle = v1.suggestionStyle; + newSettings.sass.completion.mixinStyle = v1.suggestionStyle; } if (typeof v1.suggestFromUseOnly !== "undefined") { - newSettings.sass.completions.suggestFromUseOnly = v1.suggestFromUseOnly; + newSettings.sass.completion.suggestFromUseOnly = v1.suggestFromUseOnly; } if (typeof v1.triggerPropertyValueCompletion !== "undefined") { - newSettings.sass.completions.triggerPropertyValueCompletion = + newSettings.sass.completion.triggerPropertyValueCompletion = v1.triggerPropertyValueCompletion; } if (typeof v1.suggestAllFromOpenDocument !== "undefined") { - newSettings.scss.completions.includeFromCurrentDocument = + newSettings.scss.completion.includeFromCurrentDocument = v1.suggestAllFromOpenDocument; } if (typeof v1.suggestionStyle !== "undefined") { - newSettings.scss.completions.mixinStyle = v1.suggestionStyle; + newSettings.scss.completion.mixinStyle = v1.suggestionStyle; } if (typeof v1.suggestFromUseOnly !== "undefined") { - newSettings.scss.completions.suggestFromUseOnly = v1.suggestFromUseOnly; + newSettings.scss.completion.suggestFromUseOnly = v1.suggestFromUseOnly; } if (typeof v1.triggerPropertyValueCompletion !== "undefined") { - newSettings.scss.completions.triggerPropertyValueCompletion = + newSettings.scss.completion.triggerPropertyValueCompletion = v1.triggerPropertyValueCompletion; } @@ -59,7 +59,7 @@ export function toNewConfiguration( } export function isOldConfiguration( - maybeV1: Partial, + maybeV1: Partial, ) { const asV1 = maybeV1 as Partial; if (typeof asV1.loadPaths !== "undefined") return true; diff --git a/packages/language-server/src/server.ts b/packages/language-server/src/server.ts index 807c16f8..c6a02333 100644 --- a/packages/language-server/src/server.ts +++ b/packages/language-server/src/server.ts @@ -1,6 +1,8 @@ import { + defaultConfiguration, getLanguageService, LanguageService, + LanguageServiceConfiguration, } from "@somesass/language-services"; import { ClientCapabilities, @@ -22,16 +24,15 @@ import type { FileSystemProvider } from "./file-system"; import { getFileSystemProvider } from "./file-system-provider"; import { RuntimeEnvironment } from "./runtime"; import { - defaultSettings, - EditorSettings as EditorConfiguration, + ConfigurationV1, isOldConfiguration, - LanguageServerConfiguration as Configuration, - ConfigurationV1 as ConfigurationV1, toNewConfiguration, } from "./configuration"; import { getSassRegionsDocument } from "./utils/embedded"; import WorkspaceScanner from "./workspace-scanner"; import { createLogger, type Logger } from "./logger"; +import { EditorConfiguration } from "@somesass/language-services/dist/language-services-types"; +import merge from "lodash.merge"; export class SomeSassServer { private readonly connection: Connection; @@ -136,9 +137,9 @@ export class SomeSassServer { }); const applyConfiguration = ( - somesass: Partial, + somesass: Partial, editor: Partial, - ): Configuration => { + ): LanguageServiceConfiguration => { if (isOldConfiguration(somesass)) { this.log.warn( `Your somesass configuration uses old setting names. They will continue to work for some time, but it's recommended you change your settings to the new names. See https://wkillerud.github.io/some-sass/user-guide/settings.html`, @@ -146,35 +147,23 @@ export class SomeSassServer { somesass = toNewConfiguration(somesass as Partial); } - const settings: Configuration = { - ...defaultSettings, - ...somesass, - }; - - const editorSettings: EditorConfiguration = { - insertSpaces: false, - indentSize: undefined, - tabSize: 2, - ...editor, - }; + const settings: LanguageServiceConfiguration = merge( + defaultConfiguration, + somesass, + { + editor: { + ...editor, + }, + }, + ); + settings.workspace.workspaceRoot = workspaceRoot; if (settings.logLevel) { this.log.setLogLevel(settings.logLevel); } if (ls) { - ls.configure({ - editorSettings, - workspaceRoot, - loadPaths: settings.workspace.loadPaths, - completionSettings: { - suggestAllFromOpenDocument: settings.suggestAllFromOpenDocument, - suggestFromUseOnly: settings.suggestFromUseOnly, - suggestionStyle: settings.suggestionStyle, - suggestFunctionsInStringContextAfterSymbols: - settings.suggestFunctionsInStringContextAfterSymbols, - }, - }); + ls.configure(settings); } return settings; @@ -204,14 +193,11 @@ export class SomeSassServer { } let [somesass, editor] = configs as [ - Partial, + Partial, Partial, ]; - const configuration: Configuration = applyConfiguration( - somesass, - editor, - ); + const configuration = applyConfiguration(somesass, editor); this.log.debug( `[Server${process.pid ? `(${process.pid})` : ""} ${workspaceRoot}] scanning workspace for files`, @@ -281,15 +267,7 @@ export class SomeSassServer { documents.onDidChangeContent(onDocumentChanged); this.connection.onDidChangeConfiguration((params) => { - if (!ls) return; - - const somesassConfiguration: Partial = - params.settings.somesass; - - const editorConfiguration: Partial = - params.settings.editor; - - applyConfiguration(somesassConfiguration, editorConfiguration); + applyConfiguration(params.settings.somesass, params.settings.editor); }); this.connection.onDidChangeWatchedFiles(async (event) => { diff --git a/packages/language-server/tsconfig.json b/packages/language-server/tsconfig.json index 9b509303..e33c719f 100644 --- a/packages/language-server/tsconfig.json +++ b/packages/language-server/tsconfig.json @@ -5,9 +5,9 @@ "sourceMap": true, "module": "commonjs", "moduleResolution": "node", - "rootDir": ".", "outDir": "out", "strict": true, + "allowSyntheticDefaultImports": true, "resolveJsonModule": true } } diff --git a/packages/language-services/src/configuration.ts b/packages/language-services/src/configuration.ts index e9603224..b065711d 100644 --- a/packages/language-services/src/configuration.ts +++ b/packages/language-services/src/configuration.ts @@ -10,7 +10,7 @@ export const defaultConfiguration: LanguageServerConfiguration = { editor: { colorDecoratorsLimit: 500, insertSpaces: false, - indentSize: undefined, + indentSize: 2, tabSize: 2, }, css: { @@ -19,11 +19,13 @@ export const defaultConfiguration: LanguageServerConfiguration = { }, completion: { enabled: true, + includeFromCurrentDocument: true, completePropertyWithSemicolon: true, triggerPropertyValueCompletion: true, }, colors: { enabled: true, + includeFromCurrentDocument: true, }, definition: { enabled: true, @@ -90,18 +92,20 @@ export const defaultConfiguration: LanguageServerConfiguration = { enabled: true, }, }, - sass: { + scss: { codeAction: { enabled: true, }, completion: { enabled: true, mixinStyle: "all", + includeFromCurrentDocument: true, suggestFromUseOnly: false, triggerPropertyValueCompletion: true, }, colors: { enabled: true, + includeFromCurrentDocument: true, }, definition: { enabled: true, @@ -168,18 +172,20 @@ export const defaultConfiguration: LanguageServerConfiguration = { enabled: true, }, }, - scss: { + sass: { codeAction: { enabled: true, }, completion: { enabled: true, mixinStyle: "all", + includeFromCurrentDocument: true, suggestFromUseOnly: false, triggerPropertyValueCompletion: true, }, colors: { enabled: true, + includeFromCurrentDocument: true, }, definition: { enabled: true, diff --git a/packages/language-services/src/features/__tests__/code-actions-extract.test.ts b/packages/language-services/src/features/__tests__/code-actions-extract.test.ts index acf1028f..21376699 100644 --- a/packages/language-services/src/features/__tests__/code-actions-extract.test.ts +++ b/packages/language-services/src/features/__tests__/code-actions-extract.test.ts @@ -1,6 +1,9 @@ import { EOL } from "node:os"; import { test, assert, beforeEach } from "vitest"; -import { getLanguageService } from "../../language-services"; +import { + defaultConfiguration, + getLanguageService, +} from "../../language-services"; import { CodeAction, Position, @@ -15,7 +18,7 @@ const ls = getLanguageService({ fileSystemProvider, ...rest }); beforeEach(() => { ls.clearCache(); - ls.configure({}); // Reset any configuration to default + ls.configure(defaultConfiguration); }); const getEdit = (result: CodeAction): TextEdit[] => { @@ -117,7 +120,8 @@ test("extraction for multiline variable", async () => { test("extraction for mixin with tab indents", async () => { ls.configure({ - editorSettings: { + ...defaultConfiguration, + editor: { insertSpaces: false, }, }); @@ -164,7 +168,8 @@ a.cta { test("extraction for mixin with space indents", async () => { ls.configure({ - editorSettings: { + ...defaultConfiguration, + editor: { insertSpaces: true, indentSize: 4, }, @@ -212,7 +217,8 @@ a.cta { test("indented: extraction for mixin", async () => { ls.configure({ - editorSettings: { + ...defaultConfiguration, + editor: { insertSpaces: true, indentSize: 2, }, @@ -260,7 +266,8 @@ a.cta test("extraction for function with tab indents", async () => { ls.configure({ - editorSettings: { + ...defaultConfiguration, + editor: { insertSpaces: false, }, }); @@ -298,7 +305,8 @@ box-shadow: _function();`, test("extraction for function with space indents", async () => { ls.configure({ - editorSettings: { + ...defaultConfiguration, + editor: { insertSpaces: true, indentSize: 2, }, @@ -337,7 +345,8 @@ box-shadow: _function();`, test("indented: extraction for function", async () => { ls.configure({ - editorSettings: { + ...defaultConfiguration, + editor: { insertSpaces: true, indentSize: 2, }, diff --git a/packages/language-services/src/features/__tests__/do-complete-at-rules.test.ts b/packages/language-services/src/features/__tests__/do-complete-at-rules.test.ts index e5248925..1d0c0891 100644 --- a/packages/language-services/src/features/__tests__/do-complete-at-rules.test.ts +++ b/packages/language-services/src/features/__tests__/do-complete-at-rules.test.ts @@ -6,18 +6,19 @@ import { getOptions } from "../../utils/test-helpers"; const { fileSystemProvider, ...rest } = getOptions(); const ls = getLanguageService({ fileSystemProvider, ...rest }); +ls.configure({ + scss: { + completion: { + suggestFromUseOnly: true, + }, + }, +}); + beforeEach(() => { ls.clearCache(); - ls.configure({}); // Reset any configuration to default }); test("should suggest symbol from a different document via @use when in @return", async () => { - ls.configure({ - completionSettings: { - suggestFromUseOnly: true, - }, - }); - const one = fileSystemProvider.createDocument("$primary: limegreen;", { uri: "one.scss", }); @@ -37,12 +38,6 @@ test("should suggest symbol from a different document via @use when in @return", }); test("should suggest symbol from a different document via @use when in @debug", async () => { - ls.configure({ - completionSettings: { - suggestFromUseOnly: true, - }, - }); - const one = fileSystemProvider.createDocument("$primary: limegreen;", { uri: "one.scss", }); @@ -62,12 +57,6 @@ test("should suggest symbol from a different document via @use when in @debug", }); test("should suggest symbol from a different document via @use when in @warn", async () => { - ls.configure({ - completionSettings: { - suggestFromUseOnly: true, - }, - }); - const one = fileSystemProvider.createDocument("$primary: limegreen;", { uri: "one.scss", }); @@ -87,12 +76,6 @@ test("should suggest symbol from a different document via @use when in @warn", a }); test("should suggest symbol from a different document via @use when in @error", async () => { - ls.configure({ - completionSettings: { - suggestFromUseOnly: true, - }, - }); - const one = fileSystemProvider.createDocument("$primary: limegreen;", { uri: "one.scss", }); diff --git a/packages/language-services/src/features/__tests__/do-complete-embedded.test.ts b/packages/language-services/src/features/__tests__/do-complete-embedded.test.ts index 2a2c70ca..a206b251 100644 --- a/packages/language-services/src/features/__tests__/do-complete-embedded.test.ts +++ b/packages/language-services/src/features/__tests__/do-complete-embedded.test.ts @@ -1,4 +1,4 @@ -import { test, assert, beforeEach } from "vitest"; +import { test, assert } from "vitest"; import { getLanguageService } from "../../language-services"; import { CompletionItemKind, @@ -76,11 +76,6 @@ function getSCSSRegionsDocument(document: TextDocument, position?: Position) { return document; } -beforeEach(() => { - ls.clearCache(); - ls.configure({}); // Reset any configuration to default -}); - test("should suggest symbol from a different document via @use", async () => { const one = fileSystemProvider.createDocument("$primary: limegreen;", { uri: "one.scss", diff --git a/packages/language-services/src/features/__tests__/do-complete-interpolation.test.ts b/packages/language-services/src/features/__tests__/do-complete-interpolation.test.ts index 6db38e63..9bbf97df 100644 --- a/packages/language-services/src/features/__tests__/do-complete-interpolation.test.ts +++ b/packages/language-services/src/features/__tests__/do-complete-interpolation.test.ts @@ -1,5 +1,8 @@ import { test, assert, beforeEach } from "vitest"; -import { getLanguageService } from "../../language-services"; +import { + defaultConfiguration, + getLanguageService, +} from "../../language-services"; import { Position } from "../../language-services-types"; import { getOptions } from "../../utils/test-helpers"; @@ -8,14 +11,16 @@ const ls = getLanguageService({ fileSystemProvider, ...rest }); beforeEach(() => { ls.clearCache(); - ls.configure({}); // Reset any configuration to default + ls.configure(defaultConfiguration); }); test("should not suggest mixin or placeholder in string interpolation", async () => { ls.configure({ - completionSettings: { - suggestAllFromOpenDocument: true, - suggestFromUseOnly: false, + scss: { + completion: { + suggestAllFromOpenDocument: true, + suggestFromUseOnly: false, + }, }, }); @@ -39,8 +44,10 @@ test("should not suggest mixin or placeholder in string interpolation", async () test("should not suggest module mixin in string interpolation", async () => { ls.configure({ - completionSettings: { - suggestFromUseOnly: true, + scss: { + completion: { + suggestFromUseOnly: true, + }, }, }); @@ -69,8 +76,10 @@ test("should not suggest module mixin in string interpolation", async () => { test("should suggest symbol from a different document via @use when in string interpolation", async () => { ls.configure({ - completionSettings: { - suggestFromUseOnly: true, + scss: { + completion: { + suggestFromUseOnly: true, + }, }, }); @@ -94,8 +103,10 @@ test("should suggest symbol from a different document via @use when in string in test("should suggest symbols when interpolation is part of CSS selector", async () => { ls.configure({ - completionSettings: { - suggestFromUseOnly: true, + scss: { + completion: { + suggestFromUseOnly: true, + }, }, }); @@ -119,8 +130,10 @@ test("should suggest symbols when interpolation is part of CSS selector", async test("should suggest variables and functions as function parameters in string interpolation ", async () => { ls.configure({ - completionSettings: { - suggestFromUseOnly: true, + scss: { + completion: { + suggestFromUseOnly: true, + }, }, }); diff --git a/packages/language-services/src/features/__tests__/do-complete-modules.test.ts b/packages/language-services/src/features/__tests__/do-complete-modules.test.ts index 8d2a84b4..d6c1b8f7 100644 --- a/packages/language-services/src/features/__tests__/do-complete-modules.test.ts +++ b/packages/language-services/src/features/__tests__/do-complete-modules.test.ts @@ -13,10 +13,17 @@ const ls = getLanguageService({ fileSystemProvider, ...rest }); beforeEach(() => { ls.clearCache(); ls.configure({ - completionSettings: { - suggestFromUseOnly: true, + scss: { + completion: { + suggestFromUseOnly: true, + }, + }, + sass: { + completion: { + suggestFromUseOnly: true, + }, }, - }); // Reset any configuration to default + }); }); test("suggests built-in sass modules", async () => { @@ -306,12 +313,6 @@ test("should suggest symbols from the document we use when it also forwards anot }); test("should not suggest symbols from a module used by the one we use", async () => { - ls.configure({ - completionSettings: { - suggestFromUseOnly: true, - }, - }); - const one = fileSystemProvider.createDocument( ['@use "./three";', "$primary: limegreen;"], { @@ -342,12 +343,6 @@ test("should not suggest symbols from a module used by the one we use", async () }); test("should only suggest symbols from the current namespace, not others being used", async () => { - ls.configure({ - completionSettings: { - suggestFromUseOnly: true, - }, - }); - const one = fileSystemProvider.createDocument( ['@use "./two";', '@use "./three";', "@function test() { @return two."], { @@ -375,12 +370,6 @@ test("should only suggest symbols from the current namespace, not others being u }); test("should not suggest private symbols from the current namespace", async () => { - ls.configure({ - completionSettings: { - suggestFromUseOnly: true, - }, - }); - const one = fileSystemProvider.createDocument( ['@use "./two";', "@function test() { @return two."], { @@ -405,12 +394,6 @@ test("should not suggest private symbols from the current namespace", async () = }); test("should suggest symbol from a different document via @use when in @if", async () => { - ls.configure({ - completionSettings: { - suggestFromUseOnly: true, - }, - }); - const one = fileSystemProvider.createDocument("$primary: limegreen;", { uri: "one.scss", }); @@ -427,12 +410,6 @@ test("should suggest symbol from a different document via @use when in @if", asy }); test("should suggest symbol from a different document via @use when in @else if", async () => { - ls.configure({ - completionSettings: { - suggestFromUseOnly: true, - }, - }); - const one = fileSystemProvider.createDocument("$primary: limegreen;", { uri: "one.scss", }); @@ -452,12 +429,6 @@ test("should suggest symbol from a different document via @use when in @else if" }); test("should suggest symbol from a different document via @use when in @each", async () => { - ls.configure({ - completionSettings: { - suggestFromUseOnly: true, - }, - }); - const one = fileSystemProvider.createDocument("$primary: limegreen;", { uri: "one.scss", }); @@ -477,12 +448,6 @@ test("should suggest symbol from a different document via @use when in @each", a }); test("should suggest symbol from a different document via @use when in @for", async () => { - ls.configure({ - completionSettings: { - suggestFromUseOnly: true, - }, - }); - const one = fileSystemProvider.createDocument("$primary: limegreen;", { uri: "one.scss", }); @@ -502,12 +467,6 @@ test("should suggest symbol from a different document via @use when in @for", as }); test("should suggest symbol from a different document via @use when in @wile", async () => { - ls.configure({ - completionSettings: { - suggestFromUseOnly: true, - }, - }); - const one = fileSystemProvider.createDocument("$primary: limegreen;", { uri: "one.scss", }); @@ -579,12 +538,6 @@ test("should suggest prefixed symbol from a different document via @use and @for }); test("should not include hidden symbol if configured", async () => { - ls.configure({ - completionSettings: { - suggestFromUseOnly: true, - }, - }); - const one = fileSystemProvider.createDocument( ["$primary: limegreen;", "$secret: red;"], { @@ -646,12 +599,6 @@ test("should not include private symbol", async () => { }); test("should only include shown symbol if configured", async () => { - ls.configure({ - completionSettings: { - suggestFromUseOnly: true, - }, - }); - const one = fileSystemProvider.createDocument( ["$primary: limegreen;", "$secondary: yellow;", "$public: red;"], { @@ -692,12 +639,6 @@ test("should only include shown symbol if configured", async () => { }); test("should suggest mixin with no parameter", async () => { - ls.configure({ - completionSettings: { - suggestFromUseOnly: true, - }, - }); - const one = fileSystemProvider.createDocument( ["@mixin primary() { color: $primary; }"], { uri: "one.scss" }, @@ -746,9 +687,11 @@ test("should suggest mixin with no parameter", async () => { test("should suggest mixin with optional parameter", async () => { ls.configure({ - completionSettings: { - suggestFromUseOnly: true, - suggestionStyle: "nobracket", + scss: { + completion: { + mixinStyle: "nobracket", + suggestFromUseOnly: true, + }, }, }); @@ -802,9 +745,11 @@ test("should suggest mixin with optional parameter", async () => { test("should suggest mixin with required parameter", async () => { ls.configure({ - completionSettings: { - suggestFromUseOnly: true, - suggestionStyle: "bracket", + scss: { + completion: { + mixinStyle: "bracket", + suggestFromUseOnly: true, + }, }, }); @@ -858,9 +803,11 @@ test("should suggest mixin with required parameter", async () => { test("given both required and optional parameters should suggest two variants of mixin - one with all parameters and one with only required", async () => { ls.configure({ - completionSettings: { - suggestFromUseOnly: true, - suggestionStyle: "nobracket", + scss: { + completion: { + mixinStyle: "nobracket", + suggestFromUseOnly: true, + }, }, }); @@ -942,12 +889,6 @@ test("given both required and optional parameters should suggest two variants of }); test("should suggest function with no parameter", async () => { - ls.configure({ - completionSettings: { - suggestFromUseOnly: true, - }, - }); - const one = fileSystemProvider.createDocument( ["@function primary() { @return $primary; }"], { uri: "one.scss" }, @@ -995,12 +936,6 @@ test("should suggest function with no parameter", async () => { }); test("should suggest function with optional parameter", async () => { - ls.configure({ - completionSettings: { - suggestFromUseOnly: true, - }, - }); - const one = fileSystemProvider.createDocument( ["@function primary($color: red) { @return $color; }"], { uri: "one.scss" }, @@ -1048,12 +983,6 @@ test("should suggest function with optional parameter", async () => { }); test("should suggest function with required parameter", async () => { - ls.configure({ - completionSettings: { - suggestFromUseOnly: true, - }, - }); - const one = fileSystemProvider.createDocument( ["@function primary($color) { @return $color; }"], { uri: "one.scss" }, @@ -1101,12 +1030,6 @@ test("should suggest function with required parameter", async () => { }); test("given both required and optional parameters should suggest two variants of function - one with all parameters and one with only required", async () => { - ls.configure({ - completionSettings: { - suggestFromUseOnly: true, - }, - }); - const one = fileSystemProvider.createDocument( ["@function primary($a, $b: 1) { @return $a * $b; }"], { uri: "one.scss" }, @@ -1184,8 +1107,10 @@ test("given both required and optional parameters should suggest two variants of test("should suggest all symbols as legacy @import may be in use", async () => { ls.configure({ - completionSettings: { - suggestFromUseOnly: false, + scss: { + completion: { + suggestFromUseOnly: false, + }, }, }); const one = fileSystemProvider.createDocument("$primary: limegreen;", { @@ -1233,9 +1158,10 @@ test("should suggest all symbols as legacy @import may be in use", async () => { test("should not suggest legacy @import symbols if configured", async () => { ls.configure({ - completionSettings: { - suggestAllFromOpenDocument: true, - suggestFromUseOnly: true, + scss: { + completion: { + suggestFromUseOnly: true, + }, }, }); @@ -1258,12 +1184,6 @@ test("should not suggest legacy @import symbols if configured", async () => { }); test("should suggest symbol from a different document via @use with wildcard alias", async () => { - ls.configure({ - completionSettings: { - suggestFromUseOnly: true, - }, - }); - const one = fileSystemProvider.createDocument( ["$primary: limegreen;", "@function one() { @return 1; }"], { @@ -1342,26 +1262,7 @@ test("should suggest symbol from a different document via @use with wildcard ali }); test("does not suggest sass globals if suggestFromUseOnly is true", async () => { - ls.configure({ - completionSettings: { - suggestFromUseOnly: true, - }, - }); - const document = fileSystemProvider.createDocument("@debug co"); const { items } = await ls.doComplete(document, Position.create(0, 9)); assert.isUndefined(items.find((item) => item.label === "comparable")); }); - -// We don't call the upstream for suggestions here since we got complaints about duplicates -test.skip("does suggest sass globals if suggestFromUseOnly is false", async () => { - ls.configure({ - completionSettings: { - suggestFromUseOnly: false, - }, - }); - - const document = fileSystemProvider.createDocument("@debug co"); - const { items } = await ls.doComplete(document, Position.create(0, 9)); - assert.isOk(items.find((item) => item.label === "comparable")); -}); diff --git a/packages/language-services/src/features/__tests__/do-complete-node-modules.test.ts b/packages/language-services/src/features/__tests__/do-complete-node-modules.test.ts index 07529adb..b60bb4c4 100644 --- a/packages/language-services/src/features/__tests__/do-complete-node-modules.test.ts +++ b/packages/language-services/src/features/__tests__/do-complete-node-modules.test.ts @@ -1,4 +1,4 @@ -import { test, assert, beforeEach } from "vitest"; +import { test, assert } from "vitest"; import { getLanguageService } from "../../language-services"; import { Position } from "../../language-services-types"; import { getOptions } from "../../utils/test-helpers"; @@ -6,13 +6,17 @@ import { getOptions } from "../../utils/test-helpers"; const { fileSystemProvider, ...rest } = getOptions(); const ls = getLanguageService({ fileSystemProvider, ...rest }); -beforeEach(() => { - ls.clearCache(); - ls.configure({ - completionSettings: { +ls.configure({ + scss: { + completion: { suggestFromUseOnly: true, }, - }); // Reset any configuration to default + }, + sass: { + completion: { + suggestFromUseOnly: true, + }, + }, }); test("symbols forwarded from node_modules don't get suggested unless used", async () => { diff --git a/packages/language-services/src/features/__tests__/do-complete-placeholders.test.ts b/packages/language-services/src/features/__tests__/do-complete-placeholders.test.ts index 0e79025e..22b2559f 100644 --- a/packages/language-services/src/features/__tests__/do-complete-placeholders.test.ts +++ b/packages/language-services/src/features/__tests__/do-complete-placeholders.test.ts @@ -1,4 +1,4 @@ -import { test, assert, beforeEach } from "vitest"; +import { test, assert } from "vitest"; import { getLanguageService } from "../../language-services"; import { CompletionItemKind, @@ -10,10 +10,6 @@ import { getOptions } from "../../utils/test-helpers"; const { fileSystemProvider, ...rest } = getOptions(); const ls = getLanguageService({ fileSystemProvider, ...rest }); -beforeEach(() => { - ls.clearCache(); -}); - test("when declaring a placeholder selector, suggest placeholders that have an @extend usage", async () => { // https://github.com/wkillerud/some-sass/issues/49 diff --git a/packages/language-services/src/features/__tests__/do-complete.test.ts b/packages/language-services/src/features/__tests__/do-complete.test.ts index e8014f30..b1f1204c 100644 --- a/packages/language-services/src/features/__tests__/do-complete.test.ts +++ b/packages/language-services/src/features/__tests__/do-complete.test.ts @@ -6,19 +6,20 @@ import { getOptions } from "../../utils/test-helpers"; const { fileSystemProvider, ...rest } = getOptions(); const ls = getLanguageService({ fileSystemProvider, ...rest }); +ls.configure({ + scss: { + completion: { + suggestAllFromOpenDocument: true, + suggestFromUseOnly: false, + }, + }, +}); + beforeEach(() => { ls.clearCache(); - ls.configure({}); // Reset any configuration to default }); test("should not suggest mixin or placeholder as a property value", async () => { - ls.configure({ - completionSettings: { - suggestAllFromOpenDocument: true, - suggestFromUseOnly: false, - }, - }); - const one = fileSystemProvider.createDocument([ '$name: "value";', "@mixin mixin($a: 1, $b) {}", @@ -38,13 +39,6 @@ test("should not suggest mixin or placeholder as a property value", async () => }); test("should not suggest mixin or placeholder as a variable value", async () => { - ls.configure({ - completionSettings: { - suggestAllFromOpenDocument: true, - suggestFromUseOnly: false, - }, - }); - const one = fileSystemProvider.createDocument([ '$name: "value";', "@mixin mixin($a: 1, $b) {}", @@ -64,13 +58,6 @@ test("should not suggest mixin or placeholder as a variable value", async () => }); test("should not suggest function, variable or placeholder after an @include", async () => { - ls.configure({ - completionSettings: { - suggestAllFromOpenDocument: true, - suggestFromUseOnly: false, - }, - }); - const one = fileSystemProvider.createDocument([ '$name: "value";', "@mixin mixin($a: 1, $b) {}", @@ -90,13 +77,6 @@ test("should not suggest function, variable or placeholder after an @include", a }); test("should not suggest function, variable or mixin after an @extend", async () => { - ls.configure({ - completionSettings: { - suggestAllFromOpenDocument: true, - suggestFromUseOnly: false, - }, - }); - const one = fileSystemProvider.createDocument([ '$name: "value";', "@mixin mixin($a: 1, $b) {}", @@ -116,13 +96,6 @@ test("should not suggest function, variable or mixin after an @extend", async () }); test("should suggest variable in @return", async () => { - ls.configure({ - completionSettings: { - suggestAllFromOpenDocument: true, - suggestFromUseOnly: false, - }, - }); - const one = fileSystemProvider.createDocument([ '$name: "value";', "@mixin mixin($a: 1, $b) {}", @@ -141,13 +114,6 @@ test("should suggest variable in @return", async () => { }); test("should suggest function in @return", async () => { - ls.configure({ - completionSettings: { - suggestAllFromOpenDocument: true, - suggestFromUseOnly: false, - }, - }); - const one = fileSystemProvider.createDocument([ '$name: "value";', "@mixin mixin($a: 1, $b) {}", @@ -166,13 +132,6 @@ test("should suggest function in @return", async () => { }); test("should suggest variable in @if", async () => { - ls.configure({ - completionSettings: { - suggestAllFromOpenDocument: true, - suggestFromUseOnly: false, - }, - }); - const one = fileSystemProvider.createDocument([ '$name: "value";', "@mixin mixin($a: 1, $b) {}", @@ -192,13 +151,6 @@ test("should suggest variable in @if", async () => { }); test("should suggest function in @if", async () => { - ls.configure({ - completionSettings: { - suggestAllFromOpenDocument: true, - suggestFromUseOnly: false, - }, - }); - const one = fileSystemProvider.createDocument([ '$name: "value";', "@mixin mixin($a: 1, $b) {}", @@ -218,13 +170,6 @@ test("should suggest function in @if", async () => { }); test("should suggest variable in @else if", async () => { - ls.configure({ - completionSettings: { - suggestAllFromOpenDocument: true, - suggestFromUseOnly: false, - }, - }); - const one = fileSystemProvider.createDocument([ '$name: "value";', "@mixin mixin($a: 1, $b) {}", @@ -245,13 +190,6 @@ test("should suggest variable in @else if", async () => { }); test("should suggest function in @else if", async () => { - ls.configure({ - completionSettings: { - suggestAllFromOpenDocument: true, - suggestFromUseOnly: false, - }, - }); - const one = fileSystemProvider.createDocument([ '$name: "value";', "@mixin mixin($a: 1, $b) {}", @@ -272,13 +210,6 @@ test("should suggest function in @else if", async () => { }); test("should not suggest anything for @each before in", async () => { - ls.configure({ - completionSettings: { - suggestAllFromOpenDocument: true, - suggestFromUseOnly: false, - }, - }); - const one = fileSystemProvider.createDocument([ '$name: "value";', "@mixin mixin($a: 1, $b) {}", @@ -295,13 +226,6 @@ test("should not suggest anything for @each before in", async () => { }); test("should suggest variable in for @each $foo in", async () => { - ls.configure({ - completionSettings: { - suggestAllFromOpenDocument: true, - suggestFromUseOnly: false, - }, - }); - const one = fileSystemProvider.createDocument([ '$name: "value";', "@mixin mixin($a: 1, $b) {}", @@ -321,13 +245,6 @@ test("should suggest variable in for @each $foo in", async () => { }); test("should suggest function in for @each $foo in", async () => { - ls.configure({ - completionSettings: { - suggestAllFromOpenDocument: true, - suggestFromUseOnly: false, - }, - }); - const one = fileSystemProvider.createDocument([ '$name: "value";', "@mixin mixin($a: 1, $b) {}", @@ -347,13 +264,6 @@ test("should suggest function in for @each $foo in", async () => { }); test("should not suggest anything in @for before from", async () => { - ls.configure({ - completionSettings: { - suggestAllFromOpenDocument: true, - suggestFromUseOnly: false, - }, - }); - const one = fileSystemProvider.createDocument([ '$name: "value";', "@mixin mixin($a: 1, $b) {}", @@ -370,13 +280,6 @@ test("should not suggest anything in @for before from", async () => { }); test("should suggest variable in @for $i from ", async () => { - ls.configure({ - completionSettings: { - suggestAllFromOpenDocument: true, - suggestFromUseOnly: false, - }, - }); - const one = fileSystemProvider.createDocument([ '$name: "value";', "@mixin mixin($a: 1, $b) {}", @@ -396,13 +299,6 @@ test("should suggest variable in @for $i from ", async () => { }); test("should suggest function in @for $i from ", async () => { - ls.configure({ - completionSettings: { - suggestAllFromOpenDocument: true, - suggestFromUseOnly: false, - }, - }); - const one = fileSystemProvider.createDocument([ '$name: "value";', "@mixin mixin($a: 1, $b) {}", @@ -422,13 +318,6 @@ test("should suggest function in @for $i from ", async () => { }); test("should suggest variable @for $i from 1 to ", async () => { - ls.configure({ - completionSettings: { - suggestAllFromOpenDocument: true, - suggestFromUseOnly: false, - }, - }); - const one = fileSystemProvider.createDocument([ '$name: "value";', "@mixin mixin($a: 1, $b) {}", @@ -448,13 +337,6 @@ test("should suggest variable @for $i from 1 to ", async () => { }); test("should suggest function @for $i from 1 to ", async () => { - ls.configure({ - completionSettings: { - suggestAllFromOpenDocument: true, - suggestFromUseOnly: false, - }, - }); - const one = fileSystemProvider.createDocument([ '$name: "value";', "@mixin mixin($a: 1, $b) {}", @@ -474,13 +356,6 @@ test("should suggest function @for $i from 1 to ", async () => { }); test("should suggest variable in @for $i from 1 through ", async () => { - ls.configure({ - completionSettings: { - suggestAllFromOpenDocument: true, - suggestFromUseOnly: false, - }, - }); - const one = fileSystemProvider.createDocument([ '$name: "value";', "@mixin mixin($a: 1, $b) {}", @@ -500,13 +375,6 @@ test("should suggest variable in @for $i from 1 through ", async () => { }); test("should suggest function in @for $i from 1 through ", async () => { - ls.configure({ - completionSettings: { - suggestAllFromOpenDocument: true, - suggestFromUseOnly: false, - }, - }); - const one = fileSystemProvider.createDocument([ '$name: "value";', "@mixin mixin($a: 1, $b) {}", @@ -526,13 +394,6 @@ test("should suggest function in @for $i from 1 through ", async () => { }); test("should suggest variable and function as parameter to mixin, not mixin or placeholder", async () => { - ls.configure({ - completionSettings: { - suggestAllFromOpenDocument: true, - suggestFromUseOnly: false, - }, - }); - const one = fileSystemProvider.createDocument([ '$name: "value";', "@mixin mixin($a: 1, $b) {}", diff --git a/packages/language-services/src/features/code-actions.ts b/packages/language-services/src/features/code-actions.ts index 5d07db0c..8f64f8d5 100644 --- a/packages/language-services/src/features/code-actions.ts +++ b/packages/language-services/src/features/code-actions.ts @@ -24,18 +24,13 @@ export class CodeActions extends LanguageFeature { } let upstream: CodeAction[] = []; - if ( - document.languageId === "sass" || - this.configuration.completionSettings?.suggestAllFromOpenDocument - ) { - const stylesheet = this.ls.parseStylesheet(document); - upstream = this.getUpstreamLanguageServer().doCodeActions2( - document, - range, - context, - stylesheet, - ); - } + const stylesheet = this.ls.parseStylesheet(document); + upstream = this.getUpstreamLanguageServer(document).doCodeActions2( + document, + range, + context, + stylesheet, + ); return [ this.getExtractVariableAction(document, range), diff --git a/packages/language-services/src/features/do-complete.ts b/packages/language-services/src/features/do-complete.ts index 108a8864..f940d7cb 100644 --- a/packages/language-services/src/features/do-complete.ts +++ b/packages/language-services/src/features/do-complete.ts @@ -92,7 +92,7 @@ export class DoComplete extends LanguageFeature { ): Promise { const result = CompletionList.create([]); - const upstreamLs = this.getUpstreamLanguageServer(); + const upstreamLs = this.getUpstreamLanguageServer(document); const context = this.createCompletionContext(document, position); const stylesheet = this.ls.parseStylesheet(document); @@ -185,7 +185,6 @@ export class DoComplete extends LanguageFeature { position, stylesheet, this.getDocumentContext(), - this.configuration.completionSettings, ); if (upstreamResult.items.length > 0) { result.items.push(...upstreamResult.items); @@ -286,12 +285,13 @@ export class DoComplete extends LanguageFeature { } } + const config = this.languageConfiguration(document); // Legacy @import style suggestions - if (!this.configuration.completionSettings?.suggestFromUseOnly) { + if (!config.completion.suggestFromUseOnly) { const documents = this.cache.documents(); for (const currentDocument of documents) { if ( - !this.configuration.completionSettings?.suggestAllFromOpenDocument && + !config.completion.includeFromCurrentDocument && currentDocument.uri === document.uri ) { continue; @@ -323,6 +323,7 @@ export class DoComplete extends LanguageFeature { if (!context.isMixinContext) break; const items = await this.doMixinCompletion( + document, currentDocument, context, symbol, @@ -358,7 +359,6 @@ export class DoComplete extends LanguageFeature { position, stylesheet, this.getDocumentContext(), - this.configuration.completionSettings, ); if (upstreamResult.items.length > 0) { result.items.push(...upstreamResult.items); @@ -495,11 +495,9 @@ export class DoComplete extends LanguageFeature { const lastChar = lineBeforePosition.charAt( lineBeforePosition.length - 1, ); - const triggers = - this.configuration.completionSettings - ?.suggestFunctionsInStringContextAfterSymbols; - if (triggers) { - context.isFunctionContext = triggers.includes(lastChar); + const functionTriggers = " (+-*%"; + if (functionTriggers) { + context.isFunctionContext = functionTriggers.includes(lastChar); } } } else if (isQuotes) { @@ -544,7 +542,8 @@ export class DoComplete extends LanguageFeature { items.push(...result); } - if (!this.configuration.completionSettings?.suggestFromUseOnly) { + const config = this.languageConfiguration(initialDocument); + if (!config.completion.suggestFromUseOnly) { const documents = this.cache.documents(); for (const current of documents) { if (visited.has(current.uri)) { @@ -754,6 +753,7 @@ export class DoComplete extends LanguageFeature { if (!context.isMixinContext) break; const mixs = await this.doMixinCompletion( + document, currentDocument, context, symbol, @@ -906,6 +906,7 @@ export class DoComplete extends LanguageFeature { } private async doMixinCompletion( + initialDocument: TextDocument, document: TextDocument, context: CompletionContext, symbol: SassDocumentSymbol, @@ -956,13 +957,12 @@ export class DoComplete extends LanguageFeature { base.filterText = `${context.namespace}.${label}`; } + const config = this.languageConfiguration(initialDocument); const makeCompletionVariants = (insert: string, detail?: string) => { // Not all mixins have @content, but when they do, be smart about adding brackets // and move the cursor to be ready to add said contents. // Include as separate suggestion since content may not always be needed or wanted. - if ( - this.configuration.completionSettings?.suggestionStyle !== "bracket" - ) { + if (config.completion.mixinStyle !== "bracket") { items.push({ ...base, labelDetails: detail ? { detail: `(${detail})` } : undefined, @@ -972,8 +972,7 @@ export class DoComplete extends LanguageFeature { if ( snippetSupport && - this.configuration.completionSettings?.suggestionStyle !== - "nobracket" && + config.completion.mixinStyle !== "nobracket" && document.languageId === "scss" ) { // TODO: test if this works correctly with multiline, I think so from the spec text @@ -1196,8 +1195,11 @@ export class DoComplete extends LanguageFeature { const url = node.getText().replace(/["']/g, ""); const moduleName = getModuleNameFromPath(url); - const rootFolderUri = this.configuration.workspaceRoot - ? Utils.joinPath(this.configuration.workspaceRoot, "/").toString(true) + const rootFolderUri = this.configuration.workspace.workspaceRoot + ? Utils.joinPath( + this.configuration.workspace.workspaceRoot, + "/", + ).toString(true) : ""; const documentFolderUri = Utils.dirname(URI.parse(document.uri)).toString( true, diff --git a/packages/language-services/src/features/do-diagnostics.ts b/packages/language-services/src/features/do-diagnostics.ts index 1c90a6a4..67be34bc 100644 --- a/packages/language-services/src/features/do-diagnostics.ts +++ b/packages/language-services/src/features/do-diagnostics.ts @@ -74,11 +74,12 @@ export class DoDiagnostics extends LanguageFeature { return []; } + // TODO: move cssValidation in here so we can apply settings more easliy (turn off linting globally) + const stylesheet = this.ls.parseStylesheet(document); - const diagnostics = this.getUpstreamLanguageServer().doValidation( + const diagnostics = this.getUpstreamLanguageServer(document).doValidation( document, stylesheet, - { validate: true }, ); return diagnostics; } @@ -86,6 +87,11 @@ export class DoDiagnostics extends LanguageFeature { private async doDeprecationDiagnostics( document: TextDocument, ): Promise { + const config = this.languageConfiguration(document); + if (config.diagnostics.deprecation.enabled === false) { + return []; + } + const references = this.getReferences(document); const diagnostics: Diagnostic[] = []; diff --git a/packages/language-services/src/features/do-hover.ts b/packages/language-services/src/features/do-hover.ts index 4d9cb370..b8946b12 100644 --- a/packages/language-services/src/features/do-hover.ts +++ b/packages/language-services/src/features/do-hover.ts @@ -25,6 +25,7 @@ export class DoHover extends LanguageFeature { document: TextDocument, position: Position, ): Promise { + const config = this.languageConfiguration(document); const stylesheet = this.ls.parseStylesheet(document); const offset = document.offsetAt(position); @@ -70,7 +71,7 @@ export class DoHover extends LanguageFeature { if (document.languageId === "sass") { // We are probably hovering over a CSS identifier // and want to defer this to vscode-css-languageservice's hover handler - return this.getUpstreamLanguageServer().doHover( + return this.getUpstreamLanguageServer(document).doHover( document, position, stylesheet, @@ -136,11 +137,14 @@ export class DoHover extends LanguageFeature { kind: MarkupKind.Markdown, value: [ candidate.annotation, - "____", - `[SassDoc reference](http://sassdoc.com/annotations/#${candidate.annotation.slice( - 1, - )})`, - ].join("\n"), + config.hover.references + ? `\n\n[SassDoc reference](http://sassdoc.com/annotations/#${candidate.annotation.slice( + 1, + )})` + : "", + ] + .join("\n") + .trim(), }, }; } @@ -259,9 +263,12 @@ export class DoHover extends LanguageFeature { kind: MarkupKind.Markdown, value: [ description, - "", - `[Sass reference](${reference}#${builtinName})`, - ].join("\n"), + config.hover.references + ? `\n\n[Sass reference](${reference}#${builtinName})` + : "", + ] + .join("\n") + .trim(), }, }; } @@ -271,7 +278,7 @@ export class DoHover extends LanguageFeature { } // Lastly, fall back to CSS hover information - return this.getUpstreamLanguageServer().doHover( + return this.getUpstreamLanguageServer(document).doHover( document, position, stylesheet, diff --git a/packages/language-services/src/features/do-signature-help.ts b/packages/language-services/src/features/do-signature-help.ts index afe95192..2b38f24b 100644 --- a/packages/language-services/src/features/do-signature-help.ts +++ b/packages/language-services/src/features/do-signature-help.ts @@ -18,21 +18,15 @@ export class DoSignatureHelp extends LanguageFeature { async doSignatureHelp( document: TextDocument, position: Position, - ): Promise { + ): Promise { const stylesheet = this.ls.parseStylesheet(document); let node = getNodeAtOffset(stylesheet, document.offsetAt(position)) as | Function | MixinReference | null; - const result: SignatureHelp = { - activeSignature: 0, - activeParameter: 0, - signatures: [], - }; - if (!node) { - return result; + return null; } if ( @@ -44,12 +38,17 @@ export class DoSignatureHelp extends LanguageFeature { (node.parent.type !== NodeType.Function && node.parent.type !== NodeType.MixinReference) ) { - return result; + return null; } node = node.parent as Function | MixinReference; } + const result: SignatureHelp = { + activeSignature: 0, + activeParameter: 0, + signatures: [], + }; const identifier = node.getIdentifier()!.getText(); const parameters = node.getArguments().getChildren(); result.activeParameter = parameters.length; diff --git a/packages/language-services/src/features/find-colors.ts b/packages/language-services/src/features/find-colors.ts index 4306468b..117a2faa 100644 --- a/packages/language-services/src/features/find-colors.ts +++ b/packages/language-services/src/features/find-colors.ts @@ -13,6 +13,7 @@ import { export class FindColors extends LanguageFeature { async findColors(document: TextDocument): Promise { + const config = this.languageConfiguration(document); const variables: Variable[] = []; const stylesheet = this.ls.parseStylesheet(document); stylesheet.accept((node) => { @@ -31,11 +32,8 @@ export class FindColors extends LanguageFeature { return true; }); - if ( - variables.length > - (this.configuration.editor?.colorDecoratorsLimit || 500) - ) { - // skip color decorators for large documents + if (variables.length > this.configuration.editor.colorDecoratorsLimit) { + // skip color decorators for large documents, it freezes up other features return []; } @@ -73,14 +71,14 @@ export class FindColors extends LanguageFeature { }), ); - if (document.languageId === "sass") { - const upstream = this.getUpstreamLanguageServer().findDocumentColors( - document, - stylesheet, - ); - result.push(...upstream); + if (config.colors.includeFromCurrentDocument === false) { + return result.filter((c) => c !== null); } + const upstream = this.getUpstreamLanguageServer( + document, + ).findDocumentColors(document, stylesheet); + result.push(...upstream); return result.filter((c) => c !== null); } @@ -97,25 +95,22 @@ export class FindColors extends LanguageFeature { if (node && node.type === NodeType.VariableName) { const parent = node.getParent(); if (parent && parent.type === NodeType.VariableDeclaration) { - return this.getUpstreamLanguageServer().getColorPresentations( + return this.getUpstreamLanguageServer(document).getColorPresentations( document, stylesheet, color, range, ); + } else { + return []; } - } else if ( - document.languageId === "sass" || - this.configuration.completionSettings?.suggestAllFromOpenDocument - ) { - return this.getUpstreamLanguageServer().getColorPresentations( - document, - stylesheet, - color, - range, - ); } - return []; + return this.getUpstreamLanguageServer(document).getColorPresentations( + document, + stylesheet, + color, + range, + ); } } diff --git a/packages/language-services/src/features/find-definition.ts b/packages/language-services/src/features/find-definition.ts index 1821cbda..9c4653c3 100644 --- a/packages/language-services/src/features/find-definition.ts +++ b/packages/language-services/src/features/find-definition.ts @@ -24,7 +24,11 @@ export class FindDefinition extends LanguageFeature { const offset = document.offsetAt(position); const node = getNodeAtOffset(stylesheet, offset); if (!node) { - return this.goUpstream(document, position, stylesheet); + return this.getUpstreamLanguageServer(document).findDefinition( + document, + position, + stylesheet, + ); } // Sometimes we can't tell at position whether an identifier is a Method or a Function @@ -99,7 +103,11 @@ export class FindDefinition extends LanguageFeature { } if (!name || !kinds) { - return this.goUpstream(document, position, stylesheet); + return this.getUpstreamLanguageServer(document).findDefinition( + document, + position, + stylesheet, + ); } // Traverse the workspace looking for a symbol of kinds.includes(symbol.kind) && name === symbol.name @@ -137,15 +145,7 @@ export class FindDefinition extends LanguageFeature { } } - return this.goUpstream(document, position, stylesheet); - } - - private goUpstream( - document: TextDocument, - position: Position, - stylesheet: Node, - ): Location | null { - return this.getUpstreamLanguageServer().findDefinition( + return this.getUpstreamLanguageServer(document).findDefinition( document, position, stylesheet, diff --git a/packages/language-services/src/features/find-document-highlights.ts b/packages/language-services/src/features/find-document-highlights.ts index b5989e90..65422a46 100644 --- a/packages/language-services/src/features/find-document-highlights.ts +++ b/packages/language-services/src/features/find-document-highlights.ts @@ -11,7 +11,7 @@ export class FindDocumentHighlights extends LanguageFeature { position: Position, ): DocumentHighlight[] { const stylesheet = this.ls.parseStylesheet(document); - return this.getUpstreamLanguageServer().findDocumentHighlights( + return this.getUpstreamLanguageServer(document).findDocumentHighlights( document, position, stylesheet, diff --git a/packages/language-services/src/features/find-document-links.ts b/packages/language-services/src/features/find-document-links.ts index 89be1b51..bd8649a7 100644 --- a/packages/language-services/src/features/find-document-links.ts +++ b/packages/language-services/src/features/find-document-links.ts @@ -13,11 +13,10 @@ export class FindDocumentLinks extends LanguageFeature { if (cached) return cached; const stylesheet = this.ls.parseStylesheet(document); - const links = await this.getUpstreamLanguageServer().findDocumentLinks2( + const links = await this.getUpstreamLanguageServer( document, - stylesheet, - this.getDocumentContext(), - ); + ).findDocumentLinks2(document, stylesheet, this.getDocumentContext()); + for (const link of links) { if (link.target && !link.target.includes("sass:")) { // For monorepos, resolve the real path behind a symlink, since multiple links in `node_modules/` can point to the same file. diff --git a/packages/language-services/src/features/find-references.ts b/packages/language-services/src/features/find-references.ts index badd21f2..3e736097 100644 --- a/packages/language-services/src/features/find-references.ts +++ b/packages/language-services/src/features/find-references.ts @@ -520,7 +520,7 @@ export class FindReferences extends LanguageFeature { return result; } - async isSameRealPath( + private async isSameRealPath( candidate: string, definition: string, ): Promise { diff --git a/packages/language-services/src/features/find-symbols.ts b/packages/language-services/src/features/find-symbols.ts index d5d715ca..0341c5c7 100644 --- a/packages/language-services/src/features/find-symbols.ts +++ b/packages/language-services/src/features/find-symbols.ts @@ -16,10 +16,9 @@ export class FindSymbols extends LanguageFeature { if (cachedSymbols) return cachedSymbols; const stylesheet = this.ls.parseStylesheet(document); - const symbols = this.getUpstreamLanguageServer().findDocumentSymbols2( + const symbols = this.getUpstreamLanguageServer( document, - stylesheet, - ) as SassDocumentSymbol[]; + ).findDocumentSymbols2(document, stylesheet) as SassDocumentSymbol[]; const sassdoc: ParseResult[] = this.cache.getSassdoc(document); for (const doc of sassdoc) { diff --git a/packages/language-services/src/features/folding-ranges.ts b/packages/language-services/src/features/folding-ranges.ts index c89b8456..be6780bc 100644 --- a/packages/language-services/src/features/folding-ranges.ts +++ b/packages/language-services/src/features/folding-ranges.ts @@ -10,7 +10,7 @@ export class FoldingRanges extends LanguageFeature { document: TextDocument, context?: FoldingRangeContext, ): Promise { - const result = this.getUpstreamLanguageServer().getFoldingRanges( + const result = this.getUpstreamLanguageServer(document).getFoldingRanges( document, context, ); diff --git a/packages/language-services/src/features/selection-ranges.ts b/packages/language-services/src/features/selection-ranges.ts index 42597807..eaba3b3b 100644 --- a/packages/language-services/src/features/selection-ranges.ts +++ b/packages/language-services/src/features/selection-ranges.ts @@ -11,7 +11,7 @@ export class SelectionRanges extends LanguageFeature { positions: Position[], ): Promise { const stylesheet = this.ls.parseStylesheet(document); - const result = this.getUpstreamLanguageServer().getSelectionRanges( + const result = this.getUpstreamLanguageServer(document).getSelectionRanges( document, positions, stylesheet, diff --git a/packages/language-services/src/language-feature.ts b/packages/language-services/src/language-feature.ts index 37e4d30c..e912b06b 100644 --- a/packages/language-services/src/language-feature.ts +++ b/packages/language-services/src/language-feature.ts @@ -23,12 +23,16 @@ import { URI, Utils, ClientCapabilities, + RecursivePartial, + LanguageConfiguration, } from "./language-services-types"; import { asDollarlessVariable } from "./utils/sass"; export type LanguageFeatureInternal = { cache: LanguageModelCache; - vscodeLs: VSCodeLanguageService; + cssLs: VSCodeLanguageService; + sassLs: VSCodeLanguageService; + scssLs: VSCodeLanguageService; }; type FindOptions = { @@ -68,15 +72,65 @@ export abstract class LanguageFeature { this._internal = _internal; } - configure(configuration: LanguageServerConfiguration): void { + languageConfiguration(document: TextDocument): LanguageConfiguration { + switch (document.languageId) { + case "css": { + return this.configuration.css; + } + case "sass": { + return this.configuration.sass; + } + case "scss": { + return this.configuration.scss; + } + } + + throw new Error(`Unsupported language ${document.languageId}`); + } + + configure( + configuration: RecursivePartial, + ): void { this.configuration = merge(defaultConfiguration, configuration); - this._internal.vscodeLs.configure({ - validate: false, + + this._internal.sassLs.configure({ + validate: this.configuration.sass.diagnostics.enabled, + lint: this.configuration.sass.diagnostics.lint, + completion: this.configuration.sass.completion, + hover: this.configuration.sass.hover, + importAliases: this.configuration.workspace.importAliases, + loadPaths: this.configuration.workspace.loadPaths, + }); + + this._internal.scssLs.configure({ + validate: this.configuration.scss.diagnostics.enabled, + lint: this.configuration.scss.diagnostics.lint, + completion: this.configuration.scss.completion, + hover: this.configuration.scss.hover, + importAliases: this.configuration.workspace.importAliases, + loadPaths: this.configuration.workspace.loadPaths, + }); + + this._internal.cssLs.configure({ + validate: this.configuration.css.diagnostics.enabled, + lint: this.configuration.css.diagnostics.lint, + completion: this.configuration.css.completion, + hover: this.configuration.css.hover, + importAliases: this.configuration.workspace.importAliases, + loadPaths: this.configuration.workspace.loadPaths, }); } - protected getUpstreamLanguageServer(): VSCodeLanguageService { - return this._internal.vscodeLs; + protected getUpstreamLanguageServer( + document: TextDocument, + ): VSCodeLanguageService { + if (document.languageId === "scss") { + return this._internal.scssLs; + } + if (document.languageId === "css") { + return this._internal.cssLs; + } + return this._internal.sassLs; } protected getDocumentContext() { @@ -86,10 +140,11 @@ export abstract class LanguageFeature { * @returns The resolved path */ resolveReference: (ref: string, base: string) => { - if (ref.startsWith("/") && this.configuration.workspaceRoot) { - return Utils.joinPath(this.configuration.workspaceRoot, ref).toString( - true, - ); + if (ref.startsWith("/") && this.configuration.workspace.workspaceRoot) { + return Utils.joinPath( + this.configuration.workspace.workspaceRoot, + ref, + ).toString(true); } try { return resolve(base, ref); diff --git a/packages/language-services/src/language-services-types.ts b/packages/language-services/src/language-services-types.ts index d288f051..dc4a7d46 100644 --- a/packages/language-services/src/language-services-types.ts +++ b/packages/language-services/src/language-services-types.ts @@ -74,6 +74,14 @@ export interface SassDocumentSymbol extends DocumentSymbol { children?: SassDocumentSymbol[]; } +export type RecursivePartial = { + [P in keyof T]?: T[P] extends (infer U)[] + ? RecursivePartial[] + : T[P] extends object | undefined + ? RecursivePartial + : T[P]; +}; + export interface LanguageService { /** * Clears all cached documents, forcing everything to be reparsed the next time a feature is used. @@ -86,11 +94,13 @@ export interface LanguageService { * @example * ```js * languageService.configure({ - * workspaceRoot: URI.parse(this.workspace), + * workspace: { + * workspaceRoot: URI.parse(this.workspace), + * }, * }); * ``` */ - configure(settings: LanguageServerConfiguration): void; + configure(settings: RecursivePartial): void; doComplete( document: TextDocument, position: Position, @@ -108,7 +118,7 @@ export interface LanguageService { doSignatureHelp( document: TextDocument, position: Position, - ): Promise; + ): Promise; findColors(document: TextDocument): Promise; findDefinition( document: TextDocument, @@ -177,7 +187,7 @@ export type Rename = export type LintLevel = "ignore" | "warning" | "error"; -export interface LanguageSettings { +export interface LanguageConfiguration { /** * A list of relative file paths pointing to JSON files following the custom data format. * Some Sass loads custom data on startup to enhance its CSS support for CSS custom properties (variables), at-rules, pseudo-classes, and pseudo-elements you specify in the JSON files. @@ -189,6 +199,13 @@ export interface LanguageSettings { }; colors: { enabled: boolean; + /** + * Compatibility setting for VS Code. + * + * By default the built-in SCSS server shows color decorators for colors declared in the current document. + * To avoid duplicates, by default Some Sass (only in VS Code) will only show color decorators where a variable is being used. + */ + includeFromCurrentDocument: boolean; }; completion: { enabled: boolean; @@ -215,6 +232,13 @@ export interface LanguageSettings { */ triggerPropertyValueCompletion: boolean; completePropertyWithSemicolon?: boolean; + /** + * Compatibility setting for VS Code. + * + * By default the built-in SCSS server shows suggestions for variables, mixins and functions declared in the current document. + * To avoid duplicates, by default Some Sass (only in VS Code) will not suggest them. + */ + includeFromCurrentDocument: boolean; }; definition: { enabled: boolean; @@ -296,9 +320,9 @@ export interface WorkspaceConfiguration { } export interface LanguageServerConfiguration { - css: LanguageSettings; - sass: LanguageSettings; - scss: LanguageSettings; + css: LanguageConfiguration; + sass: LanguageConfiguration; + scss: LanguageConfiguration; editor: EditorConfiguration; workspace: WorkspaceConfiguration; logLevel: "trace" | "debug" | "info" | "warn" | "error" | "fatal" | "silent"; @@ -308,20 +332,19 @@ export interface EditorConfiguration { /** * Insert spaces rather than tabs. */ - insertSpaces?: boolean; + insertSpaces: boolean; /** * If {@link insertSpaces} is true this option determines the number of space characters is inserted per indent level. */ - indentSize?: number; + indentSize: number; /** * An older editor setting in VS Code. If both this and {@link indentSize} is set, only `indentSize` will be used. */ - tabSize?: number; + tabSize: number; /** * Controls the max number of color decorators that can be rendered in an editor at once. - * @default 500 */ - colorDecoratorsLimit?: number; + colorDecoratorsLimit: number; } export interface AliasSettings { diff --git a/packages/language-services/src/language-services.ts b/packages/language-services/src/language-services.ts index 850881c1..24089120 100644 --- a/packages/language-services/src/language-services.ts +++ b/packages/language-services/src/language-services.ts @@ -1,4 +1,7 @@ -import { getSassLanguageService } from "@somesass/vscode-css-languageservice"; +import { + getCSSLanguageService, + getSassLanguageService, +} from "@somesass/vscode-css-languageservice"; import { defaultConfiguration } from "./configuration"; import { CodeActions } from "./features/code-actions"; import { DoComplete } from "./features/do-complete"; @@ -65,18 +68,25 @@ class LanguageServiceImpl implements LanguageService { #selectionRanges: SelectionRanges; constructor(options: LanguageServiceOptions) { - const sassLs = getSassLanguageService({ + const vscodeLsOptions = { clientCapabilities: options.clientCapabilities, fileSystemProvider: mapFsProviders(options.fileSystemProvider), - }); + }; + const sassLs = getSassLanguageService(vscodeLsOptions); + const cache = new LanguageServerCache({ sassLs, ...options.languageModelCache, }); + const internal = { - sassLs, cache, + sassLs, + cssLs: getCSSLanguageService(vscodeLsOptions), + // The server code is the same as sassLs, but separate on syntax in case the user has different settings + scssLs: getSassLanguageService(vscodeLsOptions), }; + this.#cache = cache; this.#codeActions = new CodeActions(this, options, internal); this.#doComplete = new DoComplete(this, options, internal); diff --git a/vscode-extension/package.json b/vscode-extension/package.json index 14c5bf4b..6ba41f6f 100644 --- a/vscode-extension/package.json +++ b/vscode-extension/package.json @@ -669,7 +669,7 @@ "type": "boolean", "scope": "resource", "default": true, - "description": "Show references to MDN in CSS hovers." + "description": "Show references to MDN in CSS hovers, Sass documentation for Sass built-in modules and SassDoc for annotations." }, "somesass.scss.links.enabled": { "type": "boolean", @@ -957,7 +957,7 @@ "type": "boolean", "scope": "resource", "default": true, - "description": "Show references to MDN in CSS hovers." + "description": "Show references to MDN in CSS hovers, Sass documentation for Sass built-in modules and SassDoc for annotations." }, "somesass.sass.links.enabled": { "type": "boolean", From ff427fe947dacf13c1f038ef71b590ad6a21c9d6 Mon Sep 17 00:00:00 2001 From: William Killerud Date: Sun, 22 Sep 2024 14:06:31 +0200 Subject: [PATCH 05/23] chore: drop development build --- packages/language-server/README.md | 4 ---- packages/language-server/bin/some-sass-language-server | 7 +------ packages/language-server/package.json | 8 ++------ packages/language-server/rspack.config.js | 8 +++++--- vscode-extension/rspack.browser.config.js | 7 +------ vscode-extension/rspack.node.config.js | 7 +------ 6 files changed, 10 insertions(+), 31 deletions(-) diff --git a/packages/language-server/README.md b/packages/language-server/README.md index 81ca4928..dac4359f 100644 --- a/packages/language-server/README.md +++ b/packages/language-server/README.md @@ -29,10 +29,6 @@ Then start the language server like so: some-sass-language-server --stdio ``` -**Options** - -`--debug` – runs the development build of the language server, helpful to get more context if the server crashes - ### Workspace configuration See [how to configure a client](https://wkillerud.github.io/some-sass/language-server/configure-a-client.html) and the [documentation for the available settings](https://wkillerud.github.io/some-sass/user-guide/settings.html). diff --git a/packages/language-server/bin/some-sass-language-server b/packages/language-server/bin/some-sass-language-server index f44eb7ef..f2ffd244 100755 --- a/packages/language-server/bin/some-sass-language-server +++ b/packages/language-server/bin/some-sass-language-server @@ -1,9 +1,4 @@ #!/usr/bin/env node const path = require("path"); -const args = process.argv.slice(2); -if (args.includes("--debug")) { - require(path.join(__dirname, "..", "dist", "development", "node-server.js")); -} else { - require(path.join(__dirname, "..", "dist", "node-server.js")); -} +require(path.join(__dirname, "..", "dist", "node-server.js")); diff --git a/packages/language-server/package.json b/packages/language-server/package.json index 824a8d00..8c4a9d99 100644 --- a/packages/language-server/package.json +++ b/packages/language-server/package.json @@ -9,6 +9,7 @@ "lsp", "language-server-protocol" ], + "type": "commonjs", "engines": { "node": ">=20" }, @@ -31,18 +32,13 @@ "exports": { ".": { "browser": "./dist/browser-server.js", - "development": "./dist/development/node-server.js", "default": "./dist/node-server.js" - }, - "./development": { - "browser": "./dist/development/browser-server.js", - "default": "./dist/development/node-server.js" } }, "author": "William Killerud (https://www.williamkillerud.com/)", "license": "MIT", "scripts": { - "build": "tsc --noEmit && rspack", + "build": "rspack", "clean": "shx rm -rf dist node_modules", "test": "vitest", "coverage": "vitest run --coverage" diff --git a/packages/language-server/rspack.config.js b/packages/language-server/rspack.config.js index f16e9e01..3a5e23f0 100644 --- a/packages/language-server/rspack.config.js +++ b/packages/language-server/rspack.config.js @@ -79,6 +79,10 @@ function defineConfig(config, mode) { resolve: { extensions: [".ts", ".js"], }, + optimization: { + mangleExports: false, + minimize: true, + }, module: { rules: [ { @@ -96,7 +100,7 @@ function defineConfig(config, mode) { }, ], }, - devtool: false, + devtool: "cheap-source-map", }; /** @type RspackConfig */ @@ -114,8 +118,6 @@ function defineConfig(config, mode) { } module.exports = [ - defineConfig(nodeConfig, "development"), defineConfig(nodeConfig, "production"), - defineConfig(browserConfig, "development"), defineConfig(browserConfig, "production"), ]; diff --git a/vscode-extension/rspack.browser.config.js b/vscode-extension/rspack.browser.config.js index 1e780af6..c6079a7b 100644 --- a/vscode-extension/rspack.browser.config.js +++ b/vscode-extension/rspack.browser.config.js @@ -59,11 +59,6 @@ const config = { }; module.exports = (env, argv) => { - const baseFrom = - argv.mode === "development" - ? "../node_modules/some-sass-language-server/dist/development" - : "../node_modules/some-sass-language-server/dist/"; - config.plugins?.push( new rspack.ProvidePlugin({ process: "process/browser", @@ -71,7 +66,7 @@ module.exports = (env, argv) => { new rspack.CopyRspackPlugin({ patterns: [ { - from: `${baseFrom}/browser-server.*`, + from: "../node_modules/some-sass-language-server/dist/browser-server.*", to: "[name][ext]", }, ], diff --git a/vscode-extension/rspack.node.config.js b/vscode-extension/rspack.node.config.js index e310cb13..acd22dcd 100644 --- a/vscode-extension/rspack.node.config.js +++ b/vscode-extension/rspack.node.config.js @@ -45,16 +45,11 @@ const config = { }; module.exports = (env, argv) => { - const baseFrom = - argv.mode === "development" - ? "../node_modules/some-sass-language-server/dist/development" - : "../node_modules/some-sass-language-server/dist/"; - config.plugins?.push( new rspack.CopyRspackPlugin({ patterns: [ { - from: `${baseFrom}/node-server.*`, + from: "../node_modules/some-sass-language-server/dist/node-server.*", to: "[name][ext]", }, ], From 3b0ca4c50f75b63c1a80cda3f69af734de3ec584 Mon Sep 17 00:00:00 2001 From: William Killerud Date: Sun, 22 Sep 2024 14:19:34 +0200 Subject: [PATCH 06/23] chore: lodash bundled, not a dep --- package-lock.json | 6 ++---- packages/language-server/package.json | 6 ++---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index 987544ee..d440687a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22886,18 +22886,16 @@ "name": "some-sass-language-server", "version": "1.8.3", "license": "MIT", - "dependencies": { - "@types/lodash.merge": "4.6.9", - "lodash.merge": "4.6.2" - }, "bin": { "some-sass-language-server": "bin/some-sass-language-server" }, "devDependencies": { "@somesass/language-services": "1.7.1", + "@types/lodash.merge": "4.6.9", "@types/node": "20.16.5", "@vitest/coverage-v8": "2.0.5", "fast-glob": "3.3.2", + "lodash.merge": "4.6.2", "merge-options": "3.0.4", "path-browserify": "1.0.1", "process": "0.11.10", diff --git a/packages/language-server/package.json b/packages/language-server/package.json index 8c4a9d99..4b2894d8 100644 --- a/packages/language-server/package.json +++ b/packages/language-server/package.json @@ -45,9 +45,11 @@ }, "devDependencies": { "@somesass/language-services": "1.7.1", + "@types/lodash.merge": "4.6.9", "@types/node": "20.16.5", "@vitest/coverage-v8": "2.0.5", "fast-glob": "3.3.2", + "lodash.merge": "4.6.2", "merge-options": "3.0.4", "path-browserify": "1.0.1", "process": "0.11.10", @@ -58,9 +60,5 @@ "vscode-languageserver-textdocument": "1.0.12", "vscode-languageserver-types": "3.17.5", "vscode-uri": "3.0.8" - }, - "dependencies": { - "@types/lodash.merge": "4.6.9", - "lodash.merge": "4.6.2" } } From 627765e081e75c08ae3457e7a0c142d3c8cd7152 Mon Sep 17 00:00:00 2001 From: William Killerud Date: Sun, 22 Sep 2024 18:23:34 +0200 Subject: [PATCH 07/23] chore: config, build --- package-lock.json | 136 ++-- package.json | 2 +- packages/language-server/package.json | 11 +- .../language-server/rspack.browser.config.js | 65 ++ packages/language-server/rspack.config.js | 123 ---- .../language-server/rspack.node.config.js | 44 ++ packages/language-server/tsconfig.json | 3 +- .../__tests__/do-signature-help.test.ts | 6 +- .../src/features/do-hover.ts | 4 +- packages/language-services/tsconfig.json | 2 +- vscode-extension/package.json | 595 +++++++++--------- vscode-extension/rspack.browser.config.js | 3 +- vscode-extension/rspack.node.config.js | 3 +- vscode-extension/rspack.test-web.config.js | 3 +- .../workspace/.vscode/settings.json | 15 - .../test/e2e/defaults-scss/hover.test.js | 2 +- .../workspace/.vscode/settings.json | 15 - .../workspace/.vscode/settings.json | 3 +- 18 files changed, 511 insertions(+), 524 deletions(-) create mode 100644 packages/language-server/rspack.browser.config.js delete mode 100644 packages/language-server/rspack.config.js create mode 100644 packages/language-server/rspack.node.config.js delete mode 100644 vscode-extension/test/e2e/defaults-sass/workspace/.vscode/settings.json delete mode 100644 vscode-extension/test/e2e/defaults-scss/workspace/.vscode/settings.json diff --git a/package-lock.json b/package-lock.json index d440687a..b4499e3a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -43,7 +43,7 @@ "ts-loader": "9.5.1", "typescript": "5.5.4", "typescript-eslint": "8.4.0", - "vitest": "2.0.5" + "vitest": "2.1.1" } }, "node_modules/@adobe/css-tools": { @@ -6510,14 +6510,14 @@ } }, "node_modules/@vitest/expect": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-2.0.5.tgz", - "integrity": "sha512-yHZtwuP7JZivj65Gxoi8upUN2OzHTi3zVfjwdpu2WrvCZPLwsJ2Ey5ILIPccoW23dd/zQBlJ4/dhi7DWNyXCpA==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-2.1.1.tgz", + "integrity": "sha512-YeueunS0HiHiQxk+KEOnq/QMzlUuOzbU1Go+PgAsHvvv3tUkJPm9xWt+6ITNTlzsMXUjmgm5T+U7KBPK2qQV6w==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/spy": "2.0.5", - "@vitest/utils": "2.0.5", + "@vitest/spy": "2.1.1", + "@vitest/utils": "2.1.1", "chai": "^5.1.1", "tinyrainbow": "^1.2.0" }, @@ -6525,10 +6525,38 @@ "url": "https://opencollective.com/vitest" } }, + "node_modules/@vitest/mocker": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-2.1.1.tgz", + "integrity": "sha512-LNN5VwOEdJqCmJ/2XJBywB11DLlkbY0ooDJW3uRX5cZyYCrc4PI/ePX0iQhE3BiEGiQmK4GE7Q/PqCkkaiPnrA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "^2.1.0-beta.1", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.11" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@vitest/spy": "2.1.1", + "msw": "^2.3.5", + "vite": "^5.0.0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, "node_modules/@vitest/pretty-format": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-2.0.5.tgz", - "integrity": "sha512-h8k+1oWHfwTkyTkb9egzwNMfJAEx4veaPSnMeKbVSjp4euqGSbQlm5+6VHwTr7u4FJslVVsUG5nopCaAYdOmSQ==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-2.1.1.tgz", + "integrity": "sha512-SjxPFOtuINDUW8/UkElJYQSFtnWX7tMksSGW0vfjxMneFqxVr8YJ979QpMbDW7g+BIiq88RAGDjf7en6rvLPPQ==", "dev": true, "license": "MIT", "dependencies": { @@ -6539,13 +6567,13 @@ } }, "node_modules/@vitest/runner": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-2.0.5.tgz", - "integrity": "sha512-TfRfZa6Bkk9ky4tW0z20WKXFEwwvWhRY+84CnSEtq4+3ZvDlJyY32oNTJtM7AW9ihW90tX/1Q78cb6FjoAs+ig==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-2.1.1.tgz", + "integrity": "sha512-uTPuY6PWOYitIkLPidaY5L3t0JJITdGTSwBtwMjKzo5O6RCOEncz9PUN+0pDidX8kTHYjO0EwUIvhlGpnGpxmA==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/utils": "2.0.5", + "@vitest/utils": "2.1.1", "pathe": "^1.1.2" }, "funding": { @@ -6553,14 +6581,14 @@ } }, "node_modules/@vitest/snapshot": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-2.0.5.tgz", - "integrity": "sha512-SgCPUeDFLaM0mIUHfaArq8fD2WbaXG/zVXjRupthYfYGzc8ztbFbu6dUNOblBG7XLMR1kEhS/DNnfCZ2IhdDew==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-2.1.1.tgz", + "integrity": "sha512-BnSku1WFy7r4mm96ha2FzN99AZJgpZOWrAhtQfoxjUU5YMRpq1zmHRq7a5K9/NjqonebO7iVDla+VvZS8BOWMw==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "2.0.5", - "magic-string": "^0.30.10", + "@vitest/pretty-format": "2.1.1", + "magic-string": "^0.30.11", "pathe": "^1.1.2" }, "funding": { @@ -6568,9 +6596,9 @@ } }, "node_modules/@vitest/spy": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-2.0.5.tgz", - "integrity": "sha512-c/jdthAhvJdpfVuaexSrnawxZz6pywlTPe84LUB2m/4t3rl2fTo9NFGBG4oWgaD+FTgDDV8hJ/nibT7IfH3JfA==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-2.1.1.tgz", + "integrity": "sha512-ZM39BnZ9t/xZ/nF4UwRH5il0Sw93QnZXd9NAZGRpIgj0yvVwPpLd702s/Cx955rGaMlyBQkZJ2Ir7qyY48VZ+g==", "dev": true, "license": "MIT", "dependencies": { @@ -6581,14 +6609,13 @@ } }, "node_modules/@vitest/utils": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-2.0.5.tgz", - "integrity": "sha512-d8HKbqIcya+GR67mkZbrzhS5kKhtp8dQLcmRZLGTscGVg7yImT82cIrhtn2L8+VujWcy6KZweApgNmPsTAO/UQ==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-2.1.1.tgz", + "integrity": "sha512-Y6Q9TsI+qJ2CC0ZKj6VBb+T8UPz593N113nnUykqwANqhgf3QkZeHFlusgKLTqrnVHbj/XDKZcDHol+dxVT+rQ==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "2.0.5", - "estree-walker": "^3.0.3", + "@vitest/pretty-format": "2.1.1", "loupe": "^3.1.1", "tinyrainbow": "^1.2.0" }, @@ -20887,6 +20914,13 @@ "dev": true, "license": "MIT" }, + "node_modules/tinyexec": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.0.tgz", + "integrity": "sha512-tVGE0mVJPGb0chKhqmsoosjsS+qUnJVGJpZgsHYQcGoPlG3B51R3PouqTgEGH2Dc9jjFyOqOpix6ZHNMXp1FZg==", + "dev": true, + "license": "MIT" + }, "node_modules/tinypool": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.0.1.tgz", @@ -20908,9 +20942,9 @@ } }, "node_modules/tinyspy": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-3.0.0.tgz", - "integrity": "sha512-q5nmENpTHgiPVd1cJDDc9cVoYN5x4vCvwT3FMilvKPKneCBZAxn2YWQjDF0UMcE9k0Cay1gBiDfTMU0g+mPMQA==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-3.0.2.tgz", + "integrity": "sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==", "dev": true, "license": "MIT", "engines": { @@ -21683,16 +21717,15 @@ } }, "node_modules/vite-node": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-2.0.5.tgz", - "integrity": "sha512-LdsW4pxj0Ot69FAoXZ1yTnA9bjGohr2yNBU7QKRxpz8ITSkhuDl6h3zS/tvgz4qrNjeRnvrWeXQ8ZF7Um4W00Q==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-2.1.1.tgz", + "integrity": "sha512-N/mGckI1suG/5wQI35XeR9rsMsPqKXzq1CdUndzVstBj/HvyxxGctwnK6WX43NGt5L3Z5tcRf83g4TITKJhPrA==", "dev": true, "license": "MIT", "dependencies": { "cac": "^6.7.14", - "debug": "^4.3.5", + "debug": "^4.3.6", "pathe": "^1.1.2", - "tinyrainbow": "^1.2.0", "vite": "^5.0.0" }, "bin": { @@ -21706,30 +21739,30 @@ } }, "node_modules/vitest": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-2.0.5.tgz", - "integrity": "sha512-8GUxONfauuIdeSl5f9GTgVEpg5BTOlplET4WEDaeY2QBiN8wSm68vxN/tb5z405OwppfoCavnwXafiaYBC/xOA==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-2.1.1.tgz", + "integrity": "sha512-97We7/VC0e9X5zBVkvt7SGQMGrRtn3KtySFQG5fpaMlS+l62eeXRQO633AYhSTC3z7IMebnPPNjGXVGNRFlxBA==", "dev": true, "license": "MIT", "dependencies": { - "@ampproject/remapping": "^2.3.0", - "@vitest/expect": "2.0.5", - "@vitest/pretty-format": "^2.0.5", - "@vitest/runner": "2.0.5", - "@vitest/snapshot": "2.0.5", - "@vitest/spy": "2.0.5", - "@vitest/utils": "2.0.5", + "@vitest/expect": "2.1.1", + "@vitest/mocker": "2.1.1", + "@vitest/pretty-format": "^2.1.1", + "@vitest/runner": "2.1.1", + "@vitest/snapshot": "2.1.1", + "@vitest/spy": "2.1.1", + "@vitest/utils": "2.1.1", "chai": "^5.1.1", - "debug": "^4.3.5", - "execa": "^8.0.1", - "magic-string": "^0.30.10", + "debug": "^4.3.6", + "magic-string": "^0.30.11", "pathe": "^1.1.2", "std-env": "^3.7.0", - "tinybench": "^2.8.0", + "tinybench": "^2.9.0", + "tinyexec": "^0.3.0", "tinypool": "^1.0.0", "tinyrainbow": "^1.2.0", "vite": "^5.0.0", - "vite-node": "2.0.5", + "vite-node": "2.1.1", "why-is-node-running": "^2.3.0" }, "bin": { @@ -21744,8 +21777,8 @@ "peerDependencies": { "@edge-runtime/vm": "*", "@types/node": "^18.0.0 || >=20.0.0", - "@vitest/browser": "2.0.5", - "@vitest/ui": "2.0.5", + "@vitest/browser": "2.1.1", + "@vitest/ui": "2.1.1", "happy-dom": "*", "jsdom": "*" }, @@ -22902,6 +22935,7 @@ "shx": "0.3.4", "url": "0.11.4", "util": "0.12.5", + "vitest": "2.1.1", "vscode-languageserver": "9.0.1", "vscode-languageserver-textdocument": "1.0.12", "vscode-languageserver-types": "3.17.5", diff --git a/package.json b/package.json index 854448a9..16fa0aa6 100644 --- a/package.json +++ b/package.json @@ -64,6 +64,6 @@ "ts-loader": "9.5.1", "typescript": "5.5.4", "typescript-eslint": "8.4.0", - "vitest": "2.0.5" + "vitest": "2.1.1" } } diff --git a/packages/language-server/package.json b/packages/language-server/package.json index 4b2894d8..481248b8 100644 --- a/packages/language-server/package.json +++ b/packages/language-server/package.json @@ -38,7 +38,15 @@ "author": "William Killerud (https://www.williamkillerud.com/)", "license": "MIT", "scripts": { - "build": "rspack", + "prepublishOnly": "run-s build:production:*", + "prebuild": "tsc --noEmit", + "build": "run-s build:development:*", + "build:node": "rspack --config ./rspack.node.config.js", + "build:browser": "rspack --config ./rspack.browser.config.js", + "build:development:node": "npm run build:node -- --mode=development", + "build:development:browser": "npm run build:browser -- --mode=development", + "build:production:node": "npm run build:node -- --mode=production", + "build:production:browser": "npm run build:browser -- --mode=production", "clean": "shx rm -rf dist node_modules", "test": "vitest", "coverage": "vitest run --coverage" @@ -56,6 +64,7 @@ "shx": "0.3.4", "url": "0.11.4", "util": "0.12.5", + "vitest": "2.1.1", "vscode-languageserver": "9.0.1", "vscode-languageserver-textdocument": "1.0.12", "vscode-languageserver-types": "3.17.5", diff --git a/packages/language-server/rspack.browser.config.js b/packages/language-server/rspack.browser.config.js new file mode 100644 index 00000000..b65f8abe --- /dev/null +++ b/packages/language-server/rspack.browser.config.js @@ -0,0 +1,65 @@ +/* eslint-disable */ +const path = require("path"); +const rspack = require("@rspack/core"); + +/** @type {import('@rspack/core').Configuration} */ +const config = { + context: __dirname, + target: "webworker", + entry: { + "browser-server": "./src/browser-server.ts", + }, + output: { + libraryTarget: "var", + library: "serverExportVar", + filename: "[name].js", + path: path.join(__dirname, "dist"), + }, + module: { + rules: [ + { + test: /\.m?js/, + resolve: { + fullySpecified: false, + }, + }, + { + test: /\.ts$/, + exclude: [/[\\/]node_modules[\\/]/], + loader: "builtin:swc-loader", + options: { + jsc: { + parser: { + syntax: "typescript", + }, + externalHelpers: true, + }, + }, + }, + ], + }, + resolve: { + extensions: [".ts", ".js"], + mainFields: ["browser", "module", "main"], + fallback: { + events: require.resolve("events/"), + path: require.resolve("path-browserify"), + util: require.resolve("util/"), + url: require.resolve("url/"), + "fs/promises": false, + }, + }, + plugins: [ + new rspack.ProvidePlugin({ + process: "process/browser", + }), + ], + devtool: "cheap-source-map", +}; + +module.exports = (env, argv) => { + if (argv.mode === "development") { + config.devtool = "source-map"; + } + return config; +}; diff --git a/packages/language-server/rspack.config.js b/packages/language-server/rspack.config.js deleted file mode 100644 index 3a5e23f0..00000000 --- a/packages/language-server/rspack.config.js +++ /dev/null @@ -1,123 +0,0 @@ -// @ts-check -/* eslint-disable @typescript-eslint/no-var-requires */ - -const path = require("path"); -const merge = require("merge-options"); -const rspack = require("@rspack/core"); - -/** @typedef {import('@rspack/core').Configuration} RspackConfig **/ -/** @type RspackConfig */ -const nodeConfig = { - target: "node", - entry: { - "node-server": "./src/node-server.ts", - }, - output: { - libraryTarget: "commonjs2", - }, -}; - -/** @type RspackConfig */ -const browserConfig = { - context: __dirname, - target: "webworker", - entry: { - "browser-server": "./src/browser-server.ts", - }, - output: { - libraryTarget: "var", - library: "serverExportVar", - }, - resolve: { - mainFields: ["browser", "module", "main"], - fallback: { - events: require.resolve("events/"), - path: require.resolve("path-browserify"), - util: require.resolve("util/"), - url: require.resolve("url/"), - "fs/promises": false, - }, - }, - module: { - rules: [ - { - test: /\.m?js/, - resolve: { - fullySpecified: false, - }, - }, - { - test: /\.ts$/, - exclude: [/[\\/]node_modules[\\/]/], - loader: "builtin:swc-loader", - options: { - jsc: { - parser: { - syntax: "typescript", - }, - externalHelpers: true, - }, - }, - }, - ], - }, - plugins: [ - new rspack.ProvidePlugin({ - process: "process/browser", - }), - ], -}; - -function defineConfig(config, mode) { - /** @type RspackConfig */ - const baseConfig = { - mode, - output: { - filename: "[name].js", - path: path.join(__dirname, "dist"), - }, - resolve: { - extensions: [".ts", ".js"], - }, - optimization: { - mangleExports: false, - minimize: true, - }, - module: { - rules: [ - { - test: /\.ts$/, - exclude: [/[\\/]node_modules[\\/]/], - loader: "builtin:swc-loader", - options: { - jsc: { - parser: { - syntax: "typescript", - }, - externalHelpers: true, - }, - }, - }, - ], - }, - devtool: "cheap-source-map", - }; - - /** @type RspackConfig */ - const developmentConfig = { - devtool: "source-map", - output: { - path: path.join(__dirname, "dist", "development"), - }, - }; - - if (mode === "development") { - return merge(baseConfig, config, developmentConfig); - } - return merge(baseConfig, config); -} - -module.exports = [ - defineConfig(nodeConfig, "production"), - defineConfig(browserConfig, "production"), -]; diff --git a/packages/language-server/rspack.node.config.js b/packages/language-server/rspack.node.config.js new file mode 100644 index 00000000..a8c4892f --- /dev/null +++ b/packages/language-server/rspack.node.config.js @@ -0,0 +1,44 @@ +/* eslint-disable */ +const path = require("path"); +const rspack = require("@rspack/core"); + +/** @type {import('@rspack/core').Configuration} */ +const config = { + target: "node", + entry: { + "node-server": "./src/node-server.ts", + }, + output: { + filename: "[name].js", + path: path.join(__dirname, "dist"), + libraryTarget: "commonjs2", + }, + resolve: { + extensions: [".ts", ".js"], + }, + module: { + rules: [ + { + test: /\.ts$/, + exclude: [/[\\/]node_modules[\\/]/], + loader: "builtin:swc-loader", + options: { + jsc: { + parser: { + syntax: "typescript", + }, + externalHelpers: true, + }, + }, + }, + ], + }, + devtool: "cheap-source-map", +}; + +module.exports = (env, argv) => { + if (argv.mode === "development") { + config.devtool = "source-map"; + } + return config; +}; diff --git a/packages/language-server/tsconfig.json b/packages/language-server/tsconfig.json index e33c719f..9aa26efc 100644 --- a/packages/language-server/tsconfig.json +++ b/packages/language-server/tsconfig.json @@ -9,5 +9,6 @@ "strict": true, "allowSyntheticDefaultImports": true, "resolveJsonModule": true - } + }, + "exclude": ["**/*.test.ts", "vitest.config.mts"] } diff --git a/packages/language-services/src/features/__tests__/do-signature-help.test.ts b/packages/language-services/src/features/__tests__/do-signature-help.test.ts index b17eb18c..a078fc65 100644 --- a/packages/language-services/src/features/__tests__/do-signature-help.test.ts +++ b/packages/language-services/src/features/__tests__/do-signature-help.test.ts @@ -311,11 +311,7 @@ test("signature help when given more parameters than are supported", async () => }); const result = await ls.doSignatureHelp(document, Position.create(0, 18)); - assert.deepStrictEqual(result, { - signatures: [], - activeParameter: 0, - activeSignature: 0, - }); + assert.deepStrictEqual(result, null); }); test("is not confused by using a function as a parameter", async () => { diff --git a/packages/language-services/src/features/do-hover.ts b/packages/language-services/src/features/do-hover.ts index b8946b12..6e4e16ba 100644 --- a/packages/language-services/src/features/do-hover.ts +++ b/packages/language-services/src/features/do-hover.ts @@ -138,7 +138,7 @@ export class DoHover extends LanguageFeature { value: [ candidate.annotation, config.hover.references - ? `\n\n[SassDoc reference](http://sassdoc.com/annotations/#${candidate.annotation.slice( + ? `\n[SassDoc reference](http://sassdoc.com/annotations/#${candidate.annotation.slice( 1, )})` : "", @@ -264,7 +264,7 @@ export class DoHover extends LanguageFeature { value: [ description, config.hover.references - ? `\n\n[Sass reference](${reference}#${builtinName})` + ? `\n[Sass reference](${reference}#${builtinName})` : "", ] .join("\n") diff --git a/packages/language-services/tsconfig.json b/packages/language-services/tsconfig.json index 569a032c..de63c7b7 100644 --- a/packages/language-services/tsconfig.json +++ b/packages/language-services/tsconfig.json @@ -7,7 +7,7 @@ "moduleResolution": "node", "declaration": true, "rootDir": "src", - "allowSyntheticDefaultImports": true, + "esModuleInterop": true, "outDir": "dist", "strict": true }, diff --git a/vscode-extension/package.json b/vscode-extension/package.json index 6ba41f6f..df5508e6 100644 --- a/vscode-extension/package.json +++ b/vscode-extension/package.json @@ -63,204 +63,175 @@ ], "configuration": [ { - "title": "CSS", + "title": "SCSS", "properties": { - "somesass.css.customData": { - "type": "array", - "markdownDescription": "A list of relative file paths pointing to JSON files following the [custom data format](https://github.com/microsoft/vscode-css-languageservice/blob/master/docs/customData.md).\n\nSome Sass loads custom data on startup to enhance its CSS support for CSS custom properties (variables), at-rules, pseudo-classes, and pseudo-elements you specify in the JSON files.\n\nThe file paths are relative to workspace and only workspace folder settings are considered.", - "default": [], - "items": { - "type": "string" - }, - "scope": "resource" - }, - "somesass.css.codeAction.enabled": { + "somesass.scss.codeAction.enabled": { "type": "boolean", "scope": "resource", "default": true, "description": "Enables or disables all code actions." }, - "somesass.css.colors.enabled": { + "somesass.scss.colors.enabled": { "type": "boolean", "scope": "resource", "default": true, "description": "Enables or disables all color decorators." }, - "somesass.css.completion.enabled": { + "somesass.scss.colors.includeFromCurrentDocument": { + "type": "boolean", + "scope": "resource", + "default": false, + "description": "Compatibility setting for VS Code. By default the built-in SCSS server shows color decorators for variables declared in the current document. To avoid duplicates Some Sass will not show them unless you opt in." + }, + "somesass.scss.completion.enabled": { "type": "boolean", "scope": "resource", "default": true, "description": "Enables or disables all completions (IntelliSense)." }, - "somesass.css.completion.triggerPropertyValueCompletion": { + "somesass.scss.completion.includeFromCurrentDocument": { + "type": "boolean", + "default": false, + "description": "Compatibility setting for VS Code. By default the built-in SCSS server shows suggestions for variables, mixins and functions declared in the current document. To avoid duplicates Some Sass will not suggest them unless you opt in." + }, + "somesass.scss.completion.suggestFromUseOnly": { + "type": "boolean", + "default": false, + "description": "If your project uses the new module system with @use and @forward, you may want to only include suggestions from your used modules." + }, + "somesass.scss.completion.mixinStyle": { + "type": "string", + "default": "all", + "description": "Controls the style of suggestions for mixins and placeholders.", + "enum": ["all", "nobracket", "bracket"], + "enumItemLabels": ["All", "No brackets", "Only brackets"], + "enumDescriptions": [ + "Show all suggestions", + "Only show suggestions without brackets", + "Where brackets are suggested, omit duplicates without brackets" + ] + }, + "somesass.scss.completion.triggerPropertyValueCompletion": { "type": "boolean", "scope": "resource", "default": true, "description": "By default, Some Sass triggers property value completion after selecting a CSS property. Use this setting to disable this behavior." }, - "somesass.css.completion.completePropertyWithSemicolon": { + "somesass.scss.completion.completePropertyWithSemicolon": { "type": "boolean", "scope": "resource", "default": true, "description": "Insert semicolon at end of line when completing CSS properties." }, - "somesass.css.definition.enabled": { + "somesass.scss.definition.enabled": { "type": "boolean", "scope": "resource", "default": true, "description": "Enables or disables Go to Definition." }, - "somesass.css.diagnostics.enabled": { + "somesass.scss.diagnostics.enabled": { "type": "boolean", "scope": "resource", "default": true, "description": "Enables or disables all diagnostics (deprecation, errors and lint rules)." }, - "somesass.css.diagnostics.deprecation.enabled": { + "somesass.scss.diagnostics.deprecation.enabled": { "type": "boolean", "scope": "resource", "default": true, "description": "Enables or disables deprecation diagnostics (strike-through)." }, - "somesass.css.diagnostics.lint.enabled": { + "somesass.scss.diagnostics.lint.enabled": { "type": "boolean", "scope": "resource", - "default": true, + "default": false, "description": "Enables or disables all linting." }, - "somesass.css.diagnostics.lint.compatibleVendorPrefixes": { + "somesass.scss.diagnostics.lint.compatibleVendorPrefixes": { "type": "string", "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], + "enum": ["ignore", "warning", "error"], "default": "ignore", "description": "When using a vendor-specific prefix make sure to also include all other vendor-specific properties." }, - "somesass.css.diagnostics.lint.vendorPrefix": { + "somesass.scss.diagnostics.lint.vendorPrefix": { "type": "string", "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], + "enum": ["ignore", "warning", "error"], "default": "warning", "description": "When using a vendor-specific prefix, also include the standard property." }, - "somesass.css.diagnostics.lint.duplicateProperties": { + "somesass.scss.diagnostics.lint.duplicateProperties": { "type": "string", "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], + "enum": ["ignore", "warning", "error"], "default": "ignore", "description": "Do not use duplicate style definitions." }, - "somesass.css.diagnostics.lint.emptyRules": { + "somesass.scss.diagnostics.lint.emptyRules": { "type": "string", "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], + "enum": ["ignore", "warning", "error"], "default": "warning", "description": "Do not use empty rulesets." }, - "somesass.css.diagnostics.lint.importStatement": { + "somesass.scss.diagnostics.lint.importStatement": { "type": "string", "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], + "enum": ["ignore", "warning", "error"], "default": "ignore", "description": "Import statements can lead to sequential loading of CSS." }, - "somesass.css.diagnostics.lint.boxModel": { + "somesass.scss.diagnostics.lint.boxModel": { "type": "string", "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], + "enum": ["ignore", "warning", "error"], "default": "ignore", "markdownDescription": "Do not use `width` or `height` when using `padding` or `border`." }, - "somesass.css.diagnostics.lint.universalSelector": { + "somesass.scss.diagnostics.lint.universalSelector": { "type": "string", "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], + "enum": ["ignore", "warning", "error"], "default": "ignore", "markdownDescription": "The universal selector (`*`) is known to be slow." }, - "somesass.css.diagnostics.lint.zeroUnits": { + "somesass.scss.diagnostics.lint.zeroUnits": { "type": "string", "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], + "enum": ["ignore", "warning", "error"], "default": "ignore", "description": "No unit needed for zero." }, - "somesass.css.diagnostics.lint.fontFaceProperties": { + "somesass.scss.diagnostics.lint.fontFaceProperties": { "type": "string", "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], + "enum": ["ignore", "warning", "error"], "default": "warning", "markdownDescription": "`@font-face` rule must define `src` and `font-family` properties." }, - "somesass.css.diagnostics.lint.hexColorLength": { + "somesass.scss.diagnostics.lint.hexColorLength": { "type": "string", "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], + "enum": ["ignore", "warning", "error"], "default": "error", "description": "Hex colors must consist of 3, 4, 6 or 8 hex numbers." }, - "somesass.css.diagnostics.lint.argumentsInColorFunction": { + "somesass.scss.diagnostics.lint.argumentsInColorFunction": { "type": "string", "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], + "enum": ["ignore", "warning", "error"], "default": "error", "description": "Invalid number of parameters." }, - "somesass.css.diagnostics.lint.unknownProperties": { + "somesass.scss.diagnostics.lint.unknownProperties": { "type": "string", "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], + "enum": ["ignore", "warning", "error"], "default": "warning", "description": "Unknown vendor specific property." }, - "somesass.css.diagnostics.lint.validProperties": { + "somesass.scss.diagnostics.lint.validProperties": { "type": "array", "uniqueItems": true, "items": { @@ -270,144 +241,116 @@ "default": [], "description": "A list of properties that are not validated against the `unknownProperties` rule." }, - "somesass.css.diagnostics.lint.ieHack": { + "somesass.scss.diagnostics.lint.ieHack": { "type": "string", "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], + "enum": ["ignore", "warning", "error"], "default": "ignore", "description": "IE hacks are only necessary when supporting IE7 and older." }, - "somesass.css.diagnostics.lint.unknownVendorSpecificProperties": { + "somesass.scss.diagnostics.lint.unknownVendorSpecificProperties": { "type": "string", "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], + "enum": ["ignore", "warning", "error"], "default": "ignore", "description": "Unknown vendor specific property." }, - "somesass.css.diagnostics.lint.propertyIgnoredDueToDisplay": { + "somesass.scss.diagnostics.lint.propertyIgnoredDueToDisplay": { "type": "string", "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], + "enum": ["ignore", "warning", "error"], "default": "warning", "markdownDescription": "Property is ignored due to the display. E.g. with `display: inline`, the `width`, `height`, `margin-top`, `margin-bottom`, and `float` properties have no effect." }, - "somesass.css.diagnostics.lint.important": { + "somesass.scss.diagnostics.lint.important": { "type": "string", "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], + "enum": ["ignore", "warning", "error"], "default": "ignore", "markdownDescription": "Avoid using `!important`. It is an indication that the specificity of the entire CSS has gotten out of control and needs to be refactored." }, - "somesass.css.diagnostics.lint.float": { + "somesass.scss.diagnostics.lint.float": { "type": "string", "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], + "enum": ["ignore", "warning", "error"], "default": "ignore", "markdownDescription": "Avoid using `float`. Floats lead to fragile CSS that is easy to break if one aspect of the layout changes." }, - "somesass.css.diagnostics.lint.idSelector": { + "somesass.scss.diagnostics.lint.idSelector": { "type": "string", "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], + "enum": ["ignore", "warning", "error"], "default": "ignore", "description": "Selectors should not contain IDs because these rules are too tightly coupled with the HTML." }, - "somesass.css.diagnostics.lint.unknownAtRules": { + "somesass.scss.diagnostics.lint.unknownAtRules": { "type": "string", "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], + "enum": ["ignore", "warning", "error"], "default": "warning", "description": "Unknown at-rule." }, - "somesass.css.foldingRanges.enabled": { + "somesass.scss.foldingRanges.enabled": { "type": "boolean", "scope": "resource", - "default": true, + "default": false, "description": "Enable or disable folding ranges." }, - "somesass.css.highlights.enabled": { + "somesass.scss.highlights.enabled": { "type": "boolean", "scope": "resource", - "default": true, + "default": false, "description": "Enable or disable highlights." }, - "somesass.css.hover.enabled": { + "somesass.scss.hover.enabled": { "type": "boolean", "scope": "resource", "default": true, "description": "Enable or disable all hover information." }, - "somesass.css.hover.documentation": { + "somesass.scss.hover.documentation": { "type": "boolean", "scope": "resource", "default": true, "description": "Show property and value documentation in CSS hovers." }, - "somesass.css.hover.references": { + "somesass.scss.hover.references": { "type": "boolean", "scope": "resource", "default": true, - "description": "Show references to MDN in CSS hovers." + "description": "Show references to MDN in CSS hovers, Sass documentation for Sass built-in modules and SassDoc for annotations." }, - "somesass.css.links.enabled": { + "somesass.scss.links.enabled": { "type": "boolean", "scope": "resource", - "default": true, + "default": false, "description": "Enable or disable the link provider that lets you click an import and open the file." }, - "somesass.css.references.enabled": { + "somesass.scss.references.enabled": { "type": "boolean", "scope": "resource", "default": true, "description": "Enable or disable Find all references." }, - "somesass.css.rename.enabled": { + "somesass.scss.rename.enabled": { "type": "boolean", "scope": "resource", "default": true, "description": "Enable or disable Rename." }, - "somesass.css.selectionRanges.enabled": { + "somesass.scss.selectionRanges.enabled": { "type": "boolean", "scope": "resource", - "default": true, + "default": false, "description": "Enable or disable selection ranges." }, - "somesass.css.signatureHelp.enabled": { + "somesass.scss.signatureHelp.enabled": { "type": "boolean", "scope": "resource", "default": true, "description": "Enable or disable selection ranges." }, - "somesass.css.workspaceSymbol.enabled": { + "somesass.scss.workspaceSymbol.enabled": { "type": "boolean", "scope": "resource", "default": true, @@ -416,36 +359,27 @@ } }, { - "title": "SCSS", + "title": "Sass (Indented)", "properties": { - "somesass.scss.customData": { - "type": "array", - "markdownDescription": "A list of relative file paths pointing to JSON files following the [custom data format](https://github.com/microsoft/vscode-css-languageservice/blob/master/docs/customData.md).\n\nSome Sass loads custom data on startup to enhance its CSS support for CSS custom properties (variables), at-rules, pseudo-classes, and pseudo-elements you specify in the JSON files.\n\nThe file paths are relative to workspace and only workspace folder settings are considered.", - "default": [], - "items": { - "type": "string" - }, - "scope": "resource" - }, - "somesass.scss.codeAction.enabled": { + "somesass.sass.codeAction.enabled": { "type": "boolean", "scope": "resource", "default": true, "description": "Enables or disables all code actions." }, - "somesass.scss.colors.enabled": { + "somesass.sass.colors.enabled": { "type": "boolean", "scope": "resource", "default": true, "description": "Enables or disables all color decorators." }, - "somesass.scss.completion.enabled": { + "somesass.sass.completion.enabled": { "type": "boolean", "scope": "resource", "default": true, "description": "Enables or disables all completions (IntelliSense)." }, - "somesass.scss.completion.mixinStyle": { + "somesass.sass.completion.mixinStyle": { "type": "string", "default": "all", "description": "Controls the style of suggestions for mixins and placeholders.", @@ -457,132 +391,126 @@ "Where brackets are suggested, omit duplicates without brackets" ] }, - "somesass.scss.completion.suggestFromUseOnly": { + "somesass.sass.completion.suggestFromUseOnly": { "type": "boolean", "default": false, "description": "If your project uses the new module system with @use and @forward, you may want to only include suggestions from your used modules." }, - "somesass.scss.completion.triggerPropertyValueCompletion": { + "somesass.sass.completion.triggerPropertyValueCompletion": { "type": "boolean", "scope": "resource", "default": true, "description": "By default, Some Sass triggers property value completion after selecting a CSS property. Use this setting to disable this behavior." }, - "somesass.scss.completion.completePropertyWithSemicolon": { - "type": "boolean", - "scope": "resource", - "default": true, - "description": "Insert semicolon at end of line when completing CSS properties." - }, - "somesass.scss.definition.enabled": { + "somesass.sass.definition.enabled": { "type": "boolean", "scope": "resource", "default": true, "description": "Enables or disables Go to Definition." }, - "somesass.scss.diagnostics.enabled": { + "somesass.sass.diagnostics.enabled": { "type": "boolean", "scope": "resource", "default": true, "description": "Enables or disables all diagnostics (deprecation, errors and lint rules)." }, - "somesass.scss.diagnostics.deprecation.enabled": { + "somesass.sass.diagnostics.deprecation.enabled": { "type": "boolean", "scope": "resource", "default": true, "description": "Enables or disables deprecation diagnostics (strike-through)." }, - "somesass.scss.diagnostics.lint.enabled": { + "somesass.sass.diagnostics.lint.enabled": { "type": "boolean", "scope": "resource", "default": true, "description": "Enables or disables all linting." }, - "somesass.scss.diagnostics.lint.compatibleVendorPrefixes": { + "somesass.sass.diagnostics.lint.compatibleVendorPrefixes": { "type": "string", "scope": "resource", "enum": ["ignore", "warning", "error"], "default": "ignore", "description": "When using a vendor-specific prefix make sure to also include all other vendor-specific properties." }, - "somesass.scss.diagnostics.lint.vendorPrefix": { + "somesass.sass.diagnostics.lint.vendorPrefix": { "type": "string", "scope": "resource", "enum": ["ignore", "warning", "error"], "default": "warning", "description": "When using a vendor-specific prefix, also include the standard property." }, - "somesass.scss.diagnostics.lint.duplicateProperties": { + "somesass.sass.diagnostics.lint.duplicateProperties": { "type": "string", "scope": "resource", "enum": ["ignore", "warning", "error"], "default": "ignore", "description": "Do not use duplicate style definitions." }, - "somesass.scss.diagnostics.lint.emptyRules": { + "somesass.sass.diagnostics.lint.emptyRules": { "type": "string", "scope": "resource", "enum": ["ignore", "warning", "error"], "default": "warning", "description": "Do not use empty rulesets." }, - "somesass.scss.diagnostics.lint.importStatement": { + "somesass.sass.diagnostics.lint.importStatement": { "type": "string", "scope": "resource", "enum": ["ignore", "warning", "error"], "default": "ignore", "description": "Import statements can lead to sequential loading of CSS." }, - "somesass.scss.diagnostics.lint.boxModel": { + "somesass.sass.diagnostics.lint.boxModel": { "type": "string", "scope": "resource", "enum": ["ignore", "warning", "error"], "default": "ignore", "markdownDescription": "Do not use `width` or `height` when using `padding` or `border`." }, - "somesass.scss.diagnostics.lint.universalSelector": { + "somesass.sass.diagnostics.lint.universalSelector": { "type": "string", "scope": "resource", "enum": ["ignore", "warning", "error"], "default": "ignore", "markdownDescription": "The universal selector (`*`) is known to be slow." }, - "somesass.scss.diagnostics.lint.zeroUnits": { + "somesass.sass.diagnostics.lint.zeroUnits": { "type": "string", "scope": "resource", "enum": ["ignore", "warning", "error"], "default": "ignore", "description": "No unit needed for zero." }, - "somesass.scss.diagnostics.lint.fontFaceProperties": { + "somesass.sass.diagnostics.lint.fontFaceProperties": { "type": "string", "scope": "resource", "enum": ["ignore", "warning", "error"], "default": "warning", "markdownDescription": "`@font-face` rule must define `src` and `font-family` properties." }, - "somesass.scss.diagnostics.lint.hexColorLength": { + "somesass.sass.diagnostics.lint.hexColorLength": { "type": "string", "scope": "resource", "enum": ["ignore", "warning", "error"], "default": "error", "description": "Hex colors must consist of 3, 4, 6 or 8 hex numbers." }, - "somesass.scss.diagnostics.lint.argumentsInColorFunction": { + "somesass.sass.diagnostics.lint.argumentsInColorFunction": { "type": "string", "scope": "resource", "enum": ["ignore", "warning", "error"], "default": "error", "description": "Invalid number of parameters." }, - "somesass.scss.diagnostics.lint.unknownProperties": { + "somesass.sass.diagnostics.lint.unknownProperties": { "type": "string", "scope": "resource", "enum": ["ignore", "warning", "error"], "default": "warning", "description": "Unknown vendor specific property." }, - "somesass.scss.diagnostics.lint.validProperties": { + "somesass.sass.diagnostics.lint.validProperties": { "type": "array", "uniqueItems": true, "items": { @@ -592,116 +520,116 @@ "default": [], "description": "A list of properties that are not validated against the `unknownProperties` rule." }, - "somesass.scss.diagnostics.lint.ieHack": { + "somesass.sass.diagnostics.lint.ieHack": { "type": "string", "scope": "resource", "enum": ["ignore", "warning", "error"], "default": "ignore", "description": "IE hacks are only necessary when supporting IE7 and older." }, - "somesass.scss.diagnostics.lint.unknownVendorSpecificProperties": { + "somesass.sass.diagnostics.lint.unknownVendorSpecificProperties": { "type": "string", "scope": "resource", "enum": ["ignore", "warning", "error"], "default": "ignore", "description": "Unknown vendor specific property." }, - "somesass.scss.diagnostics.lint.propertyIgnoredDueToDisplay": { + "somesass.sass.diagnostics.lint.propertyIgnoredDueToDisplay": { "type": "string", "scope": "resource", "enum": ["ignore", "warning", "error"], "default": "warning", "markdownDescription": "Property is ignored due to the display. E.g. with `display: inline`, the `width`, `height`, `margin-top`, `margin-bottom`, and `float` properties have no effect." }, - "somesass.scss.diagnostics.lint.important": { + "somesass.sass.diagnostics.lint.important": { "type": "string", "scope": "resource", "enum": ["ignore", "warning", "error"], "default": "ignore", "markdownDescription": "Avoid using `!important`. It is an indication that the specificity of the entire CSS has gotten out of control and needs to be refactored." }, - "somesass.scss.diagnostics.lint.float": { + "somesass.sass.diagnostics.lint.float": { "type": "string", "scope": "resource", "enum": ["ignore", "warning", "error"], "default": "ignore", "markdownDescription": "Avoid using `float`. Floats lead to fragile CSS that is easy to break if one aspect of the layout changes." }, - "somesass.scss.diagnostics.lint.idSelector": { + "somesass.sass.diagnostics.lint.idSelector": { "type": "string", "scope": "resource", "enum": ["ignore", "warning", "error"], "default": "ignore", "description": "Selectors should not contain IDs because these rules are too tightly coupled with the HTML." }, - "somesass.scss.diagnostics.lint.unknownAtRules": { + "somesass.sass.diagnostics.lint.unknownAtRules": { "type": "string", "scope": "resource", "enum": ["ignore", "warning", "error"], "default": "warning", "description": "Unknown at-rule." }, - "somesass.scss.foldingRanges.enabled": { + "somesass.sass.foldingRanges.enabled": { "type": "boolean", "scope": "resource", "default": true, "description": "Enable or disable folding ranges." }, - "somesass.scss.highlights.enabled": { + "somesass.sass.highlights.enabled": { "type": "boolean", "scope": "resource", "default": true, "description": "Enable or disable highlights." }, - "somesass.scss.hover.enabled": { + "somesass.sass.hover.enabled": { "type": "boolean", "scope": "resource", "default": true, "description": "Enable or disable all hover information." }, - "somesass.scss.hover.documentation": { + "somesass.sass.hover.documentation": { "type": "boolean", "scope": "resource", "default": true, "description": "Show property and value documentation in CSS hovers." }, - "somesass.scss.hover.references": { + "somesass.sass.hover.references": { "type": "boolean", "scope": "resource", "default": true, "description": "Show references to MDN in CSS hovers, Sass documentation for Sass built-in modules and SassDoc for annotations." }, - "somesass.scss.links.enabled": { + "somesass.sass.links.enabled": { "type": "boolean", "scope": "resource", "default": true, "description": "Enable or disable the link provider that lets you click an import and open the file." }, - "somesass.scss.references.enabled": { + "somesass.sass.references.enabled": { "type": "boolean", "scope": "resource", "default": true, "description": "Enable or disable Find all references." }, - "somesass.scss.rename.enabled": { + "somesass.sass.rename.enabled": { "type": "boolean", "scope": "resource", "default": true, "description": "Enable or disable Rename." }, - "somesass.scss.selectionRanges.enabled": { + "somesass.sass.selectionRanges.enabled": { "type": "boolean", "scope": "resource", "default": true, "description": "Enable or disable selection ranges." }, - "somesass.scss.signatureHelp.enabled": { + "somesass.sass.signatureHelp.enabled": { "type": "boolean", "scope": "resource", "default": true, "description": "Enable or disable selection ranges." }, - "somesass.scss.workspaceSymbol.enabled": { + "somesass.sass.workspaceSymbol.enabled": { "type": "boolean", "scope": "resource", "default": true, @@ -710,9 +638,9 @@ } }, { - "title": "Sass (Indented)", + "title": "CSS", "properties": { - "somesass.sass.customData": { + "somesass.css.customData": { "type": "array", "markdownDescription": "A list of relative file paths pointing to JSON files following the [custom data format](https://github.com/microsoft/vscode-css-languageservice/blob/master/docs/customData.md).\n\nSome Sass loads custom data on startup to enhance its CSS support for CSS custom properties (variables), at-rules, pseudo-classes, and pseudo-elements you specify in the JSON files.\n\nThe file paths are relative to workspace and only workspace folder settings are considered.", "default": [], @@ -721,156 +649,193 @@ }, "scope": "resource" }, - "somesass.sass.codeAction.enabled": { + "somesass.css.codeAction.enabled": { "type": "boolean", "scope": "resource", - "default": true, + "default": false, "description": "Enables or disables all code actions." }, - "somesass.sass.colors.enabled": { + "somesass.css.colors.enabled": { "type": "boolean", "scope": "resource", - "default": true, + "default": false, "description": "Enables or disables all color decorators." }, - "somesass.sass.completion.enabled": { + "somesass.css.completion.enabled": { "type": "boolean", "scope": "resource", - "default": true, - "description": "Enables or disables all completions (IntelliSense)." - }, - "somesass.sass.completion.mixinStyle": { - "type": "string", - "default": "all", - "description": "Controls the style of suggestions for mixins and placeholders.", - "enum": ["all", "nobracket", "bracket"], - "enumItemLabels": ["All", "No brackets", "Only brackets"], - "enumDescriptions": [ - "Show all suggestions", - "Only show suggestions without brackets", - "Where brackets are suggested, omit duplicates without brackets" - ] - }, - "somesass.sass.completion.suggestFromUseOnly": { - "type": "boolean", "default": false, - "description": "If your project uses the new module system with @use and @forward, you may want to only include suggestions from your used modules." + "description": "Enables or disables all completions (IntelliSense)." }, - "somesass.sass.completion.triggerPropertyValueCompletion": { + "somesass.css.completion.triggerPropertyValueCompletion": { "type": "boolean", "scope": "resource", "default": true, "description": "By default, Some Sass triggers property value completion after selecting a CSS property. Use this setting to disable this behavior." }, - "somesass.sass.definition.enabled": { + "somesass.css.completion.completePropertyWithSemicolon": { "type": "boolean", "scope": "resource", "default": true, + "description": "Insert semicolon at end of line when completing CSS properties." + }, + "somesass.css.definition.enabled": { + "type": "boolean", + "scope": "resource", + "default": false, "description": "Enables or disables Go to Definition." }, - "somesass.sass.diagnostics.enabled": { + "somesass.css.diagnostics.enabled": { "type": "boolean", "scope": "resource", - "default": true, + "default": false, "description": "Enables or disables all diagnostics (deprecation, errors and lint rules)." }, - "somesass.sass.diagnostics.deprecation.enabled": { + "somesass.css.diagnostics.deprecation.enabled": { "type": "boolean", "scope": "resource", "default": true, "description": "Enables or disables deprecation diagnostics (strike-through)." }, - "somesass.sass.diagnostics.lint.enabled": { + "somesass.css.diagnostics.lint.enabled": { "type": "boolean", "scope": "resource", "default": true, "description": "Enables or disables all linting." }, - "somesass.sass.diagnostics.lint.compatibleVendorPrefixes": { + "somesass.css.diagnostics.lint.compatibleVendorPrefixes": { "type": "string", "scope": "resource", - "enum": ["ignore", "warning", "error"], + "enum": [ + "ignore", + "warning", + "error" + ], "default": "ignore", "description": "When using a vendor-specific prefix make sure to also include all other vendor-specific properties." }, - "somesass.sass.diagnostics.lint.vendorPrefix": { + "somesass.css.diagnostics.lint.vendorPrefix": { "type": "string", "scope": "resource", - "enum": ["ignore", "warning", "error"], + "enum": [ + "ignore", + "warning", + "error" + ], "default": "warning", "description": "When using a vendor-specific prefix, also include the standard property." }, - "somesass.sass.diagnostics.lint.duplicateProperties": { + "somesass.css.diagnostics.lint.duplicateProperties": { "type": "string", "scope": "resource", - "enum": ["ignore", "warning", "error"], + "enum": [ + "ignore", + "warning", + "error" + ], "default": "ignore", "description": "Do not use duplicate style definitions." }, - "somesass.sass.diagnostics.lint.emptyRules": { + "somesass.css.diagnostics.lint.emptyRules": { "type": "string", "scope": "resource", - "enum": ["ignore", "warning", "error"], + "enum": [ + "ignore", + "warning", + "error" + ], "default": "warning", "description": "Do not use empty rulesets." }, - "somesass.sass.diagnostics.lint.importStatement": { + "somesass.css.diagnostics.lint.importStatement": { "type": "string", "scope": "resource", - "enum": ["ignore", "warning", "error"], + "enum": [ + "ignore", + "warning", + "error" + ], "default": "ignore", "description": "Import statements can lead to sequential loading of CSS." }, - "somesass.sass.diagnostics.lint.boxModel": { + "somesass.css.diagnostics.lint.boxModel": { "type": "string", "scope": "resource", - "enum": ["ignore", "warning", "error"], + "enum": [ + "ignore", + "warning", + "error" + ], "default": "ignore", "markdownDescription": "Do not use `width` or `height` when using `padding` or `border`." }, - "somesass.sass.diagnostics.lint.universalSelector": { + "somesass.css.diagnostics.lint.universalSelector": { "type": "string", "scope": "resource", - "enum": ["ignore", "warning", "error"], + "enum": [ + "ignore", + "warning", + "error" + ], "default": "ignore", "markdownDescription": "The universal selector (`*`) is known to be slow." }, - "somesass.sass.diagnostics.lint.zeroUnits": { + "somesass.css.diagnostics.lint.zeroUnits": { "type": "string", "scope": "resource", - "enum": ["ignore", "warning", "error"], + "enum": [ + "ignore", + "warning", + "error" + ], "default": "ignore", "description": "No unit needed for zero." }, - "somesass.sass.diagnostics.lint.fontFaceProperties": { + "somesass.css.diagnostics.lint.fontFaceProperties": { "type": "string", "scope": "resource", - "enum": ["ignore", "warning", "error"], + "enum": [ + "ignore", + "warning", + "error" + ], "default": "warning", "markdownDescription": "`@font-face` rule must define `src` and `font-family` properties." }, - "somesass.sass.diagnostics.lint.hexColorLength": { + "somesass.css.diagnostics.lint.hexColorLength": { "type": "string", "scope": "resource", - "enum": ["ignore", "warning", "error"], + "enum": [ + "ignore", + "warning", + "error" + ], "default": "error", "description": "Hex colors must consist of 3, 4, 6 or 8 hex numbers." }, - "somesass.sass.diagnostics.lint.argumentsInColorFunction": { + "somesass.css.diagnostics.lint.argumentsInColorFunction": { "type": "string", "scope": "resource", - "enum": ["ignore", "warning", "error"], + "enum": [ + "ignore", + "warning", + "error" + ], "default": "error", "description": "Invalid number of parameters." }, - "somesass.sass.diagnostics.lint.unknownProperties": { + "somesass.css.diagnostics.lint.unknownProperties": { "type": "string", "scope": "resource", - "enum": ["ignore", "warning", "error"], + "enum": [ + "ignore", + "warning", + "error" + ], "default": "warning", "description": "Unknown vendor specific property." }, - "somesass.sass.diagnostics.lint.validProperties": { + "somesass.css.diagnostics.lint.validProperties": { "type": "array", "uniqueItems": true, "items": { @@ -880,119 +845,147 @@ "default": [], "description": "A list of properties that are not validated against the `unknownProperties` rule." }, - "somesass.sass.diagnostics.lint.ieHack": { + "somesass.css.diagnostics.lint.ieHack": { "type": "string", "scope": "resource", - "enum": ["ignore", "warning", "error"], + "enum": [ + "ignore", + "warning", + "error" + ], "default": "ignore", "description": "IE hacks are only necessary when supporting IE7 and older." }, - "somesass.sass.diagnostics.lint.unknownVendorSpecificProperties": { + "somesass.css.diagnostics.lint.unknownVendorSpecificProperties": { "type": "string", "scope": "resource", - "enum": ["ignore", "warning", "error"], + "enum": [ + "ignore", + "warning", + "error" + ], "default": "ignore", "description": "Unknown vendor specific property." }, - "somesass.sass.diagnostics.lint.propertyIgnoredDueToDisplay": { + "somesass.css.diagnostics.lint.propertyIgnoredDueToDisplay": { "type": "string", "scope": "resource", - "enum": ["ignore", "warning", "error"], + "enum": [ + "ignore", + "warning", + "error" + ], "default": "warning", "markdownDescription": "Property is ignored due to the display. E.g. with `display: inline`, the `width`, `height`, `margin-top`, `margin-bottom`, and `float` properties have no effect." }, - "somesass.sass.diagnostics.lint.important": { + "somesass.css.diagnostics.lint.important": { "type": "string", "scope": "resource", - "enum": ["ignore", "warning", "error"], + "enum": [ + "ignore", + "warning", + "error" + ], "default": "ignore", "markdownDescription": "Avoid using `!important`. It is an indication that the specificity of the entire CSS has gotten out of control and needs to be refactored." }, - "somesass.sass.diagnostics.lint.float": { + "somesass.css.diagnostics.lint.float": { "type": "string", "scope": "resource", - "enum": ["ignore", "warning", "error"], + "enum": [ + "ignore", + "warning", + "error" + ], "default": "ignore", "markdownDescription": "Avoid using `float`. Floats lead to fragile CSS that is easy to break if one aspect of the layout changes." }, - "somesass.sass.diagnostics.lint.idSelector": { + "somesass.css.diagnostics.lint.idSelector": { "type": "string", "scope": "resource", - "enum": ["ignore", "warning", "error"], + "enum": [ + "ignore", + "warning", + "error" + ], "default": "ignore", "description": "Selectors should not contain IDs because these rules are too tightly coupled with the HTML." }, - "somesass.sass.diagnostics.lint.unknownAtRules": { + "somesass.css.diagnostics.lint.unknownAtRules": { "type": "string", "scope": "resource", - "enum": ["ignore", "warning", "error"], + "enum": [ + "ignore", + "warning", + "error" + ], "default": "warning", "description": "Unknown at-rule." }, - "somesass.sass.foldingRanges.enabled": { + "somesass.css.foldingRanges.enabled": { "type": "boolean", "scope": "resource", - "default": true, + "default": false, "description": "Enable or disable folding ranges." }, - "somesass.sass.highlights.enabled": { + "somesass.css.highlights.enabled": { "type": "boolean", "scope": "resource", - "default": true, + "default": false, "description": "Enable or disable highlights." }, - "somesass.sass.hover.enabled": { + "somesass.css.hover.enabled": { "type": "boolean", "scope": "resource", - "default": true, + "default": false, "description": "Enable or disable all hover information." }, - "somesass.sass.hover.documentation": { + "somesass.css.hover.documentation": { "type": "boolean", "scope": "resource", - "default": true, + "default": false, "description": "Show property and value documentation in CSS hovers." }, - "somesass.sass.hover.references": { + "somesass.css.hover.references": { "type": "boolean", "scope": "resource", - "default": true, - "description": "Show references to MDN in CSS hovers, Sass documentation for Sass built-in modules and SassDoc for annotations." + "default": false, + "description": "Show references to MDN in CSS hovers." }, - "somesass.sass.links.enabled": { + "somesass.css.links.enabled": { "type": "boolean", "scope": "resource", - "default": true, + "default": false, "description": "Enable or disable the link provider that lets you click an import and open the file." }, - "somesass.sass.references.enabled": { + "somesass.css.references.enabled": { "type": "boolean", "scope": "resource", - "default": true, + "default": false, "description": "Enable or disable Find all references." }, - "somesass.sass.rename.enabled": { + "somesass.css.rename.enabled": { "type": "boolean", "scope": "resource", - "default": true, + "default": false, "description": "Enable or disable Rename." }, - "somesass.sass.selectionRanges.enabled": { + "somesass.css.selectionRanges.enabled": { "type": "boolean", "scope": "resource", - "default": true, + "default": false, "description": "Enable or disable selection ranges." }, - "somesass.sass.signatureHelp.enabled": { + "somesass.css.signatureHelp.enabled": { "type": "boolean", "scope": "resource", - "default": true, + "default": false, "description": "Enable or disable selection ranges." }, - "somesass.sass.workspaceSymbol.enabled": { + "somesass.css.workspaceSymbol.enabled": { "type": "boolean", "scope": "resource", - "default": true, + "default": false, "description": "Enable or disable selection ranges." } } diff --git a/vscode-extension/rspack.browser.config.js b/vscode-extension/rspack.browser.config.js index c6079a7b..780e87c0 100644 --- a/vscode-extension/rspack.browser.config.js +++ b/vscode-extension/rspack.browser.config.js @@ -1,5 +1,4 @@ -// @ts-check -/* eslint-disable @typescript-eslint/no-var-requires */ +/* eslint-disable */ const path = require("path"); const rspack = require("@rspack/core"); diff --git a/vscode-extension/rspack.node.config.js b/vscode-extension/rspack.node.config.js index acd22dcd..d4caeae9 100644 --- a/vscode-extension/rspack.node.config.js +++ b/vscode-extension/rspack.node.config.js @@ -1,5 +1,4 @@ -// @ts-check -/* eslint-disable @typescript-eslint/no-var-requires */ +/* eslint-disable */ const path = require("path"); const rspack = require("@rspack/core"); diff --git a/vscode-extension/rspack.test-web.config.js b/vscode-extension/rspack.test-web.config.js index a50d87f1..4ceb7dc2 100644 --- a/vscode-extension/rspack.test-web.config.js +++ b/vscode-extension/rspack.test-web.config.js @@ -1,5 +1,4 @@ -// @ts-check -/* eslint-disable @typescript-eslint/no-var-requires */ +/* eslint-disable */ const path = require("path"); const rspack = require("@rspack/core"); diff --git a/vscode-extension/test/e2e/defaults-sass/workspace/.vscode/settings.json b/vscode-extension/test/e2e/defaults-sass/workspace/.vscode/settings.json deleted file mode 100644 index f680ec48..00000000 --- a/vscode-extension/test/e2e/defaults-sass/workspace/.vscode/settings.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "somesass.loadPaths": [], - "somesass.scannerDepth": 30, - "somesass.scannerExclude": [ - "**/.git/**", - "**/node_modules/**", - "**/bower_components/**" - ], - "somesass.scanImportedFiles": true, - "somesass.suggestAllFromOpenDocument": false, - "somesass.suggestFromUseOnly": false, - "somesass.suggestionStyle": "all", - "somesass.suggestFunctionsInStringContextAfterSymbols": " (+-*%", - "somesass.triggerPropertyValueCompletion": true, -} diff --git a/vscode-extension/test/e2e/defaults-scss/hover.test.js b/vscode-extension/test/e2e/defaults-scss/hover.test.js index 259d980c..bc05de6f 100644 --- a/vscode-extension/test/e2e/defaults-scss/hover.test.js +++ b/vscode-extension/test/e2e/defaults-scss/hover.test.js @@ -77,7 +77,7 @@ test("shows hover for SassDoc annotations", async () => { // Prefixed symbols are shown with their original names const expectedContents = { contents: [ - "@type\n____\n[SassDoc reference](http://sassdoc.com/annotations/#type)", + "@type\n\n[SassDoc reference](http://sassdoc.com/annotations/#type)", ], }; diff --git a/vscode-extension/test/e2e/defaults-scss/workspace/.vscode/settings.json b/vscode-extension/test/e2e/defaults-scss/workspace/.vscode/settings.json deleted file mode 100644 index f680ec48..00000000 --- a/vscode-extension/test/e2e/defaults-scss/workspace/.vscode/settings.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "somesass.loadPaths": [], - "somesass.scannerDepth": 30, - "somesass.scannerExclude": [ - "**/.git/**", - "**/node_modules/**", - "**/bower_components/**" - ], - "somesass.scanImportedFiles": true, - "somesass.suggestAllFromOpenDocument": false, - "somesass.suggestFromUseOnly": false, - "somesass.suggestionStyle": "all", - "somesass.suggestFunctionsInStringContextAfterSymbols": " (+-*%", - "somesass.triggerPropertyValueCompletion": true, -} diff --git a/vscode-extension/test/e2e/suggest-from-use-only/workspace/.vscode/settings.json b/vscode-extension/test/e2e/suggest-from-use-only/workspace/.vscode/settings.json index e0ca07df..9fb70d6e 100644 --- a/vscode-extension/test/e2e/suggest-from-use-only/workspace/.vscode/settings.json +++ b/vscode-extension/test/e2e/suggest-from-use-only/workspace/.vscode/settings.json @@ -1,3 +1,4 @@ { - "somesass.suggestFromUseOnly": true + "somesass.scss.completion.suggestFromUseOnly": true, + "somesass.sass.completion.suggestFromUseOnly": true } From c0b663af40269c98bc490fae982125cc7aef0b9d Mon Sep 17 00:00:00 2001 From: William Killerud Date: Sun, 22 Sep 2024 18:44:01 +0200 Subject: [PATCH 08/23] feat: cli --- .../bin/some-sass-language-server | 24 +++++++++++++++++++ packages/language-server/src/logger.ts | 12 +++++++--- 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/packages/language-server/bin/some-sass-language-server b/packages/language-server/bin/some-sass-language-server index f2ffd244..04932a4b 100755 --- a/packages/language-server/bin/some-sass-language-server +++ b/packages/language-server/bin/some-sass-language-server @@ -1,4 +1,28 @@ #!/usr/bin/env node const path = require("path"); +const fs = require("fs"); + +const args = process.argv; + +if (args.includes("--version") || args.includes("-v") || args.includes("-V")) { + try { + const pkg = fs.readFileSync(path.join(__dirname, "..", "package.json"), "utf-8"); + const json = JSON.parse(pkg); + if (!json.version) { + throw new Error(); + } + console.info(json.version); + } catch (e) { + console.info("Something went wrong reading the current version number."); + } + return; +} + +if (args.includes("--help") || args.includes("-h")) { + console.info(`some-sass-language-server <--stdio|--node-ipc|--socket={number}> [--loglevel ] + +For documentation, visit https://wkillerud.github.io/some-sass/language-server/getting-started.html`); + return; +} require(path.join(__dirname, "..", "dist", "node-server.js")); diff --git a/packages/language-server/src/logger.ts b/packages/language-server/src/logger.ts index 538abdc7..97886a7e 100644 --- a/packages/language-server/src/logger.ts +++ b/packages/language-server/src/logger.ts @@ -29,15 +29,15 @@ function levelToRank(level: string): number { return error; case "warn": return warn; - case "info": - return info; case "debug": return debug; case "trace": return trace; case "silent": - default: return silent; + case "info": + default: + return info; } } @@ -47,6 +47,12 @@ class LoggerImpl implements Logger { constructor(connection: Connection) { this.#connection = connection; + try { + const levelArg = process.argv.indexOf("--loglevel"); + if (levelArg !== -1) { + this.#level = levelToRank(process.argv[levelArg + 1]); + } + } catch {} } setLogLevel(level: string): void { From 42d83062ac812aaa4fa34dcfbb98472a2dfe2dc0 Mon Sep 17 00:00:00 2001 From: William Killerud Date: Sun, 22 Sep 2024 19:32:54 +0200 Subject: [PATCH 09/23] docs: new settings --- docs/src/README.md | 6 +- docs/src/images/usage/settings-built-in.png | Bin 0 -> 63121 bytes .../src/language-server/configure-a-client.md | 10 +- docs/src/language-server/existing-clients.md | 2 +- docs/src/language-server/getting-started.md | 18 +- docs/src/language-server/helix.md | 16 +- docs/src/user-guide/settings.md | 256 +- packages/language-server/src/server.ts | 4 +- vscode-extension/package.json | 2287 +++++++++-------- 9 files changed, 1439 insertions(+), 1160 deletions(-) create mode 100644 docs/src/images/usage/settings-built-in.png diff --git a/docs/src/README.md b/docs/src/README.md index 18644fb5..f5599f86 100644 --- a/docs/src/README.md +++ b/docs/src/README.md @@ -8,7 +8,7 @@ Some features include: - Workspace-wide code navigation and refactoring, such as Rename Symbol. - Rich documentation through [SassDoc][sassdoc]. - Language features for [`%placeholders`][placeholder], both when using them and writing them. -- Support for both SCSS and intended [syntaxes]. +- Support for both SCSS and intended [syntaxes], as well as CSS. ![](./images/highlight-reel.gif) @@ -20,11 +20,11 @@ You can find the extension here: - On the [Open VSX Registry][openvsx]. - In the [Releases section on GitHub][ghreleases]. -See the User guide section to learn more about what the extension can do. +See the User guide section to learn more about what the extension can do, or jump into [Settings](./user-guide/settings.md). ## Some Sass Language Server -Some Sass is also a language server using the [Language Server Protocol (LSP)][lsp]. +Some Sass is also a language server using the [Language Server Protocol (LSP)][lsp]. It can be used for both SCSS, Sass (indented) and CSS. The language server is [published on npm][npm], and can be used with any editor that has an LSP client. See [Getting started](./language-server/getting-started.md) to learn more. diff --git a/docs/src/images/usage/settings-built-in.png b/docs/src/images/usage/settings-built-in.png new file mode 100644 index 0000000000000000000000000000000000000000..43e522c38b28cd368d3944849970dba2c31e8beb GIT binary patch literal 63121 zcmaI71yo$i(gq5I1W0gq4G>&|ThO2(!96gzyK8W_;4Z;oaCdhJ?tuXYch@($|GDSf zL*9F=&02d;_pYw4>aME(s&=rvoCMNq{MS%WP)L#=MZZ8ny@-JP^TEG@{DOP&xC;dZ zLt~<-YOg9Q!vnCgVAR#O(lcOmwy=h@LqYKgI$P@k%na;F^$d(mEcwZgn%c-oP4xN6 zRo=@o%UX*V7@K@_wKY(1l~V+`ngO`=$pr;o^EvZC2v``{>ykQKm|NQMIP;VLhb|A~ z{`b#J}8K+3_$%*aeG@S2p*R^O24i>UZtFGHUA$&Kypt$CQ3 zoSd8(o!A(yY>k*$xVgERm|2-vSs5Tb80=gu?RA|QEbS30hg3nMer|8_TUHu?YP{=4O$?!RB= zQT<|IXJzj2dw70w7Iti@KIvoQbDs$^$iD`I5 z_*?%5mJp@eLbRKlHzW!L^}5VNL_}UvM1)k{*2>Vt+yDydV{lvooT9=!cEDK64w;Y8 z_7`ERZ}u=B5%|wn%>CX9y<>re`GyqTfkya-oIDe8J2U7T09v0uh#dP>#|m{2{5#Os zj#qevf2W;!{%%L*B`hmFd_SyYDkqZo9 z!?QsP5sBER?aOqquZpW`2Vn*sAG1@Bo^G)BjWH*)Vqg&OMwBx`IirVC%D{T-M{HNq zJCer)vhyc!XLNxmQUlBF)EA_XI}hLq$XQ_g^3NtgZ9}owb*U#Ysr1U(enzvb0B02K z0MfX)GcU`&r`l@8i6z2UL9sD@0$Ke9Vf*uE-{U;dxBB2-jj%+rVF-3fl4k^Q8yeO3 zjoOHt;@U-U)1wGVrcVhyam)R3k<@ce8b0RUGIS0YsjxOE&|iVg;sr#gb>85M(x9R9 z2M>MU7?XV+nGB-W*3ZnX{m$HWgXkBA9JDeV3cw$z71xJMpA5qetaVjMVbvJGR8wd+eP^e_&8j(rQ0^A(*QrMT<% zm^=}g?W-Ucq4q24&K+w;O(-k>p*8hu_$5RgZ(x_xSC;$N#1hcoF{RLc__K;ld_F87 zRivkdrW7p|!O9wxuPG2$Bq)00@P<-6JX;{A!k9KWfJ2No+hZKfn1hF?1-a#=mXCm+ zrMQmps_<1#-}oxCei(i)EXZ3|FPkMe(OiZs4^bhI+kdBfsRL0@;A@4dSPAqD@}6&a z2NggCQ1|spFQxooPGBF(kub2U@Ry9WTs1Zjglk@v(7#?mJ6P&tSd>FlyeM(E4fQZrBnf7FnKlRU_U%XQLc zRm<3yil8)#sf*bgz!~^7kda&X)9|N^NyNG9j?|9fPRdW90X(ZKD`L_nYXhqRE4995 zf7lmzOpg#=e=#+Q!raunrJS&#F9royx2Xz#UY13(GXn7UY71Il{ zmBN)o6swf33LT3g7^8H4)qA&O8h4z$M4A5j9#A7+Gi`b|-8kJl{eG%t`sJ?M6jM>8 z={wVU)3;{dO;aavCvr`B%ud;*-;bHK=F*JgRx7G=AD~;vNXrgMNarf$Oy|7MvdARL zN&_zEK8OYuh|Efk(@gJ-<4sOaA&qP0EN0%xM`lXQO8;Ceo&9n3c~wYI$}840^s(Hh z5_*z!HnZbb1=;*~5A$;Q%yBK+OpxVwz3SP5SzL}<7CF{3_Eue(l)2<%nakvJhHm<5 zoqiqFrsH&)f$zG>1`A&otn!Svtm3U^^e$ba53}dQc(ENAZVfE~>876T_tE~T{y?!- zv6LPSX@GRC!H-P~y2`kOY1d-qV$K<=8O=S9nJbF|4rq=Pa~|{7g@yUo76cX&`}POx z`$hYQ6Pr67=M3j`m$+`6cNdpN`+~f4Jo-F@PS-;dQ!G6v<)C9d-=3u&IBXOy6W)qc z)70)!b}$z>Bdv!~osm94J;A7qr;KoxXO=7gjUvg$?_^4{)E(X2EZ`1K{_hrjd@Bb#ci>HPF&(U3wyh89`Xx0-cPLMleuL+hotbU{i(_>o4v zDm{@E%kxe1K(4aXFQf3Y!5W=JQr1%MByr{JrIwPoVm4wFT_9B2qURL!X|>`H#D39EU( zm+5e_$1}56!lWvg2u^b{eqkdr7_fRaawdJcY8AFHr<|!BrNVsddxe7J|I@#-(=CON zQ|T$_G5QKHW>`Gp#^FV`j;Te*!Nf?HzSOy5dq5qUG3b@NkX&A4lyXq(u~@Nqvv_o9 zJ#SMWTKl$6|Ep2^=++l?lg~SMT6B(D3{{N9E3!)r3k-}`OjgS|O-6U=10lH~ym6Ls zvPz~(Da8VZoBJ&dV-7li8dnFKi-Zgp!ByZ%nMv6+kYO=$Iiu#O$EW{=R@=B&AyA=| zuI$b=%1hq;-TC+r*QVRsF4Mre_w7j80nrrFk>|u0Tnh`v3#ya3bBgYWgcw9_H)cyf zr^q{^Bd!mE6V6|b^rvZd3$qOixbs~~C=11w@Fy3X7Ow0iQUHsEtHYkW&fDe;m;A#r+|z*{cY~)&bZMnxQywuP5@OUwN31%PIzmr z$JyPbGp&WGR6Ba5p*l3?y0tJ2lobk$Pz1F1!W$@?0dp^Y!1%t`H$0f9U?aCKD6>n>gvrxS@qK6ut;R$q-12>TBD~KWBVhghs%pi(@l#_M@;jJ z%hVJZSB_4tXLlnq6MijMb5pHaZj)IaNx^a5GN0)Uc^u8H8toZ4Q;JN7Q`IsO=h+OC zpkKfx>-q*JseT?dpDXX+S1wW2RW8#snJLvUDk>^k%4uv|Fkh%1n3|fZH_|?f3igH% z`uBxNP)tD6XllAT$2W5{~Ew=J8mIbRF*xfLmN!yg8WYL)FkYi#l-0-4k+HfLU z%<$%P({LpDeO`8UCqj2;Nuv}43_0n)uc+5PG3hOLiGv~Gd5w94ii#@gKB^X5o*b(s znw3-LGfr$(BgdZ&r;C&fAMbAvI<{Lv3iUGqqC&9GuGc9-l4IKZ!wc_=M?#c_O1w*$ zLj`ocDr-cpmwynE1s=8xr*hk+e$}iUJ_MF1&Y9@ySjA~Sr}C3Z{>#db79_b+<~XH; zk(ifnhVgkVZQk(4S7^9!vYE}$cX5e#e!=T{hXIX-`tQrw4OU8-UdNncL4NxE45;3A z2Ys^6$ZGP30uIkK~Cvio8%s!Vi zWRPyX_i=_7mD7gf?a-DxNHhBSfS<|&+hrhjNg7luWlVW334bp>%-u$vTL&DD2a z!QeSj2=h=ra{)CSiR*Yry2l$v1X#Fn3$Me zp!Tyx`}+|JR%)>6drEdTd6f-F9H%Tfo+n-pvg3yPB4Q`bj4;d>$FmwVG9F}nHq=H&4Pv}kxU_jhDp)|;-Xhv zypDrI9D~MLJd?pVkNm&+%*;giUTroz>Yqqop^T(QQ zb2al|Q}bZ+XwG>fT+2$^=GJz=W`}=yVy0M-VILL97>oaj$Nc4oNeKCnZjm{@@iJB z9iPbwoMqAGxay2+D=A51&;d3l041)7G&f2!+lyHU7i0dz@yt2dFzjiNAszld=G9wqj&~9x{i#xyT7SMf)2!$Fu zPH-{p9oYZ93f5JKU5HG@auSm#Bf$gOGqVy4TOt!2SY)W+){E#^u~w)J+dCQdhP_*t zuY{GjWVc!W@MAu{R;^7mrbu=J0L>*gi7qq&Sd3MAEdc5aQ(5_TQ-x#`z{YA5<`({| zCq!nJ@rFjnVgi47H4cl??5Xc%DMKm|bw~xujF#>27-gB@vrTRh?>+s+hD-@S?K3cy z*zYgth{_hkKn>MWN#>Hl0rdS=!XcspTRf$g3J5PBA5G(#Jsf!~v;)iKrKLqrQDz7~ zrmTkyW5=C#59xo(**?@tLVELKw4su#ty1)XU}#kpSc(x`CRFS0Ok)=M`iWIzRx_SS zW{dXe>v(*AksVp@5!C zcNj%Uq$;npsNld3a${BTPU+tI?h1|4?Hki<95;@m<9(l1P8!@-oYO4BynzNabRdW*Bapi@+HXyXlvB<~YV{5x5Kj zjfWMv)~AKF*G~0Z;F(^ZjP~d(QrqX+1y8?brbd~UYpq!bv~j)ULhf=N^zR$~5v}`( z(D7009qJ~?!QzIudd!p1&@ClEnl&3Ttn+&35(~3-Xg`D0JPo5ZTKy_y80~( z2TBHj{5-BZmArCHn~=PD&T^IFEhu)oydyb77So{jgwTOvEq@Ef}#rYUUkj89+A&3V{-Yg(yWGCYg<_f8r4Bdp@%Y8=_2bZRo81j zC{KO}bMY#ib+W|XKg{)tdb~5WczKc*zbTX$_nj;PF9$aey96@+EHdt<`CWOT-*v*K zw@%)YL;5pS?~$RB_$7*Ypwi1-&$V?(TBqiZHX<#1-u3z`S$1+7)^SRif7ioHFVBP7xNiDKzy9$(88Et?ieR=dOvf~g!S zIarj!SmKo8EHya1Xz7aAH!Fj?AJS}U;-nr0beetSX0r)FPg?;hTd-7u+Wh#c26}q3&vMBY=XyNvK7Q<5nDtX(WeUSFp!ezE zHGc>|I^<3fB=|_tbq^A&MV|{{t5bw0Fx?YR(ps3u98H(T|Idi}vcWMYI#$4NnSVQE zA=paFsG2^Thue$1qJ@y+#00-fydGchcsN{jOq5p5inw0{0jQtsl5!8Fcg)^x$z&K= z-C`1AAHvx`(kC0&E2G@3D;iD*buiiui8h}GtvD+UzILjDSTYG+v-?>L~n|822 zltsJyBKv~H6%3}TvJvrDt8!$Z+3bF|8W2vPFe-RRRIHK=G_!fZCX zQR^P(7?V}+f?{!cKLN7ge#A(rK8%#D@%;N`6UpD43up$T@=TSRAs-ZQ8VbW*!@(Jc(Adpx7Yt{+wiss#oPx3VRfwJCMW2full0~@}j50^>fGFSTX3>t1M@~ zhsWZuj5FU*ED*z3h- zf3s7lQEN4K(H@k*W__*>$;@t-Ra?a?NC-nfWw7(}N3n^DvZ3j|AA_9p+N?}L+5)#- z39M~aiDT0=A4juo4i;bWDXlB|=H9~e_qe#30YPH%P{b;|iC|5QcN*8u6`?ZzNIhcA zTO#bP_ra&rr*F1M@;4Mqmd%GY@3SB0M@Q8wI$ZJ3hQ<;U#-90Bi%=oSvf|KkVSR_g zrFnZsCeEIc_qzNMDJ4N+YFOA;%kynBdqGfo;>uLBx-!}dek!kqW`8tSInZJ&V4BG- zFU+1;f7Z|od_~smdXa2MqhqAex}L~@vqVn^RpUssDOx#DR;3umP zTK4rZyoE9Kl)XQrmmM}JZ0{P$C z{=Es{xz@Jhdr(pSY(Wbm{pANJGg1ogmq>Ybu7y0l{_ZWT^ya*?aPHYm$j22SqossY zpFWEjQGH-2Gg%^Dx~?gjKOfGR76u{Ru26=rH53HPNaNu~-`w0JkAa3BkxGGPPb2@gW0IGLm3r&`de^nE{Q2wS8?fx$ zazJ=h zy@poR&(MS4etWzdj-rUv-FpV8W952vc+h?M^M^DNN!dFBcH^i!sE+S<6vI5bsYOM! zY)*%ob)g_$`)yQ*#6|IXD3oE6p+I(8cW(d$Y%xULIRlS@Er@ai0DTefQ>iud3$@y zes6boc_91r_&}t?6&QYN-u7^rX9phLdbnEURLGZ;-FrmIhZ7kT-4~dJmhKJpSZ;J+ z<99u`)(J72DbZEn-&?E$?o1WN-fYBvLch!2C8}Yt`R38#U@}{#Wv#GbR`zB#kZ&M` z$y}$lz+z4G7t+-y!3V_&I9)E+|GE&1u=aw_Im1qEcUrTKxh(>&=f-xU+~CBJkdWNB z#u-}fCq0&r39I*8oY4oPxzu$&L?g6>c=fx0s0`O#8Vt*Q&hCufcj;1Ly_87SC51fz zY4nJv+u1fkUwtpjhE43VCA+Z(6tsN~^SNIFLb@HT;B>d-sxg5@gq$OHFfU`+_4(wd zPx0n@yu!QR736G=fGwBm)N<&&B21{#Ue{eDyMzQw*gQ+}oPOhYMyb(r{vYf2D~E>L zeO_QJ-iP97J9jMEPs%=)HmO{nCURP(-?Tm5wRJmcA5)%GWjqWANAU3O6NvUxCTM>7 z6y!Wpx9pfg_Lkh-kI(&Xah0RWaD=t(x`zq931O)9{&Z+>Q_N}>iF4_zw&%@ecg0Tg z$KDis97auJ&zm8g2F+TB4)G**fy^TZ-@F^E{uB@R7csmVWi1H>+tE zjzQxLYZCRe^T|t!&=2ZreLsTtkeN=o#9F)NYjP^MMP^ujli{7rJqMrdirGfp$$c+@ z73^x`EQk5Re&b%5;m=&ji%T(!Ylt+Cn)Bgxeu9Q{hZySEbE{^x-MBx|WWSW=h^R9f zOAlar35(7z56|CCne}=}+L>lPQYf6&?{s4zRso&Xz`!7YRRO!+HgX+$#j@#O_*aK- zT2TI(-yOF?7sX!JD2<@DSaY=3J&0tauJxi+CU#`EnRC^B(goFnT*JJ=|4hiX<=cuX z4{~{d*=C)MSGw2Z&DL%)@N!`1f8yv}RIc?P3d94(RI1Mh<2-PIEAICveOtlQ>CAyd zj)``BqBUwF`PE5va$Fo2_3fIIJ(Cx=d%&i2zgkA(lUHl%R{g)kj^2EO2V#`np$J^J zr=5aGp62`u$TQPDF4gM7kH@|yJG%kv*I(l(<1P`$QEQV5%PYKZwucYu71+>fa&*X! zZcKGraWRDK;9z=q?uRuLFJs4f103*y)INNRP}u!tT^pnmv!rXnw~UwFgcksHaMdW! z(31PvNET)of&Rl;#?#XMFF3)1I;Liya`V%-shCIkoDj`=%cgQo9E&A{TX&z~Zj6A} z#=IV@cIGN_Iu-{qkMe4n>sB8QodVL^?~d98H|4&4O*#>8J^v}a)pE7+#&X8&A3w+3 z;(B45cFM(nA4Tp*s@{PDHbKOg(1#Azv@$$?rC;Df1%a_j;^q% zyoEi+Y&{*Mv+TQSz2c|#M&^xq`EZMuXJa`m9znQ+Om_d? z+|O9xw4Z|U``l628`plaK(6S`x*vDLU}$mNZ*Ak@Zm^(qN=3E*0iHg64se7{(`VVH>9uBO^sNp}YW(5*2d|h8z?0(DCT^h&>pZNYwq_Rlw20Jc> z2<4ge`n)h{Cp;Mr`ytz47}}^ePAS=$wiaKur+b+o@rm2jveWEM3_z2{;cgn}xrriu zH~;C<_uXi3Y?5QI3y;s95AK$9YE7d4KXC-=+h21;37 zLnm!hn#<64$>Onh!>0G>Kx{RFPk3Dfi%A13)jWb5tmNH{hE*vifQCFC!6NZ~;~Es{ zw0TUtVeNuTaJ^s#Y_L{rw)MkcZnavdHW{77CFI2sm~Fcv78150VC}W6yhI^u(LL#L zb0&lJI*rY!FP|?5|I8oh=9EDg2~3t(DnnT5b6WM7?fDsKbaU!pgr1`qZmrR58>GpX z1+VSLq+>)COlcr% zR~AmV01Wb_QPFzVuwX}`GbiSxcd^8;ES?^&K9zX3m*>NgxHH%D<^!?%k`z)$GH_Qw z7Pa$vD_w50os{}`-!m(=O&BeL(ln`x_~^6H4E)B{lX8gtB02PBPVFGocHCKhU-Mr0 z^k|&GkjFg8G!6Xxsz(?$V2#fzIFINM%t~e20T@uv4qDLIDk+s#DNB`&4?d^T^?$b*G)LemJwVOKLPaujVo$D9=o-!7X z%^O`jw48S&U~I)Q!T+OS5FN1$Ojj<=d2jhEQnp}n;v{>jB(zTNtH^7IS2EOWN0(P5 z!^bx8Y=+W37`>;gNDPG?33yrUxG<5dRrYYPv*p;7ovhn<5x3vq!6fdHSBVu#?s>Yx z1(z&+grFJe%{MQ77V!6X@-sM=nufE79*{Zzc6HwHsCpq2CZoewN%#ls^hHD|Cdq4O zLA5zZB8!k6gDMb!z)<*RG`-;RK9s3-yPFctbf=b}%jNy$O1RCiaUO45Kkte)+D>(ePs>Z6G^=8ZR%32ClovJaW#U$VP@_4 z0k}in`T)O|XJ6G&2D?>1`Edn&yx6*71;ORk?^jfQb{emeJ9;9nR= z{D6*uwhCQ*I(m8>L%KCcC3@4uR!rR+gBvus#V&Auo@tFD<{}^bqK}P7x6{wHr+;~5W%Xofl$y%heiL_{y^*r=bw_))4bo`v(eanR|R0J(v#?o zcum0el<2UrsKL`|tIkoUuoq}=ChNWcX+CU-N)Wr`nwWu-QlJ|u|2m}jV1I)0=-?6} zB>QYprbydvev9a@`$b@01r}1GX?tLk3k^1E=q_e;*q!Q^ux@DphUBWqet`N!ybhJX znNARP0sDaXWw>%-srL)6XLf?Mnspya1?UC>x<0SC&{4jGvi=;fdS(NIomXr zeDf`Q(5rRcYkj-`!iBD%USwr3n+|MIQ)h?Wpe{2s9MY!z9dLQTRCfgl=OEdi4p7eu zW=1nq&&qMF!GhN&Vci{c<2Du+RXJT+%uHd})76go2XR+>yV=fLQ*8%n4pD1ejtB`* zqr1OUbtA0Dyp*r1fUHz5R{A&uJ$wyDU-y%7Et?*!3%?mi7`$hw-P1JUCjd_<$|M{l zXB)@D5KGN8p=88;d{BOsrHf=(ZjP@J*qwlTn~HeGco)2p>c$O zk%8|W$dpE!&eS6MELBx8fAZC%T{GcWpj{Ici77iUxC;8#EJ`Q-QAJoubK){GHLz z(gfB~mPeZLO zOGOd$kAV|1BlA|h-_v>84R|E9AOB#9z#ji0wDM}jZA?t>eQm4LRD*?q2EvMXxScs& zg2u(akPe?(5vbCxCH!Hvj_xQvcUTujF(6P=x?lRgkeL5u zVaO4_|FSSIlUKrCerq+z?0#*npr(eW)-S^m9~aj!*)Q@xyYa6;F^bzKX86;{<1iMT zaw3gFUSb8HFF8vj&@kicJO4O3m1Gpbd**5-t3L<(NjAPeWHX$`I~&}m>Bc_`sj{My zP1c8068v1t0{q!u7&iI6;&j5xlYR;;-e2A?Wbz^P9rrh9BM>MgX^@8J&*~S_H!zmA zsq~|>h5tmg|E;YmP4$ik8E@jKPCrMeeasQMlkJqJ&EEje{^a8HlMr#=J)1J}bCUAo zzmddDri|DBg*g81aYIeImgvuVqCQ6>!d+l)`h)L`g+6-_Gh5b)2I`Y74!p+xw%s zDoAJzb$o-%->y{g%RfiC|Ep6n#)gsO+G71)t!A1f^Zz14anbN zy!j$zzo{kt0g11n_wPZ53>Blqd4^F!qaDMZ))EGe2|Z8SKqTNV3(;9;t7q^}r~SE! zYOB>1OdK5Q+8zJ@y50YSX@wT4AG>4#UcVSm@05c|M1yM)D_xyyR*Dkq ze`nycMH*FV_|7Ckm~L!~V!Y7K<;!OnY7tuR%VYOYXVD#u(KA$rV*Ldex_&SL(C8a4r_dg%A7+GNrKEUZ}|Hhtbt zfz0Xq3W?QjYnX*|)z)l^OwDRJ*m2BZAoMZ>y=qU16qB_-~_HwQ*Mkvd)v7xu9QPWKRaYh-&OXQVfrU}Sgt zMh#q_t6jD*z6C#S%)ir(A>-oWqCdyF((=h7vY-EI#b{<@M|}AGc^5K&HzF}#w@f-~ zPxIx1S%aMRPOy+1{C?Hd3c^Ia5a1)X{u#0g71n-x3Asg0dIlX^_jjjZ$8SzEo*Uyu2$sfo%hOWP;U6g$q;a~&GB~KYYYFM?@ zoFyaUvDT+sH{T|k4Xf^1xIbKQ;>$|F1qlftAQEv*QGOcxb@XH{CQwzBaCy9@kvzh& zXXM7iJH42X^w$y}Ux3#qKRzAsCese;`wgEFx^8DN;vdc%WytbMFEmqUxL2OBljHCB zjV912zSq%zL%OW+iF+OqV(-IkJPvQbBM>B32ROyldL7dg-DbD;GQfHw#~cVBzLdmf zG|kJgN?Yh4Q< z7)~-uH$mq51vR_n34tCJ$}S)|4WkIbM`zzNxQTk>iR|xVBO5~gMTWwqSgF2s9iifU z);gX^_u|C`1(-ig_W+WMs4LUTGs&N`}u40_&!2(6b&1po7PL`&Tcg=cSsx zNXob%UxDAUUhc(1Xsc0?Mg0K;7UHZs2?+AOI^Cez>REsu;Qf^N)p6MY2W;Un z(wjtL|I5elY~(H_CI%hs;c*{KJp##LE#DO02lwb1QuCs^Em}yZ0Y?ojSxI)!E;s5Z z_-jQ1ky-Bct0F<-^_{eLVytd6=4U}j#qd{AKkUqD4UmYdR$K3qKj+litf-%AHJT^6 zKmeQ(I$$$C->_>@WGzS?E;+$mRjjA?b=9I}Q=?=|k$F(}PfF?GmaAnW)NNfzMkI3H zAwlb)rS3;l{M1=temaNQ0nW;22_h3nVQ3sKHE*Y*DWR!Igvx?NooHAZKj?f?rp|JC zxa-LyS1u3+fE2-V3hxADwe(i?qOx$^`H?UZmc-U2W_z^*>-NwWwlbqdN0mp$e)o7s z!rbQx!c_rMXSfc^q}_f_vy+Ix)paDS%faK(4_XwM4QZn}YBq~ZQ3ux-aKbH+z;R9D z`F>XM%Fy<>cpp5F!Q-%N{BE%}N4x=$z@(!qkp5VabiS|`tqW>#yW$A+dSIR`R$-cK z^>E|7ne1f3Nrs%fr^0`b0<$<=y=?{_*13 zu*`VsdT?2L32qvjT7B}=(j(7!Gb%Xt@aq8rUbACdB^u{o)v`nUX=T=jr>a$GtES1x z(y{TZLN7-5o4@P3bYWz0*#;lux4MF6+y-kgSld649zAl(?p?j=t(6aY`+wAs+}8@1E=q#wa!3*8A<+AyEBG zHp_di$$5@P&$GqVq`k7X4$b>6l7(JZ6>7{*y=>_O##(6C&uKO>!-w6V6YBH=3ISY| zVE9}gf?Dksx1@A_H!A#EPcKOR4Cz}Ko@VU)R*Kc(=*1nHXD$}|EAlFfGw2j*4vND$ z@g#_04!aw_O=IuLF<*T=jvP&LLcE5b!rq*VL z;{E#|sZ5Kq`qLu6sE^<|(N{FhLK{!VaH~$j^v>5?wa9$0kO=i3J!Z9nwGi9$V!uLC zOKcwWBvyzhM_ksKO(>7|32ies=)Na6;4}?jIyJ<@VrS=*NMmIj?Q+6m%gxdGUSnngUQ3~Z*N<0PL=QIbR>V#F z%~efIkmTo)Q_{(0mFx9vn|2^mh7z&HLIuj~s&&pAot>2y4RR*At%bYhwMc71eIVK5 zs|9fROF;z#gC7WM{oOBe9R_JuWpeu(f+XmdZ*y&dO@0>=e}%00WI}ge{Vcp{6mw$l z;x#N;e&-Ce7DH;=U!d?sDf0c)rfzl!J}8l3N55Ra%#)wa%UtR_&0GuS{MNhkWZHrN z=ndn5q+<%`X!r@)Pmgc?59Yz??gN-1EuBLb+va_M~Y&1Z*hWgk9)BE@-$ z`2;;#QwjL(Q*a*J=mS6&lSn3l1QQpHUz`H8v5G zcydjS%bCEZsqe?KVb;T5_h)jxSHBeZxZ&O0jP1z@hlY5m zN0C~c2RS?u5V}z<;G;<9B^`{1Nxl*kaV|M493Q8)8P2E>4=ekZ)`YL$yur?m8!L50 zCmxJILvONt;33d%2rYhr
>q9-<;XQ)u&wa1sOZS8LC|9QOXqX<4W{7X@?PP8l^ zIJl-WohPZ`Zx{P^V|ei*cr5OIkk4g&7c)jHQXyXkm<(aFeXl6O*ZFEo(fjC&B2azR z-Q2w);%D|HP)E}>7~?Ikd0UIiqd(5>+i&pqp-9l;?q4S@j6skbJQ3I*(KVJk!Oc6u zpV$0d&K2tVa`NdY?@X2B=Wiluh(FzZKa!=|g`~;O2L7;pK$BXn)&>lsVzz@EmnJs7 z$D3M}H!6L`px4THXAV)YL1sF<{Vkhsc%6}n2SQt~w7_E2`aJIl0TrfBa#FWy;?L^WQ;?zFtfx%qwciC4U{ZauiG=7-Tfa`Z_{pb-GH+LGFE>fFOZ6;iIzAX*ivp_4oBMj}+=*b)?C9Gu zUJxgB__|TLN167TiM=f$(s6mkSg3egB*CrLo=3MkSL*64ddAMdN%lknN(Z=9r_C9Z zauwv`crc^daTXW#_U-uM^3@VphbkRSjlIaK<$|M*VS7#2qlXN7j3E2Ya&dAa0Yeh3 ziVmDt)L)1zt;j~*gdChRj;q?nv}`1tT^NWH{^-uvwgS)JTOZhP#4`G35fbb=ek`c%Nl|{I3WmantLNomm0A6t2+Q=*g`7OBszF;;pegM4?K7!LN)78*TI1Z{D z+w$D%)j5GS+Yz5Lm`luhT_Mu~r~o#HI!DqLFQ`S1sE{x8je+72E6+`Swxb|xizluX z;=eZ~pe|{DE$n;%)3Q3$Am z`yl4b=wR88&7iJnb!Ai&Itw?};~Rc+QoR-{kakv>5=Pm~AA1GpJNycN(E|$R($_RE zrxzGufC1qfjYYVf-wUKSZ0#L*jN(dIrA$YFKo5`_i;akrJ7+4UF!zSlhXly?&_o2r zeL{No@(;TS3A4P@V2pj^%n0X;x&>Fd$&vIxd3_DV$9Lj$-%x1aX3@MH26F=v(Ot5uZrtFAfil4}Aaay#f!&`7_U|%4u zCd-DU>trn=N*}t9{jups;U8N=1T(aMO+iJw12I-=@&to;mmi(cFyDguvc*Oc)zIMA z5YwwHE%@F>yrOrxK5qWS!T@&Y5~k4{Eh@Tn;Ha@8!GYhIik37&Ho#+V~w!ekpN%~MeqCE zclxp~L8o%`gU7l87zuOvDq^o?O)E)e5q00*8LeAzO-A_b!Qf6I24>lc4 z#|37HY@!sM)XtU$+X5#$ly1nZ)Fb6&gg0xdD!kmteO_0*I5P+gMs0L~43TYRYxc>z z9*q}SnuSYyX0zQbYqClxn-u?nY9Y0k##gN7ECxQj9FwME{MJ`JHCuI{%I;e8v$TuAs@24qndWt;(HQ>~ z^NWM)_xMZH>CVD>F?hRaqZNg=3$u(bztxk{U$i;C-Zq)scWzif{z3Azz0ULP?KHb@ z-$>PpMYnZ^fX+xe{*s`(Gaox!{YabmM+r4&UXV?T@qKs1XOB+CtWI30u*S89H?Iqr z%(*xm^cRiq0P9^c9@@kBq40?Kv$Km1vpN}5zPphF=XgLO^0=szVqin)+Wky)nA~=Tgqcd@em$y5^l7f zUjU>AWqu3tT!R69c({e@+&4O5ebjPQOS6WXGl6L?V*sNF#>9rkpT-S0umU#U7P$?) zWfp`K9*j^5J|*4BJ6rWZB2@5>7)28C@Qj~NMtyyxX|8VWw3x-m zb9J0d;v6dV)G|g z8lFMozhGsBK^BZ!3-KbYP`t<7$m%P(O*%06qW4i3n>j0NdC}Sw8U$~f=ZNU?uKuZK z2(!Y4NG1*cGOJ+@)t!kb8XU7>SOQ%%dW?%$mL%*?GCvnlF@HvdsIK`;6miPIPw{Pj zGy-$vJ<$<;apRf>N>mUBX^GZh52MmGD%!bCrc+_MKrFlYDVf8CQYZpXxtEQrGP4L< zTji#JrSuf-*evI4Um9CIoz96KryIEK(l8*^!XGrDKYE7i8mC_V4Ac}*GsfS|P)w?w zf?KslV@J^^_y_a{>HPym&`PjI#FCx%2K~^f0H3Hu!rCX|gbftxqTBpgEv})c9iu|E zr1+e8I40+rdmJEMg5$$st4o^r<~Toi#GMDq(sHPeglrQb1M6dvgf=*3X*>k9HhoFO zO01)2YTotOo|5rCK29&TAFTqjRAnA%hINiTA94Zqn0zO?g`|SXmG|9;y_=C=F8T0u z*OK}n(1Giv`nh=i`ZAr76uU-znTZ={&~@q20BV`icKj-K?=6=?ln7h&NJ815Ykt>1tTA(BmAu0ohB?CLdDP0oXGv-n~#*kO^7 zo$hzNhyA&Qx2b1Ma}W2tG{VIw@qc~=G7;<1@T-mU6J5`@-%QB_IT0EJV*bJozY){6 z=bziZ-O;mkD{`X3|o`OhmoPe>qN6jFxwnU9dO=k81h9o}#-Cc4~W$mIRipSglg z$PC4hRQ7@tR+9D$ejWUNph7p|i}4l{i2g8KSm}w_Pio%J$Bdik>D9#jxE}mCtkT!_ z)Is#f<~eQz=?Drnz@kfb-w@mVT9ga1QtNO**>^6==dGF*ATnxi}rpgoqPcCu7OS}In z1vRmrC(V8TlN!ZPZ%HI%JSV>0aQy^+?y%u(CVtViGx*t0;*w!`eYbEjE#0CR?NoMN zEFqq&CbcCW`Ap@4YP<0&r2nX4mC?@76L+!#;chC##H-!tdsQ>9H~lmMmA#odWtvnv zOC-IG-Snv4b^ADc#i$Rd=LCn^LLY?xw7ks#^SD2Qrx7`n9DHb z*L%cEiX{B;`u8@?x3lm}XMG1FcCO!(8MI~lj;aE!Ev3Kn>*3mJwEGI@n zeDm-7h3*&lZze>Ms%*fluZv>GR?FM_$W^hlPQPm}pSW(Gz~(wep=6#h+=7XCotEp- zG?BqaaM!XMqFFO9DFzNooS7f=j`F2f8t01hOhw$dokP*enoioG_XbW`rehgf0W?m( zmQ8^gs}S2{Zqah9EpBGCM$F9AaBqg@%e6c8)(p>Ijn=YgVIMva44>#WajYAIkHEy# zz*Is_4BR~n+34p#gSG+`=kVX5yw7njizJCJ-SqCx%v;H^~Ym*5Y?aiOvUOb2_3g zhkf<;d4RoCBlmo_k~b#3Ghck3S5JYd9+kJ4lzh;WuWG>CdH%9d8Biv}a=wjG!w5qow!>FfNcKk$+K*TCyaw{LA31VAt z%jmwxy(EaPAzthH2_fF@nkvD#eb+L_@za8_JZS1k$Mc<4_$IIGJwDB{NLagC`Oz88 zk@)RL5b3kU~Wl3wG?)M@2%t*EZEnb8fMo~rPS_AF#hh7q9N*#K<~Zx7Yu} z129$qGzd&WP!_=WENRT_i5Rj z57DJD#64LA+2?e3@(C76bjpfOq0X(82AN7hIi7$jh7Cf>i<+$8rUDLqUiD?{uQ4Ae zO->Y@hw`~#5$&=Vk2MFm;SXA`21<&E+v`S3C!4)B|E``$tx@>%eg|Vi}c)HPb zY!p$IYys8z@G9Wp|Bx5|@|RZAUDx z4A|i(X)F#H&P7;e0EPe$a&ibSD`T7~y~Uq54SA6dlk@>!FS>p%{^wc(qJGRvUtBhx zvD5W#?C-JWhO3_Ea-yylynUMfAHI~c1HPCVqQ?+dF&rxTzx&OB!=z$`)WO?Ou@yuS z^GyBzrlI_#_|=N%RS1H~^*oL^x;HKZ+M@{AsP{Hj9x_CH%FD|cFX)P4|Md;X;oRN= z;t_pb^T3@X8-go@|&74n-OTVomdhOH??n5H@Bx1ghmS)FURfy$H{V|^lShzt5Ha* zfQNG%NOKs$I>5>%Xtqn_@-O`0->(A<06w#rLE7K$1#Ko|sX{wo+n!1>3TBB{k0uqc zPpzH$AL}irDB$hl{PGoW;pjIzAMID`)mv%khOJK_6`VL zlUnUv^j^)cqq1uM2dyC&fMYP^K@U58sq5Zr12fCE2K+^Ud(#U{vy1q5Z5`8>_X&03 z;I6N(t*w>sw7;ZIVZ=Ti`1>^%hM%IED9!!xaeW?uZZ1A$ZA=2HioImDwKRYLgqiL! z|Id-1D*$I#odj~gXUn>)dv(r%Fp1I+=%$>KZxW0CKFV?UfvZP&0pl=^#Eg_lqPNpP z$7d$r(WvnTWea*~182(9{}cXi{Kg`pugN8M*A0Lk+7?5&?>I;tdc6l?D5!D6CBclE zwX|Ob=}7+mz06eL)0`rx@}CSZuzZdu*}Vxl-B>xppgX83yvY?}*!_Q@M}od4cu@y) z6Jveq`djVw_qk|55N``dU2{w%???W$_(W%4waWd@iqd&sC zJ}zbI)*!$M!8%vS7-Yv`Er2qw^7*rIv*X@I02t7|&<+HEP@Oq}8Xq8P%DP^4*6a}AEC6n( z7|>okzBkiDAWww7<7=Wzk-r~YjGPMY9YJPdcRYSLx5)^8GQgJvx&aos(ZxDTG#PVd zC3H)cq~zpur96pu_Tq;UZl8FfA#owHLMoOUZ~sFo{O6_&`Gy^(L`k1FGsRz`)nIJ` zyMf5VQ(ox$+&k^ay-nqD*iLaf-zK0QHt>?#K$11Xj4dgEKumMB;tl;;OOHxE7 zJUl$}OI+pWr1N56T6D--`SC!K!ZohMGBPrmW>$dH`X|x>{aCh8N2lg`Y){Sq z1;YVu(lk$dV*X%kYFXRdBGvP!rnW($+!y1m|5*(wW6*u6^`bz4^u!FPuFl5VmHNI< zvh(!&im3mBgZ=>unHj>#?b{iBm6)~cdGg!i&&?BqKcuHrRsRpa=0}Z*GOn0bu}F@u zq5A@~fNG-nJD>CRdzs_k?o}~z7kI6Gi%}DwVUtwceDiG2Cv3doH z{zB^abR~KECCm;1<4_)?^A#DsiBjVK9uo)Gw^cT(J7qA_d2!J3V0Lseg~KxGX#p^Z zRWkqkc?rW4`?f~d^(;xb(gh_$x-o>(fuD-oZmN;&!ctyEV0f1N75D! zzi;d456x2})&C#=`saH|a;BOeVP$`xheL!9DAuU^%>{ld$^GZc|5etI^T7c&UX~ZH z(Al4)dm=7t_McxWIDsjI4ag1~Wn707Y*w{{L1rrBJ1CIMhWy#+*d zIY4av2?5HPQQudjW>1FGCjMRK9Bd?=i@>)F9P<}SZr#3 z%#KQ&h~+q8?k+dg@LbJ#ab`*KcCL347Hb7_Rwt_RCx zcOtj^I!wCcX($UmAy>d=jh!0>^6?dkk@K>hWDW2?L_?L{_wG-Q-^Q#8zz4=vkQ)2` z0QfV5b`^!Gbwb|_`_;a94K|`)OAxZ-oQ_MA$B$glf2PM@_^n|=w}T2J(LONHjuQVp zpjCH4091^*wqkoEH6AkohHFzZ%DEjQiq4X(6%Q~%Fkd@ zciP6KgruZqrXmW_pqYgzSEEc-QfwM|_GE4QQ0z)4bmTUQlgT_untDo2qSwu#FD}0? zAO%$Dh`xMcKhm_hAGVl$q&*prTTTQUqHIKsXZ{8InMuO~;SSn6yt=(V%bSNh0T|~p zEchA%NPe~$yys8ftHt?`&%=4Pdw&pD0x&fL!u{$$Oum3~SUzUOZ70)YYbbGDRO`Zn zp?~r_Q#A6NG9o!_OyGK149u<3v>W;zD{}3;{*UugDsZJMv&=4_Zhg?3NE^@YH4W57 zKu`0)#*OT}Z#@R!wx*4+4_)b(y6|Zc&%i>SuaGkd{$(kmeGB*0RSDm}1E6e8Np|bH z-)f9g^xDaT@igf_E7}(WYmWiT+xj1;m1_XluS0tR#ATgK1^OqPJp*w}#BH1AQ1f=QPE4hZ zq&Ooz=KxTIp;>G10PbW(nxZGCaG*gYq^x1Z-hZfs?8O9&*cB*Rz~s0cYJDwu^GZo} zoJ3bOf*-#|GUN!I?{KZ2A_ocDdpd9@Aq19vqWl^%g`T)OqJ}jt^0Oj^?Bi8Jk!S_M zTO%%$8J}0moV+g|0Kc+CkVm1GVDnHZ_s1g}A2!$k!dIXj$p%aw4Jerp$1WX~z?jxL z&m+61wHpBZsty28x!ePNGOCtaS^dMty)f>*eRY3PB*bxXVHiPWLXQLvzirhw&2&m4 zIv751yq#Kt`jf$aMSg{3Ym_5tKR}{=Ql#UlV@v-^QOZfgUb{91@;9tEh`tZI>Wihm zEJW_S z4RV;m`tXrK<=Jk-HhQ&Yu~6G7seZ&iV1Kf#>Qp8SlM`gljK|9g9|BSX6dwZ??=t`p zks}To-~mUly*@dIz}cW~e4Br)TyNTtiM+e%6YQ`2!_{}Yai-Vx;CV&jJa52Q{s`$O zyG}l}IaH@|0Yy8M?00rq_usqT+QkTw|!9~v0;Cf)yxIarZqMb;_9?mK0xnl)aRtGt- z(O4RIfui?{2?nd`WcP#mExn%u@KCiP(sud1vv(Q9O8ev2TWbO!#oc=ne%H!_%2Vh+ z8L|mpq=|M!XX`>O8R`#4_F{`ZN?oxmk?NIycFxJ&5!ZM5q!*&Ds{z_;``Zh2TL=A0 zG>XP28@cZR-{gWk5nK@*-0M7@PJW_?>*TLu)hsCVOAZE?TK-K^pUrXDeU&}FTI zc`=td| z({<1z7i4lzJyqM_028+tpXzTe2ZGGjJ}De3~`bldj{%>G?-6lB4A zmhMu#sF2}GGqH^66q?7iWbz#oP{NDOgGkRC5t@iu58gpMrcAu3)Fg}(Ek*V&U+62Q zlIxjRP8Bcg`V1Km!V1~LX>h1VoCjV7{YHcr{`D1;&+Tx)slv58+Y<45MS!Wtxuwq5 z*$Qfy_dZsQo``H{7Ls21PrOJ^iQ8Nn26x-GFBxPY{y+a(6U-u>b*v8tp@!%o_)H8ioIe!VkAY47oqjOKhSfDl@;4?UEj?sE|g6*d;qN5Em2;J z&l4hF!Le#NbWL*E*2u~3;4%81p^FzPTvOH@#Tc>`+bDf{^HJEjvU`HJmWfrMbb$CZ zujO%a`bcoLTDtf!SL*KruD~nYu_gUHCm=Q#4VQnvMvQi&AXzsJQ`3`TV&24=fs{P} zNi-*Sze9f@Ac%|XY%Lkfpd{ey*&2#p<)^OwCy%yd*f;`8dY8P|8%rVs#6KPY($r@1 zmCEp{jiSdhC2+NmjlXpVJ+>=3$0p-do6LIUvLu-o`=o9EG<=aZ!J!7+OHpRnQx?LA z6f{@}*2ye^-hHsiFnvZL+`8`7zUGG_D;{|CwF-A6d?LXyfJ)akKz?351%Cy9q_uH} z7n9O|qPx+>)0O>lGix)&v7+Im6V-hLi2K;$U7u&{CWft_{}RAE%ozw^x-RDuw7Hly z42bkO&|0;xF!1F{mw)|NLqmA!-LDf$Eanh?{s1M3;-4q97$-Yi;pm@v!$Whm4a86%9ZfEno?nA|l>p zp&DPqdjs{?)$rjT_cU;?AVGV4B8L(ay=Go1jU`uKf2+!@jLm7-xmvPusfm6WNZoI2 z5z?n`#-KMJLeoWog}UOGH7h%ecPMT&^tJE7t=r?EV^bxQeIR>S04$!n+UHOy8SgPf z1ea=yFSL?G#$%)Xs*7tcf8fd;%6<+RA=H9lA~0aL1C_VDYsdP>U7i|n8$iV#I}pn1 zRs6L%S>${^>mas?H8yk_MGKLF=H^C8h>?F~7kc%qW3bl8>|~;ToySU-y*kq_MO_^> ziFLHoq%UOr?njU_6*leE`uJP^rc?GfLABR_oPIL3IxDOH)3?`TBP9h*fPu9sIpT7V zLNoATcIAH4*YHn9RHJz*vMH zUdX4lkE-{T5UqX+Az|#dS4axj*d77hf>@k@AEK}c=mAbMXy)}}qkoLx*Nf;p<8=Qn z@XQW}U5uTQ%c?VrS46O@kF&6HEU`0-Nevz}k(WV#FFPbj`Vk^+^Dh2Cj6gdWl_2i) zSb`*esD91M-}E=pwL*0(PY?_CL-4!wgQN4|OEwZtgUOWldaVl=ckW=eL4PtWUKT;v zsVG3DMJrtO|I_Z6bA&0JQ8hxi{(Z2As)GU;=f=vkuy$5AvLm4&#>qhiNnY%itlDoq ztxp^H&A(&usbgete)!6{7{>1^SBs@2*<{PusPUQVY_?GClYaOEOU*&C;q+*fmTWI? zJrj#40`NteQJJfzJfGs6t+m^KR2=xPS9(q>f4IS#&fSqo;iOq4Fgc=D%ZWL0N))P|I(nFOu29BC5_0sD{joC zfJFW%eS$26n0*Q|%vebh4eZUB!;`sMC7L+f-{uAA{6Z>jKF?}f zoo}HOCcf88>Rxvz1<1Ec{vFRTtjUNk=s|B@o&WwTe8ab1{F~ym(MD`N{82^mI&aqN zuaZIcH@R=U`LNgZy>B8`vqssv8C@rm4E;!Y=yHEJMp4q&Z~$%rnM&a?Q~Pv*ew=iQ z`*!4(2s-!iV-mTO2dX0@8Ufjz^7K^oP?DaMxUZH$QT3p{ADk&1A37>2!iGmSUQUlr zZB2p#Fw0*l(6VGRma;Il>m5i!5xpol1;Lg>!9ruQuOiI!wH8yw@gm=HY(kw8eR z$v|G2EKXICW{W?w%k=jNq7sDzq_LmoIq8aHF8eC~O@0X22t_@-$-8;l^Heq`O zm$`xJ62j^Y4nY9pFGdTd1sbr9a0nM2%P_U!I9V(%;lCDlNA;j|#Cnxg05HcqqLr|T z!zqVi538!*QH6&0%4`mc!6uL{9+RWHyA`Q`!*44r=Z6V&Y!2R$ZR*y2`Q0X4qjmM4MkC}|o4FFbe z&2@Y3p^(IjU9>7)J@?DgdOO{OTRZPVkhU+G*%*)a;^C=VYEpC^;XOBhAJ;};p*%j^ z{!>0k#ezhp|8?L}Y;QJ@E>mrPaywz5j`ia}U@zkRRzHKQ99!GUg%tt=|4SZ__>C+C z+~-9Cdybx!JoHq@H`xP5cIvpk@JAq1XTQ6$X$qo2(G8;C*Nq>pAJfnL_2f$eYF3Xf^7SEnerKyRQn^f7vEtRn$JR{RzxBXHZ2S zFbpre0u@tOo|Ggz3Xi`?Ent8t(-8OEh0Atz-zw!s5O?F%;yDmY&hG=R+)S6my^1{g z=`%aI6eKio+9XOyKW>m~6YLV)yraw>M@Gs~&f<0o?#b~^vNI?pFU5++UwvFwfsrFH zWFE*Z48G`=@jj}XBka3m6-++BS{^t3h7^r?|G*1>F1O>)X}B!l}a=<4H&T$iXMEr^JPvL{3y%*BI89Svfnt^dXTNhWNB>x$m)fH^2! zQZ&vkd?_OQY9Jtbyw@XO?_1e*9R^6y9qMDvZ*&txCO~h(d7xo&?1KcEuhx$C+`Sb> zAZlh8^siCx3gyM>BDg@Ek}^3=u_@hncR^A7vEGwH8&K{-<>=pF;+9@miwEkT^(I;u z`{Ut+qP}3Fr2_FGy)v@p=;IU$VzV`q*Nwx=QpbPQR{T~TMAk`sfpaHIP|=tFQTJQb z9}n`|YE%^WDcd(u}u7wT|CSg&2bq#KN1>C`5= z#;D1E?H%4pxqE+gD*!v~4jl`Vt+;M=J0HPZ8s0;TCBDdKTbHfG4jA`)q=$g_goqws zs@c<9D3;|NdSL;cc}eb_mU6Du|J(t8#mvde9y1M~k`ZDdjae64Ur>hNzWx~S>}_)d z`g&y!3O2YQIQ6snD&~S%WK)DLbib#d!xzLswwGh9 z#aK2k-(yFBw80Zwpg_JXlkJV%B$TI9!a{SbMac79zQX!wgb_;om6NFT>oJ==OYh3P zWQwn7Q2Ot1Q;iew7mD9((-}*>o+?kGvfvX_n+=QVDRhIc!80{&9tYgHHv}bBg-< z(}1gTA0~4+bzdEM?F)aN?*tfWq`%Ew$HMJR2&`iuIzU3z;wU?{H+EuMUiO6FIF^mBb%C44@;Qp;=KW6PbX>&1NYI3|vncV)YEnV_ zga!L_yLtmt42$P#Dk|nCUKjPLJYE)UQ>B^>gUk2Y1q%9hjp94N*Q4s#}hD!|^8}1cs7sFBwP^EOX|4P4k z+-BgtZ}}M5-__ze*1GnMYg#iH4Ffkzv`6`ealrc>yQp!d48{`&CBdnWtq`ismrRtc zC8*v{O)BgPX4LEN2*a_Xml6>U*^<8_kCvhNz?* z8}iR}Bm5aj8cYzALV||6<4Xt&HPa>+d!n<}0p;rox!6qPStLnn<(LA6oOei)T`CHT z4R4j%S({`|e4Q6nRP+=J^$xVNss`yFU@y+MiEL(N9P8dhKf2d%1(wZzDCRVh`-V9W zv}KuN(a~H9&q5>uoS8Q-0PB+->2gn}-0Am%Efo5b8VsVm54 z=XlRSh-C;p^htStFvC?d#IdgN&Unk@G{<+lM#1#A-6Pv}m5zDrt(6iA;pu#U_M);{ z1VeX<6L!@uUmYTb!K?zch=KETU!VPUxP}aqUi<$4FJnCeA}|sW()zefoJDH`6n|sA zFtp|gw?#W;uRmB8YHbqlSZy@%b=w}SpguSa^g1h}V*@*cN{;6-@Uu~1kg%bu*@Vsl zXYx9=ME0+r4tNceAy;b@|1wB1QJ@mL;9~U$Q=y)%uxdh#YO8Q0LBMJzws~j~{W(Hz zgX-kKXS2O6OFow{3%Y;dE)zKL8MapC6BUKU`j+FMahBe~x9!Ky-+zo`5oROORF&lD zDmw3DvhPdj{9P22Q^*Nm{*2UL_$oV`xZ#kDP4w=!3!x1w3mZ7^Ce6KRponKG2i+jA zTx*_pTsJ4?H#1S&effcq57n@-$m+p~ma)C``y}oFfBK4cJJ{$U% zG3rT4%8`3*YfU2LVUYe-F(;9fht{Oo$=U<-P<%e%JL%UX%v2Ee-{H3mS>Lq!m2~@Y zeKPlPm`%1GNb?R9LR5Bg)Lt=XU_;=@|QI(X!l3iyDKT}!(pjDI|X&CAC(b6A_(I5x^}=U1 zJBV(1b(A{Gq;0#erKxEFm|NZ0+|D*nj}umHfco78$nCWixd)OdLwwdIsOOCd$ z?vUW0gD{C7Rrh1TZ_K_bGjTd)5MV}SAcYrVM#0qAaiIm9ndc|mB(#VxGcrIJ@i`oP9Hx}IaqK{0H5EDdiiM65+}KIWyf%ciB68 z$NTOL4&Eou_1CS)v^l~xh%u9V+bJN!phvup8}Z&r-iI5o2TJ6@Y#B;89#hoIqOdQD z{RHL^PoT|5s3lPIbBk~kBlUvFx{=~Z4_g@Yg`4(Rg|4jl>7_|MkIM#7tzaNPhiCJ8 zVjhr5x&cEs*@u)VR+!upRh~ES178pOd&oYty=y5G$u5#hSG!`#yF8e?e$PFdmekO? z#jp&$i=JvR=gov(r|E83h} zNO^IX0qyR(AIxYO8^tx&3uFW`!GQGMG5M%$%ReRp*D7q8=S$CTdvlO)c%wdURd|Dg z<@Wi$?*<4sBZ003a_`>M&A-l%t!311t>)TRN4@yTL+S&AtQ@H<@p;2;T+j3SZbZrM z6idAH}rv1e01Vs7ytSu3BZ(xZU>DM6XVjT1DzEme~~qE@x5*WbPl*4TSiC1dmb7$e>;WNd>*` zHSH?6&%kx1L{*!c!O_uFrG19gh^rDK<6G`iyFKwksxYIxpk!^}5fGyzYsS(zK0Had z(&4?heNQ64HlRA%{i&^829hf5c*{b~J-+C=8D}3uadONq^C}1L-Zv^26YmOtktR*1 z#j}t@d1(X}ZLIC|`*T}*DxZt>&7Tu*JjT}3F5%wy*PSF~Ypyd&lD!woX0Sf4_Q{=8 z-Da`Jh3tEc($aY#4itpq3OvI+<8j$x{D^^l%FhcN$#vCiH*#hM-~axPH&4(pkhv`U zjwyHc>#T=RBJWPg+Z@Y=T!EMN3)Z4P5f23mZE|B>6$B1z)k3{Hz|xvzUbb4Dv2UV= zQ|Yy5Z+3`f#IuN=vQii4&jxzaHKpO|CX8sk@20c+cBqP_^9!>X1&r(w`LBOP8Um0d z%d{vOcU_!p5jD?Ci{YjihZ;IneO}Cfm5Rw3M+Bu4bBr!;4!n(3W5v1kbyR-w=>P#@Ld1_D`r%pj@Jrc&kW zRy;(RYGvQ88uXpB^rWVlX|mx92b)G$zle_wB?m3he&78d;(6V^g zvyepN9@koT211(QS((9ok>P)G0rmnLufW+8AT}aXcVO0Tj(mAqxZ~kEz!unx^Rqec zl!)W|%@hi>L+shX2h)x<*a+KrK+AFShf&f;`{fwiZHg!(#gu4=2uFNtCO!ld2}=Ie z)LTcwR-Om{z~m^)c1rw5OX#X9y7yLrcQ1c;fVIxLMi*KV=kNeTG$PhYDZ6#KX)~&N z=-k9g4ZMVOHS?}c*8HhRr6+3^7!$m1?E$`i&Zu?xG zgV8JbwBv21rSBKTh(+Ti{g>wLB$qb1wT7(oFC|+CQ|x6`z?pD?)ME_Ias`Xlg#{@5 z1Zb=VIE*T5)M5?qS=)pjZ^uC{bcI!T zO;o2ru`!K`I{j%3Ki45nh(j1nAhCpjobL$XIJ{k_g74Qg(Xs~&Agu;)`+5D#9NOA4-u6##MeGR;l6Gm0Hp<8)Vhr zeen)qpM1eleC1rzqj&E;6OoBuz(=^^R;lMGN~g_Bnop!1O7*Lrz4`Gr?+xqHYhX&H zkJF?0gQ_O-oKh$s{QePY0_{ku)t93P_L4J}%*7R_`*2&ruIj)b-OoOUP@mmaWQ(@7 z^2va5$+&vfLp%3I{{*yKzJ;o2#bSuU*()xjiayAB@^W2WEZ(r*2b~ z<-6VfDAVD+$-?b7K`fb#B|L%sf@Es)r^r(Wb&;l;v2x8%*-LIA)kPXv4Kz-pZ38Rw z$B|OSpOTh1OY0Izqnpa0aq*;d$y_22PC*=2<=k(6@MTmp3HDXgAXQpLk8I?~TG?vU zR5xVSp1`Dz6YuL5z+vXIXkOGy#Gm?!^|MiZ7+AM-jX!_ zyU_pUH4_{IPwgot7rm5Z{Thzx&^_fSPLhgAw(l?xnv?6go zFDaRqffC5i^Mi4B9|9cFA)X{{FQ#~U+H&%9uX{dxvA^ zdffY}hTEfVF1Qx$0hia5`(Yr%o*py=G?Wj@!@~BiNX2d!IWM4<&KNcx*3N7}jdP2&KKT>E?9o_T;vT6TDrc zA?X5mjus_Nxg1MB(FjHL?lt?jKM%;KszJ{qiR`cNd~RT;7x7xJFz~s&$1AUU{&ejp ze(16}c`%0E{#3ZHI32t8=9ajqPxpD87E)8q14)4M|1 zVF5|Vuli$mkfh5@ZI(M@Pt~ZMEUoJKr@}41)m!;&Is0ju)bT?pZzCyM`qO2^K>Fs& zm`*DHGz;&&u2f|1(gZ(5-w}#)9Fz=@>ICM1*n~L4%lg4cmb#$AlcsM)T^L-ltQ+vw zE6ZyGQkV+J!X?fe#;3cQ33Pt*q+D9oH@{7|y@3Zd^dGmpm+yU0=1D}B>0wx^mZHvT ztj-?b-o_(tI-a;oW{suyf%M|_%erz>DOxQBwigAZUD{?2qlYSNr>ALdh!{|JtPL~| z$QBs`53;xGWn+OymUv&I@I3a{Wx}T*oZWV(Sq;-mQldSm=7U-~I)dj~<2vtS+lg02 zL!3V-Jpv~%1}4lPKzcL%J&jeHUX&t2O{@^CR_YYtROsM)PA*UsB=o0uP+wU+H)d|t zk7{WHf2iKGz#-&34MY!oG;1yOL@yhO=^+h*NABqWhP5o1yL|iZS94A71dnJR>u2uC z*I$am-JD50O}xF8he-ne9NOQ9(m+GhX6+L{zL&=dK`LN9GG7t#;SqB6{MLogkHw&; z8dl{s#xy31@HmJt#@75(Wv{oLq79}PLP2`yfSglM-m-AXv2hNNuGly4af)qaU*2m@ zcUAQWGiCU|Y)K)a&$ArjJ+Q8`K8e)L#U1j7N;YTP>a4YH>kfD^)FI5;M-N+5J+gV@ zq%;XuStB#UDmw;?>=iZ%v(dEm5J$Q>Di;-pITs|_u2h;F+S4w8!lNiAOEd93d!a+7 zALX3|d9t&jU8QK*S3!+T82;T#=J4>~0@JjRq69)VQMn zccLX;+h8@WnMmr$P0}X#%9c?Ysh-*Jm(skksxD*O(?D-7DE##xb8g%H{*Cf5&iN+B zS-geAd2&%sDr-&2M9MZrw|H()OxEz4g9VnRl z0!9YO&X@=~u6dZS0i*HuH2a1Od5x+Jxr+EY$D3z02U6B0wlSG~rmSxlV#;uGUZx96 z1f|)EJhZR#v9{itZ$K?X>-KUeV}99S>o)?wp6dL7r>)l`z@hTV&Icu)zjeC*v2_U{}%Z;w` zJgw1|bjlAp=W{<-MP&S7|Kd`}oc1byL|NNH8pVx`PH^yNteb*w7a=qonIY>N9JjkQsRKIXpQ=8u8Wye>`ciaAF5`3jyJ*lm9rG+xaa z!`YQ{sJ4vOwz(e_X@WC5wCmuNI#5qm648&n`cd(w>+#%CwHX!VV{X@sr=ZP$CVQAF+Wl#v68W-AWb z8kN^Zf;w(t9f1n>(M)}}&GuzcbpbH;XyVzq{3Iu}8q|KX++QrC;w_43pj_MwNBIdt z4O&IB+{?F1a8fT(I9!c_coYU;`PM%&w2X#i0%tZ9`dI%wt2xITQY?y~Ac$A+xtm^C z0PiHQtfv;>?8=Lw32-SQbmi#F`2y9)8;SSRN!v`94QXyFx!=|A=DB*CyN$J!ls#`4 z>);Abe%uc~fHj0P8EzxK3~j#A!h;qn@(&uR0BP(CvdZ2D;Z8NAu-)z7tBP{G%EO9u z#5*?WmL3o1Rwe1|dmo%K5-slwmhj3hN`>k+?D!R>at#BK{oLW{B#|>k&F>GX#- zubeo#kakUD))dsgd_N;u+hKw1R%e>Wd#a|F*x#{jC)jJmzV^lrLkik4d-J=R_zk4w zJB!b)YH0F(ds3~U{`TT12J~AkNV1pmrG$IxL}JEJlYMTQrL^XkTx5iDsto^|B1=PH z>s1@6?9=1|5!Gy>iE}>Y(mp6|g@$+Bgr8lF4Pd{Z@j*6$HT0d5yAIf|l9!_h>bO;z9 z?;g?FY}zP@@0;Vh4itDk5Zf6YyR}X(-AzQ{rxMAr&7oahrTY**08aqnY#8~xUf172 z!F7_l9@8C#s*~ylwaV%8sV}_UUuk-rS(}3TFYY!X#H|5!SIPmKku}i+VI^pD^PNR1H7^XoTr*^(xbW$UCdV@I#poQmP5NF9YHS> zQaW4iEBsSLywdkZ=c2~X$|UdqtoBA#SryRkjWZFy;agQn3uU4>YA`%6a^Udrl0tZK z>p~8ePJ3VchOhjG99JTnD)ni%`<_6Toy;5z<_B{AqkVAO1Tgc4x$$Z=S1)dpfxfP? zlA@*YM_}8Ize6~Vkw{WP^dV64fyvpYvvSc=dbTZYd~Z>i9(}L1#7HM_d%bmMCGlAA z(1VUtiYsvMLJDEnURHlB@N#?zTbNw(my0)!bY+dM> z-_~F+87rN)%)I;Q#-rsMPILjaO1Z<^y<%Se`oCQhn3%o1JGH_rtb0EaGW->etJI#O znM;zcq!Fz}Fy^J^6Fs0>eb~2>91{P0Ey^_e{r1KvIzd4X`j3M)TQN|vz~twg=_g4) zMsM$r&gll!yP7@=o-l$O+R!K8KJ?zzGJg5}Rk4gLJ`Vh)TvNp?f&X8Ik*lP*-VZ0e zkpZuIzRSe+$2=+R=Tv9NyJL`=H?jGtm3RST0kh-MZ+a`X#AQ|yA__jb^nw>BOKQ?u zPkS7kSQ$s~1K0CE#c}BzYBaq!`9d6dqOkZ}`eFM)m~><^y4tJYue*mq)4XyXSP$cN z(j|%Ik6C7=$~I^D)RAswh4Nn-3R$Ri3QFd%aQ2C=zykA*!cA|JtKz)%ewbN+)0N~o zLof6&sCv!t0Gy`fHl`v|u7}`A4eeNEcb)JH6}P%&DovFFL2=LsbIqQ+rD|3=D#3tv zv&4Zk!%T1IrFtW59tMDRo50lR5AZ-5*AJLiR;Np*+&Euv~>`WY{_kMaC$ zYFJ*^lH`cRZZ%`5D1TG0%1vlVZH)7jrgwWL)$0UN&^-Ds%Xd;Le>eKD=ITq_gO z+)CV@dBOM9kEE&N#6t&1e`)+AwfecQ!VV=9NQMD}35IHdi|Icx8Xz?aO_h@)bb6MupWh)xdfE z&Zo)tbdN8cO+_vCrC+(+89AkVm`Ak8X1F4sot7zJYCo8LnU=r4h4OeZ?<4Fvtdw}z zr*(fHhNh-$BR+f-?cw_kYwxZhG$}o<{t>pSAW0*)`Nr+H@-4;y%_9ZFAZdGd2K(x1 zZRJI(r(VRmG5xVxY+lZ@SjaxR^{1cKX609R?|6*WpRy?@%9(u+r?c37OAK0rJ zl}tC@CAXC$~{Gn&{x&61HMncEmP@h#w*^(8<2az>>flp_(15X;@7;& z;SxTNRrJ`ENKxLBVb#);kS{)A6c(=twlL_Wniu80loy?o3h?M3@EXM>P8-6DZ$6|S zWj1bRRq~4qH{Y#x4kYc5iLst3#%JF?w)HN@tJ*lu*BxS#DjsQQ7g)dfO!#DF<9&y_ z@Nqm-HvUA_VX9jGQFDmcRIu;iwZ+^PR{c5?qgYbm1701xvjZIw?6cqTstvm=+WUHI zySLqZ6UHqb6T9c8tkXsivvTj}cLm08Bk>sOD$-bA9m~?)H&EY>*ShmK>LG(*i&z3r zK?wW~t-*)ED_Lxp+eOqb(=Wu0H4)gYJ{enYvP;3`-?q*_tick#ZW_(_@kV;5^Mb$x zdA!V|Pc;4)u~2lS2Nf^V_VzeUq%aw?35IH!h@~~z802OhZ?CL7__4%4B=|uaEuU7% zaYkOPx6H67MB8CaWvz8Aw-%dl`=CieZy;BSwe;SapXh*t`unR?`a`t@>pz*4_~gv_ zo!ptJIRz)0rLvt*-#_|`;Va1pLKa>|YAVH{R))(a>%_gT@mZv)Hi92`%J&V{u?TITqc`doIW^^BI-@yp2o@ptX zRtmo?R$jCnX4_BQA&L6dy-q>gAqt@5M|+a!-h$$iZQqV*2;hb>aN)bL%U>j}v{+ZR z6+L*!_V`4$*fN@;o z6bMt*-`cTP=BJ!=gGgP3tSXXg&QOTfO!cg@vk<|5Vl4Gdy;G`%1NLh@n$^yRT*`5T z_}TSeY9h0w7bt#%yHCwh@#nrCmz-=ytc~KDXw*tSB+r{A8YYBKpZ74qLxhaJnIn`7yppM&iQR z&M%BO^W+z`e9fip&ayslY(=sJ3|{1IW(*i8WuH4Z(OOB>*#QcQ)(BUAqltcY$=?T{69sCL$Z#QrG2X?kH zY`mXujVTVTCnMw^GLq>9pe@~Z8?q1LDSLE7_94P7)Zl>eWw10X`yFXknJZnKiHA+a zcFeQHnhFrXe+A=H?Rw*!XQ-j7<7U5p_oP&KCp)ZW8B2>g6kgPNg*M&FzWRs?cjEqc`2c%IQ6t{z-ZrNQEi(5xL|#M$ENr)&jMpu zFi}Vk_ua8GweWr`WC{^1esKw&LORgLB}sMUHNz6Sry0%gaymkkW#sFg`%~+s^$CEL z&l;rvm@oN!#2F?QW2srqK^t2^z=zq4@nzcQL%AqzWSaAdh6q9pGlbQBSHpaQJH;ys z!_z$2B!LGhjgDEVWIX%H+bm0FqVTPnKpalMOJTCg;8xzc_IxV(JG=xBO^1f(k9P}x zoh|d2mzMy1L>F}leR?XvjaCUaI(a)((i5pP9 z#={D>`nHd__q@iKb$&nHZ+hL1J8-t2v9VZ3;8Sii9<}Un_*+xvpnqzYfbTdR#^$xa z+*Sxb1;8MY#qkjLRIbD=JWk7UM%TNlWHP#EKNWi#GfwBzoW~lf=#;a}f{f^rzUQ{o zhuOZR#9P4PCB;#t8u3Q&>6ZCG(IuMYXyS6Z)he6HV;+jjH8Sgg^UfQc+`*#3?ntka zIn*Mm_t&0s7IqlgBa^83*m{I#T?wxTc)xHv6bn`VK7HuP@{ng03M0 z?96QZZ}1*FS7n9Vp!|}IDzGub_rsxtAh}-)i9H=Eq{DD8=#xw%;mE90;%lWZ7LHU# zG38$_z2{t>B-0lm;y2t!ZohkTe>-g^#FqZ3J@2LB^6niLokccsb)5De(Lq8HxNY%g zT8T3iH#S=*EDmo!M&41s)gxTT5vw6hAAsUXpSh%E!gsnwaSJIHJ~Q}2C!gx*&0P9h z-O`nJ4OC22oJz)=1TDFEpFD(TzVAlDIE1`=qrKc>zxEWI9veg#`T&TK8?W4M+^Y3O zjSl)A6VkbT!X`1?^hv4xyzIBRTM^aB9g%_17Pjh&y-3MM^|G^EOXv37PN9G<3&y6P z_4_&N46gat&=-UTmRyU~i$R2lh;~0s$GiPtN9(ZV>rltgTxMx@{Ib18-rPM-}t=m4O$8BZ?4N&QpnB#zoIW zoLVN{V%;88nc-ibTeF&})Zl#NJ#QJdUh+jQ^w|{im@x&lqs4KIpJsCDfhxt~t=a=A zy3)aesD3fi2c+)vDX9(#7{oG~^xgT-Fe*<9gdQ}OV2AK!8HtBbnB#~mmCaQny<73M zRQQUV!r(5a^!4wnHA9!s|4PgVnaK{Z>ui29AY7J0{EDL*q_F76lrE*QY7N0QKf!te zLhXrO8_1kKJUFxUw~?JJnIU5%RTze;C??+XATQJD32C>FU!cP-a191G&tA^5J$8Jm z-T+fQoe?>ueP-z1PK&cyUlgV#OPfvb0|EE>s-1XalbM9~H(SvX6+MCcPj^GN7*49R zn9!HKCc(^(Ec$#!VPzVMXdhW#J`}<%duppG$N1>`XY$7>CO;cuO`8EX$uzf@DfyU- zX=Pl>cGmd74>MQO%0`2MU}4(|Ynf?b87YB*o~P^4n!eqWteW(&`3HRCul}SHJ@pVe zRROVXiYIZ^y$3(-MDGuDxg>wLpIz%9qCzxv*m2$T9X3~|GNGQ;lMQt*4So0B()h_e zx!2&_$(6eK6}`~y<(m%%Pb0r+>(byN>8bmPk^CUj!+It1#?-Ow*!Z_(yFEMKp+KRV zaq+yo*X$mDU-SIZQ~L<3hu&iu`x8%&^^DJ8cgaTmfo@${p{|<6*(#sz#Qsy{jZ%sx zvxM?x+S2SCKW+8vJoCZ?9hIs2q87c%+7ldHj@w_jkN263eC9HX`X_UdzVjB?)y{Sr zq`~R~%QiR#pD(eMrh!}0vSlVA@+k?@Q$9wOi_>*yI;UF^Sj^5!*Sfj=YF-of_|-WJ za|oziW(lgt(ZC=XdcdocKB;Cw?2Ut*3%7PL#obVFdbpnDD=k*f+vh~wIYG39XI zMYjunT8Lrik$&&m7l)7gA0K>`$B_IU9QD^L(=Cnrl)-Tb^#!KPrDw%ilagq!R<}xZ z({c;#kM51fQpX}#Q;$F5*4fZzrmEE2Y+vgjeqcmZT$rF^G5$0ywBIZ-cuxDda*20Y zw>^J6dKNRBlre7PvmuJ)3n>E5$>x&@s07kuHtL>HSEDSvzHei?gCB=+SV4K0WmgQoDavHLZPfL1PMc^@eC6>og92EGVHvh z2XxB{HmUA+ly13%tKbRdH&mu5%^A3t4U#e|K2e=KHaMx?y}Wp(g+u2T`B1-97>5cR z4YLRb@2Q_Y%l^=U=Hg)}bqH@(Ai4nsE5Cr6MAY~%j|dWDt>~k{R(5veeVnA zu{5Z*#g41TE;B@Gf+7ks5oY4gzrIYaPxW(pf0g5|Wnt3RmRdcyq^z!&^=vr!a(e4Q zvuafy?fstx3<;j-mFT(kxqH=gr|>pz4A^xi*z4wxjBa{TQnYoOTbgLPH1R_#guz!% z^BH-swBq_57V)#jp1r^*9@NZimt`WM)bP-ZnHS~Z0cnPw=>PeH==!@EM$T?|rpslT zv7p9iu2qvj7z4a}t7+Tc|9XQh=4J5={g)Ng9D+QSQiGNqS#>W$tGxYGedci8NgLK) z*CHcF$GL*VyQA>c$cW^?to;8U37hD#VR+I#`^HK|nCjHzcyHd^LFk^6D@0EPD<%ft z$-~7*(-|U(^2n}lIVytPobfdxcAwDMPD|Y)BYCQS$FF%{G3H!H8RWjy6s2Z9jUbyn zAoC83P};r~v(qkKHS@?$oLy?{ITl|O{>bq!dm-JQ&2jAR5$0Jx{Ng;=%{0sJ;fuUKX6_fezg0f%a=cV`0^^g4q>MJlb5Xq?{JMXx$;E zR;?@(c3qzs?@G?i@+e?nZFlYTrCerPrXc=jh8UPT>$d~4l&q+@Unxyu_LQ%b$wr>k zuIYXc$-RRYOHx)OJYK>QR$8mS&}qGyW}5a`bZ|8$XQ>aX&L^xIUr0m6GWr{)$fj^3 zKBeuq`$PQKP(H5^-eIqsRJZY>t*Wk zbU*gN!v;B9xI|Psn*2P+YnwuK;cM+H%myL^)Nayb{J-AixF4|DdN=ttw@-ZKoYlTT zyyk3Y3)_wiUpCPs?S6ea82egQMN4JwDP;B05o%jxEAq-H3VSO+UxTF`qroaz`J!Xv z__Ot#A(ODsz)ilp1BZh{g&Ko7dPjTcBsw{zse-$rj*%Q$^eg=Q_G;$YpkOTzllCgM zY?~ujpZGzU_PJ%l!Nzk@?R!s1?*pp9u)oCprcq>uef$z*%w(Z;f|gl*C{R@2(7UdI ziuBBMu6Cv}&=T9I+Tuv1@e39;3BON)gGhfI3uWynU!c+N!T!MNmXx7$ljVty!F0Vm z!w}aTqx|4Hs1#4mTWUSiP?O0;!lq3%(H40&I@j4HF{h3bm|?oZAn0JJ-Jdt6vQX7a zJzqIWO}E-t++raiAq!i){#Ct@`=RQSjlr+0zqw7^=pqcg{$Kh2s3G20xT1f?)8*;P zy>UuhfA5e9j+YDUdMo7Kbh}3a{pHSMqv6!-3u_`4*hk29Jgvt?faj=pMt6lZsdoRp zgxOJ^w=m16Gh-V3p&Y(}PDyqAb6QgnU4u$46$V*iyH9=tI+Sgz9vR-r{)-MuDLf6Ss?$f^c+CgZ+`S}Z;AVxv&inNoI z;~PF!rw0qZs4VQ`t%&Nc&Lb%#R5=6IL4*28zSKQ#O2N7&+klV$&V3Dlb`(7+^AsdQ zUyJ6oG<~!@Y~u1|fA1M3hpTDgQldn}Z}&!DF{y#y2i1cjW@*YgUBO9s)ou6``Fm@z zx}%Zi9o!b<1$?6iEtGXX)8fc|0>{hMx}&FGt5Yy8-dr$KE6bygC~7Np3^1(Twe`Rh z_b0od<5uUA-u3Vw!;e=5f56pU<^B)PR- zvKr0~5(P&&1AQ0fM|rXs8a$sZVoQ+-Qmj>59<6=J9Qgfqd2NWQhbKYaM*p0QLRVT*2XZ-yQ<|bz~s9|;6{p@I>QFIP4mJ$92#Ex*?kag_X$9w)BQYRFApP2^0 z?ZN?{wkc{$VVa7ik0-SmeUx?Pj+NIfs!iR$h`mlz&Wj!Y6uncI+9ovR>u7><5lm5i-!(|aTMZy#%_%;5wK%yx$iT;e0^vWq@9 zJT6U7o9iqApsGSgEnqIA@?fBM+wi)L2Wndq1d3FdZ%C@&UTBLZ1%==GHYUzaCZ+(_ z`TI@U4p5G7!5iF4=5CGQ;}phy{_Pz>(=yBf5Sx+d9L^cy1`Pcr2$J^^Z)i{K9?kSo zy=~9t7#hNHA2$um>X1g>;%0VT!SLN}x1H53_g%t5;_H+j2UboHAIbf6_`otEJz+UW z^nv6S`4_u`&!tn`^cCFxWTo2);;&E2`lf;>PMDdsy7oS)+!d3e^%n2$W}X7sf2L#t z4rc!CfW(Oq6kr{oE{@|8R(GcBD`8w01sMBl@h9qWeC zZ-D00=P`j0mjk82WI8BB{3q+(VeHvLr9C7o;>Rk@?$&syht8buUiLR8is z+sVZH3GLUbVWwddL~)=_)kdR8xG=qB4DTJX4p;vQGEcWTv`|iba|>K*dh)DOFw%HfARq zLkq5<)rBvPA%j;&^rFqmJA_Yr8pwop%U&iR5pOxZDmx_y%y7IenAFHa+bICw4+#wE=}G``=!+aP+sCo<6D z<`3Tz>(~UjPu&{E&ee*4yWiy4dOilZ7&ry87q zXDbfH#P@Z-XT& z4%ri*p4J|65c?$C~TG8gwF)ZnC#5mS_^nT73>Rb z{jk+tv)!)SucY(EAP{E8%iPWs;F;IX-P{Qc^uEs~LfTJcvO5;TRJ;`@u3Z|O#km+@ zOz0|!$*O)?alrJm*d2D|iVbyKbnov(Fl!Tzd!4&nGWtS9vw8GF>$3-KmhOZLbAli= zBYbl}#+07magSb8{o9(Rx(FS2=k;Y%2KGFQ>Dpy;vM0-vUIc3alnbN9fIzW?IqM^- zmYqBqpUu(s8^3D^(KW}a?bsZ{wy6CxaP66rK}n(Xaa2C$63namAJ_KPO`5=6aG9l) zH@@*H!=x;6@FGTUoihv2+&frBc4uDmY&}(6ACbp0u6{A)pR! z`O6Y}!DF^4$8a?@XF@osZv3@{+waYR{AQ7edIyIe@JD9tZ`L-pwq&LPB=E39e-965 zM9VN?mT`9oQP0o0Hw26^4tU#xtb-W~-5pj!n~q3})%M8P>fVL5w&l7^CerybX;xe* zZI=fXd9EX9I>x2WY>th!s~OyF1I>}Qb;=?XjHh9#;`Ar+^HSblNVT2r2zxc{QLWqY z8W8E?gae<*F-quE2J?~njzVHEHqlNMSeJ%cy;p9@;f$E#-OUc6^HU2-3@J*nZP>;iX}Y?8*ksv9U7(tdBrB|cb(Es_ zokQ%^(a+t3`MC(4YcErOT5V~PkgGgwC@AU73sDz#Li(Y>@^rTkofE-1D^JIK?~@T3 z+v(&~Dc#VWDf$U#MYR$q^FgC;^0|fHMwGXswN4LYit=f(a143J%lW8s9F1U8op*Ex zy4>R3q)pNi_L{eRYga_vauqFp3_m$qB^E~x@v3@ue44*Difqr?#TObY-D8^n{d_N# zTX!r2Q+FJfjnvhGBTL}Ou|891%CXc@R(QL+-)JwdCu*0Io)c4|cFOnmEnFlX?D3@2 z{2c>y41vv192dc}CIXCJxvR<7B}nDaJH&1(OtGJCr|Ar-(^X9$KS59=1E2MafXOeP z=4Eq*$u}YRLq=RZdnQ&HJ04F>4@FL7ye_Alon-zO4`Ar@K*XQ!q~-Rpd&mf)i;@2V zA>I{g_zqHF?Hx3lz-87RaK-lL#5iHqaeZj*JI$%!e(~C^(RZ<=?!UA5OGm$z#M*GK zUg}{?-{f?g4%#@R<*(b&rM^G0BI(#qKhNBh5)*%lIZVWBwt~HPoGT#6UA@_%3_!*a zHW?`x%e2WPg?RQfxrC^L75VAHkA-__9{h!p%yrhXjy-@?Ug)=$(OU%^e>)ACW!)h? zM6inDpz}gi(sZ8SGQHfL$CIC0l$vHNi)f-)lo~$SR_C#t5Q*{`AhnCz? zV9$R{K)RNvis)9Xo|6y5rast!RCP4>O}%SHmLM1~7E7Pi`>Hyc(*$)5=rN|IGeO_4OYd}96?5YE5- zy=^M2PpI^U=yG8{LWf`sE4^~+uVhO;L}!8YzXG zSa`COO*&ELHKJ4*r@fUw& z69DX!wGmZ2DQY>%g7ueth8l3i#}_uMcNmn;^zu)-H-(TR9%Chzi{DygxpnKBCwvl< zkWKiM&rj=jaY?hVkCmuwlD_1fI^YpahJRgYujI@XSP{&lUEwIArQ%^6&?`4`!wF_% z{)HXbHgc1MZ5=yvplf{a5D}4)Y6vK|Cq(Gpy`iQJN`<2Ze^0oImvo$|bMhc=V+ftp zn;*SHIJI_GV0;s~AH?bPc(c1-X)#I9yT+TAc*XdU;NGb1jBPLxjJ$}?dnbe7u<Ges7qA>B9ml+cx9E0FO%~hrn7&Rj_6Y_Ds>-XDJ5yF>QGk6zvVEAB=MPd(ODBt zrClkrl^}~a65!broQ;&H)}8G{Y7X=VnNp8L>EXmt+RUZcN4ubR$gu)(*l*5=%egy{ z(KKQBnpD5?Hz5IS8f(JWP(t1#GgkUzR6^r;o4oB`l37PYr>vDb-D*ic_A0hHDyzKC z@)3UD_p0_P$1ScFa4E3MEH}5e7_nX-3eIZflixL+U-^( zN3-TXA0@8A!WB5d_&0peO9zkJ@Y6ZgTlw^JVrAQJu7Cfhtoy^?qDPG$$Bh}`OvU3| zZju&3fowt8EWIK;ZM}FN<-AofEzAqrNMTn~sb@md1=f9EbFBN;4+}Fy$4rk3Yw6S? z(Wf#?bYN_ab^jeyO%W<{qDQ7j-h8`4V>tU(p#KV$P$=IBEbMPcURB zsCvGk)e>2vi;5FkiB+4#=(zFlD*jk$OYDlKCIgWIS=%*N#TSK}OykRs6LX{bMPF4) zVrZGR)Ta$PoM`{o5XvP~TpzuZ@ z+slqw#JVTKZ=k7fkDe zU;f^|{ozoVVjmp~C{*P((V&Ygb^L37%|2=-xmO!S2 zhU4u&DvS8zb|e&&v3vlizUs=GC~D<+RmbZL%%JoHtt;xZZt2{jG5s!sOa1t$`s_98 zuxMJN-T1xX7dgXmmX3pIcKOm6@I96iO@Abh;{LMz#=S_9UwHrFK;B@bv+~;9j$iHk z?l$_miCM9#MQ_iD{XaSbkX?ODcYtg(go~BMJY>Iy@!;XZ2OTV1I7p(@XR#DTW=GHOu*g>f6^FCx`>I#!6IEd=&2Do|on3*c% zs(5=^%LA_oc84pVjrVv#O`O4Jhu_X90Pe;6!_iNbGfs>fo?9Pml!EuqKJe#nUQF;I z6!GyQ;d>>kS#Ar)R&XEO&3{Z`se8Do)5dFt>t>z(d7Ro4y^U@Id|vpgTJC4rf(++I z{di2%V|oW=^AveyQ|UCn^JDi!XJM@2^dk`3=}c&-w3RDfYxu{~{@JvnPe^*zpxvl{)GkUHGlCVsiam)eW?>-;&M=#(nOO`rq=W*&i-4ZQPzN~ z5^iQ~cBn@2=o|zNhKG1WxM5G_C4RB>{_8oJuS{3y_5aZfR5N%{o?6OS0ps}43D3GS zxeQa+7a^B|wEm(KbwxNXF7A<^C*?m*(4QEFu?3n2RrKpKGJy-PV7fL~cRC_&{1fRw z{VhtP=8eAX`fdF*$guFrKUCTkyy!k{g`Jdw&YKBs8fT`$N!J+*Od4Vepe0o@`kk1jBs{j#;s7DE* zqDf=Q(YmT+Sdh^r@L_^gXg|^WdhruhRxznV#NvNJ*3$SHnoeU^%u&4>RAOalU-;?& z&mK`x8L=nvyle_WVXju7uDWj}NE%^Jnl6G!C>kctRlLJVm}06lwl9^9B=Bcr>i}o> zZNt{c8vyQ=r^#?nfsB@coeT)#uNPH~93CTpZ9o=qTL{&H|48QBqIt>aEEFLcKHNM>pSq+Ix- zl24`p8G69xklWr^9ia3kLAgr&0?`@%BShNbqL2@gT}3yr_ub4Kv!OhgNoyp> z6uza?V;G2RJXTdzb#M@Y_85mt?nS4BGD}#Ia;AzmAa|xm@m%O`&$l5Eb|^ft9X8{i z1IW1})O$@Xm^J&G@3fSobNe__0!xIzgie72(p6kiR)3xCGUPzzn*C;@s^dMzvj-5d z4!8l{+SYmB6)Cf8nT4Ws$v14n0VLoaYSr#;n&eqXP;<}4%zI^GSW6u;L2?O^aK(TO zb>@(vbx^Rge(#Few|$wc#*;{X#W=W5^h zt1olrE-K`Q%C>uPSw&||{{83ee*y!jzlC8J?6ll)wr>QbFUSo$;>M1CT^m0DWHOF$ z3W(&RVIHz|e*89*PWQZ`YzAa%uWbLiR`xZ{uKUSUdJ^)3*7MBg@!QZjz}X=-{+XTO z7MinLE&6Q@bs3FH&?w&RH)FxObFSc@9x2guc7qA)QC;by<}_@*iUP9$V)OF!?&&wE ze9MU^7-%=j(^0$8r2&5fKoXUpZFXJJNFH zUR=df`yQ;)hB~+a+9r;TGQ3)_aCLxovkp{dnOGMcdv}Aj7QoFn@@UgpwJTtPfYebJ z)PC~PUFLyk2!dJ^b?<2GCa>%Mh855dA5fAag@9rL#Wj*EwS;0Uh>Dkp5p=eJ0fOAu z6GI?Qg@Oi|KmHy{ID-lXjuJ~}5J{t!;~4jbw%C=bDd#$~#7&^(_$X?3|HTsPncBs! zBz;7PGl;^(<$x+rokK(94gTbWDqq#)A3iG3yalWXVmBG&BC-7t1#(E)qk0bP`Lk;* z`odK!u^NVed72g=L?Nk8)D37@RGlN;Fi=f&1Mm*+I7k_c;OW_RKEkSZj*Kw6p|e*u zP#@m(Jl_zrEP5UbC%i)4Yi?gU0sgeO_r6s4Y{%LeWQsk}Pp-d9%J{8+uu76LvIvO8 zYC-UiT!TU)fP#1-5xxi5XZJqEv*x+-I;;$`1ID32gRnUT+`CDi!9C-p;pR!+CB7%> z-0`TWLa(AM=9OBG3v<=0ny{v&eA{UfVFhYG`hfUudGRI5k0|Z^%wa@^;0Vet9x-)r{+ET2r4gP{ zTbEaUKJi)1?~sUUTSAE??6NvdzIVe)1+Zs$fLBsdt=K~Ax9P=qxg-9$yVUje2#9NON7jA28M@&?SSU^W7XC-$R?gpbLncYn^lac^(oj+sCmqX zm5deQ*HOi3-gt`}Mu~X1$2*@~(AXC*F8?~^M;2GEnx7yK5`Aw`?Ej%uJ<*P5g8CXn z=~}4!Q>KA&Qc!iq!7GA~VKsi@GDU;0~g@C{l7^68zSlzQWzY5EQ?e8lafza*l-J-&NS{h2&KrO zs#Oqc5%!=qqqOY@NRaM85<7r>L6SkL0xojb!hRIBrvutJQXf3>?&v6TPQ$kt*I)^I zXFG`X$Z+%yeiTo*E-2vsOy@uqY7bvrM~(DZQD=!kOLz@uASf?|TjxtaAVFpQ7Ywkw z)pn;y>4yNTy2lP`&g_3;%|LC?uJ~A(?ck$4D4(8Ly}OjS*Kh6ruD&T$q#9)@U5B_YxfE((oRyogC?aH#^!jQF05~?G)gFr}o z?33t^uZbLQuyqQ3{BHK^2E#oCII297eqyk_#c%=R#s_>HAJ<#_cE-mol9?Ssdzvv3 zBoehz+@`gFx^6}g#S@n9$U9sT%zyfHGkfNNRv4uHP9=0|QcbHz*=GHO^X;)CN;gcy znmW~AK_$%LC1RidnmX0_REs~#Pju6`DLuoRXV&q;5@j)VnwaXFuEF%PAo~{HN8r~} zr3aK!LmW*wqMz_x2dqfDARrggzl0h%pz*R#NFGB%e((H@4$eni)J6qR0{!3D<~oG_3kJ%ArpeBP9w!_wBeIc5B=sHY)C($@@aT_QAM`czpNIfz zF&wU=m1nHc2z0-MTHSz~?=U6GGkHD?T-eLA*gBsicCBS(Rny8KpkrVFxy6aO^jWSz zBA1dpn26L0UnzUr@<&4-i$ah6NLgN9uEF`c;i7Xkg}!M|B|I}|WyA}$0|j3_lQN1{ zvN@+A^H5WB70eJgi(MJXf({^y0Vs29ERSH(bUSA|^dHwfUiKYrKdEil0swly~}Md6EuMRtCBE@HJv&R?niERN{@dsN6G9gpwIBcvjsc zT#$zxB8i%=7D)Ted`XKN9_e;!;~sbmDp?tZ$RExCa&>A@H7iHW$+b~nT;9bn4LUxY zog0h4wsi>4@_~o;yJ2msg^d8z9a%f69`yw^S79VnCeBBuL^ePM80%UW`^V)A_JL_N)5IG{kVWVH&EsTQ z7Z_)=Yt;Hfk%!ioE-{Kd`RkDqRIVAWmr-;Lzgq_REabR|J~BWF$|)VmekTUdvsfRz z3b#L>4hZZUqTy<9WqmG3mt7WQp*_*P?!WkMoijU@4ON7@=&^Xnp0Tm9yItH-7hb_& zxgKx*bt|17hOf%GxpHN)2ImTU|Ga_uE+6hN=qf?i@(U*-f zK$&0tHjnk{v(u=E)s8nP_mfn|)jAS5gdQr2yLp)^Ss5_JaG9@D{F0ixXhB4(1+P z=j?Dm%FN~H2?~cm9jr@^w_56e6qcUg-LFbau^lb3o{F(;|Kd`9UuF3oWG)g`F{!B1 zRteD1pc`&CdhVo}3&}-QFUW@j1*H{NHaAl0fokK5BzPr~T+LqMX|%}&+mh}Du&aJu zq3jDL`2`kn&SZ(#np!9n{ppoT2pzEA_t&q4X+iy|oEdDp`C4Se1I6SErj8deIIUJ( zSb7&SJ~)E(9Kz2a+C8G_k0B zV3Z{*dGKwj&bRRZRTz;SAXgdTGMxEtkmOi^ZJ%7`xA7JiWrhJPJ!!)9mWaD+37~M* zo64PF%Cx~mWqC{*(V%iNuh`gH{F6n5l3p?^1ZvRglL zGKN23vqRkiPxJs{0CDQOX+dp3=N6D4W7WR!i9kAtE)y9?0{L-p7~U9U*H!%rS+9Z; z&-)D|69{n~h?*J~pnQxjN^7X2=ZT)h1h$gpH35C7^y0mP(|?NXJy_Hu3L+JlkIY`%s}IUMl}C!nga3*(~080qOXLlpY2rx}3% zdh04=9X!$RW0sAhvVRAxQPy|X{}~kUCo+}=jz03YblDfEze<$;S50rg% zZlHOLdnj}^805r3K=bDyMM^z!`yyl&tbb7Aqz;St}ajrShc z>_EN$6wI=fRCS7`FBf`)3n+!h0x$Jk@WXEW@xjC8ZSo*02Bs&Lh+;K+xIx162~<&< zuL5gxrRnFz_F=GR<+ssNp~A>O3&Iu6m-rwtD-+TB^{K3P8L~$}*4ut-%8k3px`3Fpk_eZwY6q zoLDUyv8aqcfgaBoI@M6OVjA!GQr%Q610XOv*rZk!P5?Uj7NF+!>jc94ldGx!TJ=BV zx!>KX8*jZ{xq-^5j;sY$?cbU$>pkW1ZUBY#=uQPtxFNU+!S%EH!ocu}j6aYxnwidk zQoO2MrM3(0g?+i{NJ6N~&;UX_oX7&I?l+PQ{lk$V&oXJfC2CpAS8jspzw!U0)th9! zZ)lU!RfdNnyJf#~;Ky--!r_yWU!OEUI{*ir2kvm3H3}uKL)`>wZZ70WowXdV;6s(r z-qZ;VC8=-UVbg$(|JU<_8@7^Z@;sdFX1Hsb7UWgDTN3F~C-@i92?n z0BrwTLj0+zfSCQ`j#(z{awN=JFKSi?B5ZI3Kkg5CWvsHyUjT`HWnnJ8RNTk$WFP9L z8GnVV>Z|HFt%lOc-~iOopV0RjHO2T&Dlc(dZfmiYmPV4utKM`t?mVan(ab#c^1?S> zVe0)fr76!)7zFVUbxT130f9OcR(bYq7h~BKlsypzOyOCXR(u!ULr2#lqQJ__`~@)R z>pldxZzXM^q5*&;pY)x|oK654$K9NEP_~}2Gvo=W%D)|$D+Tqz7GJP#Ilb^d`9RE6 zd;4s^u`Kx|a3ggALpDB&cHRkG9;pMR(tqV?t3nlu;d-s-H6#ey*V0ab0L#~C4|UQG zneJc47k0|@_!`ejq}SRPJI4FWAUCoCIIZ?ln9F*xm%;VB!t+;jP#eD7Z3LRB^~;SY zE}UP4vV!vQgGT)!>eSBj)*!0!iP8PSMz|OV5P+2qoCnXtS(8KQWs&(+pjfdks812b ztkNgwN5X>hH5wiV7+PS7FGBh0{-P9okcYq8$Vk4qid(S7t=)Ps93Uiq$lz zm;IN2otOLsb4*|;#M9hC8Fp(zR6G!r$}kz6SK}R_0kM!=-4W}0h(f^yu)zk-#s3|g zN zz=tmr$^_k-hQ$*67APsTtYUaAwbekhXVAQOjN&xI9|UpU0J(Wk3>0>Y9Wp9A>;G}-tOZ6@bT&|n^`l{&4ByE z5YsQ8keQV97zfe^Fv%Zq?1p3t(*vN!7!4CO_FeW1I>*2WpeP4G<}~{kq@9E;On`ua zgg8sUIy z-eLSGRSUACr^9QEsF>h3B+xmDMIDi1_o_^w67k?VfTBTq4mzU|bekVm`j5|S+%p?( z25Ab8ut7&=s6T7EAn4J!0Mm%ReTnXZyGRcX7AQSaSuy`h0Kj7GkpC}iwFpM?KaM?}eO+C5E;y~8=wg2y`rZcY3tGVkP<0nFsHUKx zSQMrn&Smo%GE<%X|L@QDH+sH@uIf`9;LrbCL$4ucI3QXGHX;RZ{`oj-4Q)CB7=v3F z7dm$zb9xeXf5Ga)qi_ve;NfemyI+KZNf&pNspf)X9z)m02p}7S?Uyb{tz1F@Dk12X z8pY2qknh3;P|XXhyIlZilxV<-l9-0i4>~99Ks1NjUr!WVkQ3Cg0)$!-AM>HJYyJS3 zZ3jEM0+TJ7B1lsSa6XU=_P-1+P^313OQ9D|U4-vgkaLDMWfvMbLKWEgJ+_ys37Lj; zNpONC=HUD1t}Dtd=&VA;ktWZzn7I67XB{*0E=Kzsat?n6Tw32>stUyF-D7cdhz;xj6E z#PVw9@&)@515{iH@84GR4M_WvqTquD5R6SxryU1X^JV>-AJA33529KB)=)GoKw0sx ztpc1`pZ;6zNhAUx%K~8R5Oiy+nEx5Z0MKHVWAz19YsR%Ze1P1NY=@%f09pi*Hls@y zq?SQW9e@Jn_RImZN{~rO0QQ+G?SI+l4e~~upqPJ7ZIfq3j*T#qIvS!&Vjqum_>LmR zBTr>0N7++z{jpI6vM{BUWyak~32ES-m%#sDy-ovvai=pYV;shs%zWpcA3fpe@Zt;= zW#hwcx^ur?LPUFh$>6= z!?-t_LJK1VGLQdjD0SAo(69KTyEk%dUA=j3u01^|CAgsjNrDqJlB+_Wf){vB!MaA+ zoX>Z06!TW~bP4VA^8-Y@L{wQzUkMU`%vUSAo0Z)%jQ0KcPt!cFv5J`;i-0^zf(}G1 z2r6QEK$d=%vpJssHuL2& zXo|{pxbVaC50+r>1k9KR!ytX1#o4EpSQ~GNIX{<7K=PRA{7`!F-$sL&5|p_e*9{KzF?6}`*RecAucJ!)pkYi3lb9Pcrme?5q~lNb5(lFfNlxrBJ0K!CKMHo7N&{?qqx z$&jHHN03KrL~AG;F+(6CCP~7s%?{A&dm)0Byp(N`K4+?Y0UbO4d%=90|M*qN!b`I5p=#kmn*E5FwVbA!;S;{m&kTv zNmx=5qeE0E=JF^k?xibqBqUCmIGB*fuETIDhLr+&&M(V#nhnCvj10WK zs?$sf94cZzfh^IjSB;+kcFy%h6=h2*Qibqy)(K9dl%S!U`GCvK1iA;x)F|~u2SH3; zE!h3>*)A=ee{hlxXi~A*G^FoAOp}gO|K5NLGO{n4JWrLr(aH$E^UM8zZC!h8OK}wL zs*_GhnoT#MD4PW%WXKvOyP9b?Y%JWB23rtmnxNMs9!aHl@y=Rw5zCNZ2)8sWSjQd} zQOZA+cqE>kODs*WNxc@r@!vW3xBl7u(qGRx-*>+6OK#d~5Tk2rS`Oe*wE<)LJvAXO z!7a?&Et{3PRpfV}j=?8e!L%tM+n?z1HCyO*YXE3B)PEtB#MPVlGvrvB+9ujhBp+Mp zCA-xQ{#Y8WLt78x_9QfWWCjs8N8(q>OqbmkN{it>4p>UJnJJ}99A(HCtN>R(WmaBXYP$WS5U-=i0LmmtA=5={r8p$C1gQDJA`Fg0z7x7Tiy}qBdygq5?3Y7I}i7(R9F0Wzx9*!c$SGcxPeNUZnQC_Y&R+$aG2GC zl>4Nx*MxDWEd^1{>i82NtzMPrEAY<=7;u4Q**&A~uTzo0;f+iIF=_SB2u#Eu8b}{{ zznsY?37@Qv5s2kM+-PD19Y)$AtSnn$L9`Z^h#UDUQap9O0==82E&_|V$?^_=Pi+pU zf4k}&aULgtNpG?bVw!`?1Lp^SYEKr~)yz0NETmj{4t@)hbwG>`#m3_iz6Zu6e|Xx| z1h@YUp-)!o)*G{gJEjG1X=ES^5?bURA`<#n0<;$wcG608?fl+4a!hMXU%f%HjiQ(Q zgoMTq#@zygkh)WKJL$~BiYYq9kALGASIxRLIFIykpi=h97wIh{faPnIp^eo7ag2XP zNROkFN_2v#o^7omRyC|E-hEH7wU7d1YLDDF)I(n3sY{bb15yrHS{I^MxtBEMEjR?wB#4eGxy$D6_j-C4k- zm*YwD);}e|2AfY`ZbkEF`egFUf literal 0 HcmV?d00001 diff --git a/docs/src/language-server/configure-a-client.md b/docs/src/language-server/configure-a-client.md index 32e4aa8a..aab5a8ca 100644 --- a/docs/src/language-server/configure-a-client.md +++ b/docs/src/language-server/configure-a-client.md @@ -10,15 +10,19 @@ The language server requests settings via the [`workspace/configuration` message You can also configure the language server by sending the [`workspace/didChangeConfiguration` message](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#workspace_didChangeConfiguration). -While settings keys are documented with dot-notation, the shape of the settings is a nested object. +While settings keys are documented with dot-notation, the shape of the settings is a nested object. Your editor may be able to translate from dot-notation to a properly formated object, but not every editor allows this. -For example, while we may document `"somesass.loadPaths": []` (and write it this way in `settings.json` in Code), the actual shape of the settings object sent to the server looks like this. +For example, while we may document `"somesass.scss.workspace.loadPaths": []` (and write it this way in `settings.json` in VS Code), the actual shape of the settings object sent to the server looks like this. ```json { "settings": { "somesass": { - "loadPaths": [] + "scss": { + "workspace": { + "loadPaths": [] + } + } } } } diff --git a/docs/src/language-server/existing-clients.md b/docs/src/language-server/existing-clients.md index dd2e5b8d..153e1fc5 100644 --- a/docs/src/language-server/existing-clients.md +++ b/docs/src/language-server/existing-clients.md @@ -4,6 +4,6 @@ In addition to the extension for Visual Studio Code and VSCodium, these are editors with ready-configured clients, maintained by the community. + - [Helix](./helix.md) - [Neovim](./neovim.md) - diff --git a/docs/src/language-server/getting-started.md b/docs/src/language-server/getting-started.md index 463d887f..4f345ebf 100644 --- a/docs/src/language-server/getting-started.md +++ b/docs/src/language-server/getting-started.md @@ -2,7 +2,9 @@ Some Sass is a language server using the [Language Server Protocol (LSP)][lsp]. -The language server is [published independently to npm][npm], and can be used with any editor that has an LSP client. The server is designed to run alongside the [VS Code CSS language server](https://github.com/hrsh7th/vscode-langservers-extracted). +The language server is [published independently to npm][npm], and can be used with any editor that has an LSP client. + +It's recommended you turn off any existing language server that handles SCSS and Sass. You may also use this language server to handle CSS. Its feature set matches that of `vscode-css-language-server`. ## Getting started @@ -18,9 +20,19 @@ Then start the language server like so: some-sass-language-server --stdio ``` -**Options** +Tweak the log level by using the `--loglevel` argument, or by using the `somesass.workspace.logLevel` setting. Available loglevels are: + +- silent +- fatal +- error +- warn +- info (default) +- debug +- trace -`--debug` – runs the development build of the language server, helpful to get more context if the server crashes +```sh +some-sass-language-server --stdio --loglevel debug +``` ## Configure your editor's client diff --git a/docs/src/language-server/helix.md b/docs/src/language-server/helix.md index 55eb2fa7..ed17a316 100644 --- a/docs/src/language-server/helix.md +++ b/docs/src/language-server/helix.md @@ -8,16 +8,26 @@ You can configure new language servers in [`.config/helix/languages.toml`](https [language-server.some-sass-language-server] command = "some-sass-language-server" args = ["--stdio"] -config = { somesass = { loadPaths = [] } } +# see https://wkillerud.github.io/some-sass/user-guide/settings.html for all available settings +config = { somesass = { workspace = { loadPaths = [] } } } [[language]] name = "scss" language-servers = [ - { name = "some-sass-language-server" }, - { name = "vscode-css-language-server" }, + { name = "some-sass-language-server" } ] ``` The language server will start once you open an SCSS file. +You can also use it for CSS. + +```toml +[[language]] +name = "css" +language-servers = [ + { name = "some-sass-language-server" } +] +``` + At time of writing there doesn't seem to be a grammar for Sass indented available in Helix. diff --git a/docs/src/user-guide/settings.md b/docs/src/user-guide/settings.md index 5a33823f..5eb562d4 100644 --- a/docs/src/user-guide/settings.md +++ b/docs/src/user-guide/settings.md @@ -4,140 +4,176 @@ This document describes the settings available in Some Sass. ## Recommended settings -These are the recommended settings: +These are the recommended settings if you're just getting started. ```jsonc { // Recommended if you don't rely on @import - "somesass.suggestFromUseOnly": true, + "somesass.scss.completion.suggestFromUseOnly": true, + "somesass.sass.completion.suggestFromUseOnly": true, - // Optional, if you get suggestions from the current document after namespace.$ (you don't need the $ for narrowing down suggestions) + // Optional, if you get suggestions from the current document after namespace.$ (you don't need to type the $ for narrowing down suggestions) "editor.wordBasedSuggestions": false, } ``` -### About word-based suggestions +### Going all in on Some Sass -When you get completion suggestions and type `namespace.$`, Visual Studio Code treats `$` as a fresh start for suggestions. It will start matching any variable in the current document. There are two ways to get around this: +If you don't need language features for [Less](https://lesscss.org/) and don't rely on the built-in formatter, we recommend turning off the built-in CSS/SCSS/Less language extension in Visual Studio Code. For formating we recommend [Prettier](https://prettier.io/). -1. Turn off word-based suggestions by setting `"editor.wordBasedSuggestions": false`. -2. Don't type the `$` when you write the variable name, let completions fill it out for you. +Some Sass has all the features of the built-in language extension, though they are turned off by default. -With the second approach you can keep word-based suggestions turned on. +Once you turn off the built-in language features you can configure Some Sass to handle both CSS and Sass for you. This way you get the best experience without Some Sass and VS Code getting in each others way. -## Settings reference - -These are the settings you can use to tune Some Sass. - -### Code suggestion - -#### Only include suggestions from used modules - -If your project is on the modern module syntax (`@use` and `@forward` instead of `@import`), you may want to turn -on this setting. - -With this setting turned on, Some Sass will only suggest variables, mixins and functions from the namespaces that are -in use in the open document. This setting will be turned on by default at some point after `@import` becomes CSS-only. - -- JSON key: `somesass.suggestFromUseOnly`. -- Default value: `false`. - -#### Suggest variables, mixins, and functions from the open document - -Visual Studio Code has built-in suggestions for variables, mixins and functions created in the open document. - -By default Some Sass will _not_ send suggestions for the same symbols. -If you prefer the suggestions from Some Sass (for instance if you use SassDoc), you can opt in by turning on this setting. -There will unfortunately be duplicates. - -- JSON key: `somesass.suggestAllFromOpenDocument` -- Default value: `false`. - -#### Suggestion style - -Mixins with `@content` SassDoc annotations and `%placeholders` get two suggestions by default: - -- One without `{ }`. -- One _with_ `{ }`. This one creates a new block, and moves the cursor inside the block. - -If you find this noisy, you can control which suggestions you would like to see: - -- All suggestions (default). -- No brackets. -- Only brackets. This still includes other suggestions, where there are no brackets to begin with. - -#### Decide when function suggestions should kick in - -Suggest functions after the specified symbols when in a string context. -For example, if you add the `/` symbol to this setting, then `background: url(images/he|)` -could suggest a `hello()` function (`|` in this case indicates cursor position). - -- JSON key: `somesass.suggestFunctionsInStringContextAfterSymbols`. -- Default value: `" (+-*%"`. +#### How to turn off the built-in language feature -#### Suggest values for CSS properties +1. Go to the Extensions tab and search for `@builtin css language features`. +2. Click the settings icon and pick Disable from the list. +3. Click Restart extension to turn it off. -By default, Some Sass triggers property value completion after selecting a CSS property. -Use this setting to disable this behavior. +![Screenshot showing the Extension tab filtered to show the css language features](../images/usage/settings-built-in.png) -An example would be accepting a suggestion for `display:` and immediately see suggestions like -`inline-block` for the value. +#### How to turn on Some Sass language features -Note that for SCSS this only applies if `somesass.suggestAllFromOpenDocument` is true, -which is not the case by default in VS Code. -Use `scss.completion.triggerPropertyValueCompletion` to configure the feature built in -to VS Code. +Now that you disabled the built-in language features you need to turn on those language features in Some Sass. -- JSON key: `somesass.triggerPropertyValueCompletion`. -- Default value: `true`. - -### Workspace - -#### Load paths - -A list of paths relative to the workspace root where the language server should look for stylesheets loaded by `@use` and `@import`. `node_modules` is always included. - -This feature can also be seen referred to as `includePaths`. - -Note that you will have to [configure your Sass compiler separately](https://sass-lang.com/documentation/cli/dart-sass/#load-path). - -As an example, say you have a stylesheet `shared/my-lib/variables.scss` and would like to import it as `my-lib/variables` in your other stylesheets. - -Add this to your settings and restart Visual Studio Code. +Open your user settings JSON and paste this configuration. You may want to restart VS Code to make sure the changes apply. ```json { - "somesass.loadPaths": ["shared/"] + "somesass.css.codeAction.enabled": true, + "somesass.css.colors.enabled": true, + "somesass.css.completion.enabled": true, + "somesass.css.definition.enabled": true, + "somesass.css.diagnostics.enabled": true, + "somesass.css.foldingRanges.enabled": true, + "somesass.css.highlights.enabled": true, + "somesass.css.hover.enabled": true, + "somesass.css.links.enabled": true, + "somesass.css.references.enabled": true, + "somesass.css.rename.enabled": true, + "somesass.css.selectionRanges.enabled": true, + "somesass.css.signatureHelp.enabled": true, + "somesass.css.workspaceSymbol.enabled": true, + + "somesass.scss.codeAction.enabled": true, + "somesass.scss.colors.enabled": true, + "somesass.scss.colors.includeFromCurrentDocument": true, + "somesass.scss.completion.enabled": true, + "somesass.scss.completion.includeFromCurrentDocument": true, + "somesass.scss.definition.enabled": true, + "somesass.scss.diagnostics.enabled": true, + "somesass.scss.diagnostics.lint.enabled": true, + "somesass.scss.foldingRanges.enabled": true, + "somesass.scss.highlights.enabled": true, + "somesass.scss.hover.enabled": true, + "somesass.scss.links.enabled": true, + "somesass.scss.references.enabled": true, + "somesass.scss.rename.enabled": true, + "somesass.scss.selectionRanges.enabled": true, + "somesass.scss.signatureHelp.enabled": true, + "somesass.scss.workspaceSymbol.enabled": true } ``` -In a different stylesheet you can then get `shared/my-lib/variables.scss` like this: - -```scss -@use "my-lib/variables"; -``` - -#### Exclude files or folders - -List of [micromatch](https://github.com/micromatch/micromatch) patterns for directories that are excluded when scanning. - -- JSON key: `somesass.scannerExclude`. -- Default value: `["**/.git/**", "**/node_modules/**", "**/bower_components/**"]`. - -#### Adjust scanner depth - -Depending on your project size, you may want to tweak this setting to control how many files are included. - -- JSON key: `somesass.scannerDepth`. -- Default: `30`. - -#### Stop scanner from following links +## Settings reference -`@deprecated` +You can configure similar settings for both SCSS, Sass (indented) and CSS. There are also some settings that apply to the workspace regardless of syntax. + +### SCSS + +For brevity the ID column omits the `somesass.scss` prefix. For example, to use the setting `codeAction.enabled` use the ID `somesass.scss.codeAction.enabled`. + +| Id | Description | Default | +| ------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | +| `codeAction.enabled` | Enable or disable all code actions. | `true` | +| `colors.enabled` | Enable or disable all color decorators. | `true` | +| `colors.includeFromCurrentDocument` | Compatibility setting for VS Code. By default the built-in SCSS server shows color decorators for variables declared in the current document. To avoid duplicates Some Sass will not show them unless you opt in. | `false` | +| `completion.enabled` | Enable or disable all completions (IntelliSense). | `true` | +| `completion.includeFromCurrentDocument` | Compatibility setting for VS Code. By default the built-in SCSS server shows suggestions for variables, mixins and functions declared in the current document. To avoid duplicates Some Sass will not suggest them unless you opt in. | `false` | +| `completion.suggestFromUseOnly` | If your project uses the new module system with @use and @forward, you may want to only include suggestions from your used modules. | `false` | +| `completion.mixinStyle` | Controls the style of suggestions for mixins. Options are `"all"`, `"nobracket"` (only show suggestions without brackets) and `"bracket"` (where brackets are suggested, don't suggest without brackets). | `"all"` | +| `completion.triggerPropertyValueCompletion` | By default, Some Sass triggers property value completion after selecting a CSS property. Use this setting to disable this behavior. | `true` | +| `completion.completePropertyWithSemicolon` | Insert semicolon at end of line when completing CSS properties. | `true` | +| `definition.enabled` | Enable or disable Go to Definition. | `true` | +| `diagnostics.enabled` | Enable or disable all diagnostics (deprecation, errors and lint rules). | `true` | +| `diagnostics.deprecation.enabled` | Enable or disable deprecation diagnostics (strike-through). | `true` | +| `diagnostics.lint.enabled` | Enable or disable all linting. | `false` | +| `diagnostics.lint.*` | For the available lint rules and what they do, see the [VS Code docs for CSS and SCSS lint settings](https://code.visualstudio.com/docs/languages/css#_customizing-css-scss-and-less-settings) | | +| `foldingRanges.enabled` | Enable or disable folding ranges. | `false` | +| `highlights.enabled` | Enable or disable highlights. | `false` | +| `hover.enabled` | Enable or disable all hover information. | `true` | +| `hover.documentation` | Show property and value documentation in CSS hovers. | `true` | +| `hover.references` | Show references to MDN in CSS hovers, Sass documentation for Sass built-in modules and SassDoc for annotations. | `true` | +| `links.enabled` | Enable or disable the link provider that lets you click an import and open the file. | `false` | +| `references.enabled` | Enable or disable Find all references. | `true` | +| `rename.enabled` | Enable or disable Rename. | `true` | +| `selectionRanges.enabled` | Enable or disable selection ranges. | `false` | +| `signatureHelp.enabled` | Enable or disable signature help. | `true` | +| `workspaceSymbol.enabled` | Enable or disable workspace symbol. | `true` | + +### Sass indented + +For brevity the ID column omits the `somesass.sass` prefix. For example, to use the setting `codeAction.enabled` use the ID `somesass.sass.codeAction.enabled`. + +| Id | Description | Default | +| ------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | +| `codeAction.enabled` | Enable or disable all code actions. | `true` | +| `colors.enabled` | Enable or disable all color decorators. | `true` | +| `completion.enabled` | Enable or disable all completions (IntelliSense). | `true` | +| `completion.suggestFromUseOnly` | If your project uses the new module system with @use and @forward, you may want to only include suggestions from your used modules. | `false` | +| `completion.mixinStyle` | Controls the style of suggestions for mixins. Options are `"all"`, `"nobracket"` (only show suggestions without brackets) and `"bracket"` (where brackets are suggested, don't suggest without brackets). | `"all"` | +| `completion.triggerPropertyValueCompletion` | By default, Some Sass triggers property value completion after selecting a CSS property. Use this setting to disable this behavior. | `true` | +| `definition.enabled` | Enable or disable Go to Definition. | `true` | +| `diagnostics.enabled` | Enable or disable all diagnostics (deprecation, errors and lint rules). | `true` | +| `diagnostics.deprecation.enabled` | Enable or disable deprecation diagnostics (strike-through). | `true` | +| `diagnostics.lint.enabled` | Enable or disable all linting. | `true` | +| `diagnostics.lint.*` | For the available lint rules and what they do, see the [VS Code docs for CSS and SCSS lint settings](https://code.visualstudio.com/docs/languages/css#_customizing-css-scss-and-less-settings) | | +| `foldingRanges.enabled` | Enable or disable folding ranges. | `true` | +| `highlights.enabled` | Enable or disable highlights. | `true` | +| `hover.enabled` | Enable or disable all hover information. | `true` | +| `hover.documentation` | Show property and value documentation in CSS hovers. | `true` | +| `hover.references` | Show references to MDN in CSS hovers, Sass documentation for Sass built-in modules and SassDoc for annotations. | `true` | +| `links.enabled` | Enable or disable the link provider that lets you click an import and open the file. | `true` | +| `references.enabled` | Enable or disable Find all references. | `true` | +| `rename.enabled` | Enable or disable Rename. | `true` | +| `selectionRanges.enabled` | Enable or disable selection ranges. | `true` | +| `signatureHelp.enabled` | Enable or disable signature help. | `true` | +| `workspaceSymbol.enabled` | Enable or disable workspace symbol. | `true` | + +### CSS + +For brevity the ID column omits the `somesass.css` prefix. For example, to use the setting `codeAction.enabled` use the ID `somesass.css.codeAction.enabled`. + +| Id | Description | Default | +| ------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------- | +| `codeAction.enabled` | Enable or disable all code actions. | `false` | +| `colors.enabled` | Enable or disable all color decorators. | `false` | +| `completion.enabled` | Enable or disable all completions (IntelliSense). | `false` | +| `completion.triggerPropertyValueCompletion` | By default, Some Sass triggers property value completion after selecting a CSS property. Use this setting to disable this behavior. | `true` | +| `completion.completePropertyWithSemicolon` | Insert semicolon at end of line when completing CSS properties. | `true` | +| `definition.enabled` | Enable or disable Go to Definition. | `false` | +| `diagnostics.enabled` | Enable or disable all diagnostics (deprecation, errors and lint rules). | `false` | +| `diagnostics.deprecation.enabled` | Enable or disable deprecation diagnostics (strike-through). | `false` | +| `diagnostics.lint.enabled` | Enable or disable all linting. | `false` | +| `diagnostics.lint.*` | For the available lint rules and what they do, see the [VS Code docs for CSS and SCSS lint settings](https://code.visualstudio.com/docs/languages/css#_customizing-css-scss-and-less-settings) | | +| `foldingRanges.enabled` | Enable or disable folding ranges. | `false` | +| `highlights.enabled` | Enable or disable highlights. | `false` | +| `hover.enabled` | Enable or disable all hover information. | `false` | +| `hover.documentation` | Show property and value documentation in CSS hovers. | `false` | +| `hover.references` | Show references to MDN in CSS hovers, Sass documentation for Sass built-in modules and SassDoc for annotations. | `false` | +| `links.enabled` | Enable or disable the link provider that lets you click an import and open the file. | `false` | +| `references.enabled` | Enable or disable Find all references. | `false` | +| `rename.enabled` | Enable or disable Rename. | `false` | +| `selectionRanges.enabled` | Enable or disable selection ranges. | `false` | +| `signatureHelp.enabled` | Enable or disable signature help. | `false` | +| `workspaceSymbol.enabled` | Enable or disable workspace symbol. | `false` | +| `customData` | A list of relative file paths pointing to JSON files following the [custom data format](https://github.com/microsoft/vscode-css-languageservice/blob/master/docs/customData.md). Some Sass loads custom data on startup to enhance its CSS support for CSS custom properties (variables), at-rules, pseudo-classes, and pseudo-elements you specify in the JSON files. The file paths are relative to workspace and only workspace folder settings are considered. | `[]` | -If you don't want Some Sass to follow `@import`, `@use` or `@forward` links you can turn this setting off. -This will limit functionality, and is not recommended. This setting will be removed at some point -after `@import` becomes CSS-only. +### Workspace -- JSON key: `somesass.scanImportedFiles`. -- Default: `true`. +| Id | Description | Default | +| ------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------- | +| `somesass.workspace.loadPaths` | A list of paths relative to the workspace root where the language server should look for stylesheets loaded by `@use` and `@import`. `node_modules` is always included. Note that you will have to [configure your Sass compiler separately](https://sass-lang.com/documentation/cli/dart-sass/#load-path). | `[]` | +| `somesass.workspace.exclude` | List of glob patterns for directories that are excluded in the initial scan for Sass files. Files in the exclude list will still be processed if referenced by `@use`, `@forward` and `@import` (for example a depencendy you use from `node_modules`). | `["**/.git/**", "**/node_modules/**"]` | +| `somesass.workspace.logLevel` | Control how much gets logged to the Output window. | `"info"` | diff --git a/packages/language-server/src/server.ts b/packages/language-server/src/server.ts index c6a02333..3b17082f 100644 --- a/packages/language-server/src/server.ts +++ b/packages/language-server/src/server.ts @@ -158,8 +158,8 @@ export class SomeSassServer { ); settings.workspace.workspaceRoot = workspaceRoot; - if (settings.logLevel) { - this.log.setLogLevel(settings.logLevel); + if (settings.workspace.logLevel) { + this.log.setLogLevel(settings.workspace.logLevel); } if (ls) { diff --git a/vscode-extension/package.json b/vscode-extension/package.json index df5508e6..e40bad4b 100644 --- a/vscode-extension/package.json +++ b/vscode-extension/package.json @@ -1,1044 +1,1261 @@ { - "name": "some-sass", - "displayName": "Some Sass", - "description": "Full support for @use and @forward, including aliases, prefixes and hiding. Rich documentation through SassDoc. Workspace-wide code navigation and refactoring.", - "version": "3.9.3", - "private": true, - "publisher": "SomewhatStationery", - "license": "MIT", - "engines": { - "vscode": "^1.86.0" - }, - "icon": "icon.png", - "homepage": "https://wkillerud.github.io/some-sass/", - "repository": { - "type": "git", - "url": "https://github.com/wkillerud/some-sass" - }, - "keywords": [ - "scss", - "sass", - "sassdoc", - "autocompletion", - "intellisense", - "refactor" - ], - "categories": [ - "Programming Languages" - ], - "activationEvents": [ - "onLanguage:css", - "onLanguage:scss", - "onLanguage:sass", - "onLanguage:vue", - "onLanguage:svelte", - "onLanguage:astro", - "onCommand:_somesass.applyExtractCodeAction" - ], - "capabilities": { - "virtualWorkspaces": true - }, - "browser": "./dist/browser-client.js", - "main": "./dist/node-client.js", - "contributes": { - "languages": [ - { - "id": "sass", - "aliases": [ - "Sass", - "sass-indented" - ], - "extensions": [ - ".sass" - ], - "configuration": "./languages/sass.configuration.json" - } - ], - "grammars": [ - { - "language": "sass", - "scopeName": "source.sass", - "path": "./languages/sass.tmLanguage.json" - } - ], + "name": "some-sass", + "displayName": "Some Sass", + "description": "Full support for @use and @forward, including aliases, prefixes and hiding. Rich documentation through SassDoc. Workspace-wide code navigation and refactoring.", + "version": "3.9.3", + "private": true, + "publisher": "SomewhatStationery", + "license": "MIT", + "engines": { + "vscode": "^1.86.0" + }, + "icon": "icon.png", + "homepage": "https://wkillerud.github.io/some-sass/", + "repository": { + "type": "git", + "url": "https://github.com/wkillerud/some-sass" + }, + "keywords": [ + "scss", + "sass", + "sassdoc", + "autocompletion", + "intellisense", + "refactor" + ], + "categories": [ + "Programming Languages" + ], + "activationEvents": [ + "onLanguage:css", + "onLanguage:scss", + "onLanguage:sass", + "onLanguage:vue", + "onLanguage:svelte", + "onLanguage:astro", + "onCommand:_somesass.applyExtractCodeAction" + ], + "capabilities": { + "virtualWorkspaces": true + }, + "browser": "./dist/browser-client.js", + "main": "./dist/node-client.js", + "contributes": { + "languages": [ + { + "id": "sass", + "aliases": [ + "Sass", + "sass-indented" + ], + "extensions": [ + ".sass" + ], + "configuration": "./languages/sass.configuration.json" + } + ], + "grammars": [ + { + "language": "sass", + "scopeName": "source.sass", + "path": "./languages/sass.tmLanguage.json" + } + ], "configuration": [ - { - "title": "SCSS", - "properties": { - "somesass.scss.codeAction.enabled": { - "type": "boolean", - "scope": "resource", - "default": true, - "description": "Enables or disables all code actions." - }, - "somesass.scss.colors.enabled": { - "type": "boolean", - "scope": "resource", - "default": true, - "description": "Enables or disables all color decorators." - }, - "somesass.scss.colors.includeFromCurrentDocument": { - "type": "boolean", - "scope": "resource", - "default": false, - "description": "Compatibility setting for VS Code. By default the built-in SCSS server shows color decorators for variables declared in the current document. To avoid duplicates Some Sass will not show them unless you opt in." - }, - "somesass.scss.completion.enabled": { - "type": "boolean", - "scope": "resource", - "default": true, - "description": "Enables or disables all completions (IntelliSense)." - }, - "somesass.scss.completion.includeFromCurrentDocument": { - "type": "boolean", - "default": false, - "description": "Compatibility setting for VS Code. By default the built-in SCSS server shows suggestions for variables, mixins and functions declared in the current document. To avoid duplicates Some Sass will not suggest them unless you opt in." - }, - "somesass.scss.completion.suggestFromUseOnly": { - "type": "boolean", - "default": false, - "description": "If your project uses the new module system with @use and @forward, you may want to only include suggestions from your used modules." - }, - "somesass.scss.completion.mixinStyle": { - "type": "string", - "default": "all", - "description": "Controls the style of suggestions for mixins and placeholders.", - "enum": ["all", "nobracket", "bracket"], - "enumItemLabels": ["All", "No brackets", "Only brackets"], - "enumDescriptions": [ - "Show all suggestions", - "Only show suggestions without brackets", - "Where brackets are suggested, omit duplicates without brackets" - ] - }, - "somesass.scss.completion.triggerPropertyValueCompletion": { - "type": "boolean", - "scope": "resource", - "default": true, - "description": "By default, Some Sass triggers property value completion after selecting a CSS property. Use this setting to disable this behavior." - }, - "somesass.scss.completion.completePropertyWithSemicolon": { - "type": "boolean", - "scope": "resource", - "default": true, - "description": "Insert semicolon at end of line when completing CSS properties." - }, - "somesass.scss.definition.enabled": { - "type": "boolean", - "scope": "resource", - "default": true, - "description": "Enables or disables Go to Definition." - }, - "somesass.scss.diagnostics.enabled": { - "type": "boolean", - "scope": "resource", - "default": true, - "description": "Enables or disables all diagnostics (deprecation, errors and lint rules)." - }, - "somesass.scss.diagnostics.deprecation.enabled": { - "type": "boolean", - "scope": "resource", - "default": true, - "description": "Enables or disables deprecation diagnostics (strike-through)." - }, - "somesass.scss.diagnostics.lint.enabled": { - "type": "boolean", - "scope": "resource", - "default": false, - "description": "Enables or disables all linting." - }, - "somesass.scss.diagnostics.lint.compatibleVendorPrefixes": { - "type": "string", - "scope": "resource", - "enum": ["ignore", "warning", "error"], - "default": "ignore", - "description": "When using a vendor-specific prefix make sure to also include all other vendor-specific properties." - }, - "somesass.scss.diagnostics.lint.vendorPrefix": { - "type": "string", - "scope": "resource", - "enum": ["ignore", "warning", "error"], - "default": "warning", - "description": "When using a vendor-specific prefix, also include the standard property." - }, - "somesass.scss.diagnostics.lint.duplicateProperties": { - "type": "string", - "scope": "resource", - "enum": ["ignore", "warning", "error"], - "default": "ignore", - "description": "Do not use duplicate style definitions." - }, - "somesass.scss.diagnostics.lint.emptyRules": { - "type": "string", - "scope": "resource", - "enum": ["ignore", "warning", "error"], - "default": "warning", - "description": "Do not use empty rulesets." - }, - "somesass.scss.diagnostics.lint.importStatement": { - "type": "string", - "scope": "resource", - "enum": ["ignore", "warning", "error"], - "default": "ignore", - "description": "Import statements can lead to sequential loading of CSS." - }, - "somesass.scss.diagnostics.lint.boxModel": { - "type": "string", - "scope": "resource", - "enum": ["ignore", "warning", "error"], - "default": "ignore", - "markdownDescription": "Do not use `width` or `height` when using `padding` or `border`." - }, - "somesass.scss.diagnostics.lint.universalSelector": { - "type": "string", - "scope": "resource", - "enum": ["ignore", "warning", "error"], - "default": "ignore", - "markdownDescription": "The universal selector (`*`) is known to be slow." - }, - "somesass.scss.diagnostics.lint.zeroUnits": { - "type": "string", - "scope": "resource", - "enum": ["ignore", "warning", "error"], - "default": "ignore", - "description": "No unit needed for zero." - }, - "somesass.scss.diagnostics.lint.fontFaceProperties": { - "type": "string", - "scope": "resource", - "enum": ["ignore", "warning", "error"], - "default": "warning", - "markdownDescription": "`@font-face` rule must define `src` and `font-family` properties." - }, - "somesass.scss.diagnostics.lint.hexColorLength": { - "type": "string", - "scope": "resource", - "enum": ["ignore", "warning", "error"], - "default": "error", - "description": "Hex colors must consist of 3, 4, 6 or 8 hex numbers." - }, - "somesass.scss.diagnostics.lint.argumentsInColorFunction": { - "type": "string", - "scope": "resource", - "enum": ["ignore", "warning", "error"], - "default": "error", - "description": "Invalid number of parameters." - }, - "somesass.scss.diagnostics.lint.unknownProperties": { - "type": "string", - "scope": "resource", - "enum": ["ignore", "warning", "error"], - "default": "warning", - "description": "Unknown vendor specific property." - }, - "somesass.scss.diagnostics.lint.validProperties": { - "type": "array", - "uniqueItems": true, - "items": { - "type": "string" - }, - "scope": "resource", - "default": [], - "description": "A list of properties that are not validated against the `unknownProperties` rule." - }, - "somesass.scss.diagnostics.lint.ieHack": { - "type": "string", - "scope": "resource", - "enum": ["ignore", "warning", "error"], - "default": "ignore", - "description": "IE hacks are only necessary when supporting IE7 and older." - }, - "somesass.scss.diagnostics.lint.unknownVendorSpecificProperties": { - "type": "string", - "scope": "resource", - "enum": ["ignore", "warning", "error"], - "default": "ignore", - "description": "Unknown vendor specific property." - }, - "somesass.scss.diagnostics.lint.propertyIgnoredDueToDisplay": { - "type": "string", - "scope": "resource", - "enum": ["ignore", "warning", "error"], - "default": "warning", - "markdownDescription": "Property is ignored due to the display. E.g. with `display: inline`, the `width`, `height`, `margin-top`, `margin-bottom`, and `float` properties have no effect." - }, - "somesass.scss.diagnostics.lint.important": { - "type": "string", - "scope": "resource", - "enum": ["ignore", "warning", "error"], - "default": "ignore", - "markdownDescription": "Avoid using `!important`. It is an indication that the specificity of the entire CSS has gotten out of control and needs to be refactored." - }, - "somesass.scss.diagnostics.lint.float": { - "type": "string", - "scope": "resource", - "enum": ["ignore", "warning", "error"], - "default": "ignore", - "markdownDescription": "Avoid using `float`. Floats lead to fragile CSS that is easy to break if one aspect of the layout changes." - }, - "somesass.scss.diagnostics.lint.idSelector": { - "type": "string", - "scope": "resource", - "enum": ["ignore", "warning", "error"], - "default": "ignore", - "description": "Selectors should not contain IDs because these rules are too tightly coupled with the HTML." - }, - "somesass.scss.diagnostics.lint.unknownAtRules": { - "type": "string", - "scope": "resource", - "enum": ["ignore", "warning", "error"], - "default": "warning", - "description": "Unknown at-rule." - }, - "somesass.scss.foldingRanges.enabled": { - "type": "boolean", - "scope": "resource", - "default": false, - "description": "Enable or disable folding ranges." - }, - "somesass.scss.highlights.enabled": { - "type": "boolean", - "scope": "resource", - "default": false, - "description": "Enable or disable highlights." - }, - "somesass.scss.hover.enabled": { - "type": "boolean", - "scope": "resource", - "default": true, - "description": "Enable or disable all hover information." - }, - "somesass.scss.hover.documentation": { - "type": "boolean", - "scope": "resource", - "default": true, - "description": "Show property and value documentation in CSS hovers." - }, - "somesass.scss.hover.references": { - "type": "boolean", - "scope": "resource", - "default": true, - "description": "Show references to MDN in CSS hovers, Sass documentation for Sass built-in modules and SassDoc for annotations." - }, - "somesass.scss.links.enabled": { - "type": "boolean", - "scope": "resource", - "default": false, - "description": "Enable or disable the link provider that lets you click an import and open the file." - }, - "somesass.scss.references.enabled": { - "type": "boolean", - "scope": "resource", - "default": true, - "description": "Enable or disable Find all references." - }, - "somesass.scss.rename.enabled": { - "type": "boolean", - "scope": "resource", - "default": true, - "description": "Enable or disable Rename." - }, - "somesass.scss.selectionRanges.enabled": { - "type": "boolean", - "scope": "resource", - "default": false, - "description": "Enable or disable selection ranges." - }, - "somesass.scss.signatureHelp.enabled": { - "type": "boolean", - "scope": "resource", - "default": true, - "description": "Enable or disable selection ranges." - }, - "somesass.scss.workspaceSymbol.enabled": { - "type": "boolean", - "scope": "resource", - "default": true, - "description": "Enable or disable selection ranges." - } + { + "title": "Workspace", + "properties": { + "somesass.workspace.loadPaths": { + "type": "array", + "items": { + "type": "string" + }, + "default": [], + "markdownDescription": "A list of paths relative to the workspace root where the language server should look for stylesheets loaded by `@use` and `@import`. `node_modules` is always included.\n\nNote that you will have to [configure your Sass compiler separately](https://sass-lang.com/documentation/cli/dart-sass/#load-path)." + }, + "somesass.workspace.exclude": { + "type": "array", + "items": { + "type": "string" + }, + "default": [ + "**/.git/**", + "**/node_modules/**" + ], + "description": "List of glob patterns for directories that are excluded when scanning." + }, + "somesass.workspace.logLevel": { + "type": "string", + "default": "info", + "enum": [ + "silent", + "fatal", + "error", + "warn", + "info", + "debug", + "trace" + ], + "description": "Control how much gets logged to the Output window." } - }, - { - "title": "Sass (Indented)", - "properties": { - "somesass.sass.codeAction.enabled": { - "type": "boolean", - "scope": "resource", - "default": true, - "description": "Enables or disables all code actions." - }, - "somesass.sass.colors.enabled": { - "type": "boolean", - "scope": "resource", - "default": true, - "description": "Enables or disables all color decorators." - }, - "somesass.sass.completion.enabled": { - "type": "boolean", - "scope": "resource", - "default": true, - "description": "Enables or disables all completions (IntelliSense)." - }, - "somesass.sass.completion.mixinStyle": { - "type": "string", - "default": "all", - "description": "Controls the style of suggestions for mixins and placeholders.", - "enum": ["all", "nobracket", "bracket"], - "enumItemLabels": ["All", "No brackets", "Only brackets"], - "enumDescriptions": [ - "Show all suggestions", - "Only show suggestions without brackets", - "Where brackets are suggested, omit duplicates without brackets" - ] - }, - "somesass.sass.completion.suggestFromUseOnly": { - "type": "boolean", - "default": false, - "description": "If your project uses the new module system with @use and @forward, you may want to only include suggestions from your used modules." - }, - "somesass.sass.completion.triggerPropertyValueCompletion": { - "type": "boolean", - "scope": "resource", - "default": true, - "description": "By default, Some Sass triggers property value completion after selecting a CSS property. Use this setting to disable this behavior." - }, - "somesass.sass.definition.enabled": { - "type": "boolean", - "scope": "resource", - "default": true, - "description": "Enables or disables Go to Definition." - }, - "somesass.sass.diagnostics.enabled": { - "type": "boolean", - "scope": "resource", - "default": true, - "description": "Enables or disables all diagnostics (deprecation, errors and lint rules)." - }, - "somesass.sass.diagnostics.deprecation.enabled": { - "type": "boolean", - "scope": "resource", - "default": true, - "description": "Enables or disables deprecation diagnostics (strike-through)." - }, - "somesass.sass.diagnostics.lint.enabled": { - "type": "boolean", - "scope": "resource", - "default": true, - "description": "Enables or disables all linting." - }, - "somesass.sass.diagnostics.lint.compatibleVendorPrefixes": { - "type": "string", - "scope": "resource", - "enum": ["ignore", "warning", "error"], - "default": "ignore", - "description": "When using a vendor-specific prefix make sure to also include all other vendor-specific properties." - }, - "somesass.sass.diagnostics.lint.vendorPrefix": { - "type": "string", - "scope": "resource", - "enum": ["ignore", "warning", "error"], - "default": "warning", - "description": "When using a vendor-specific prefix, also include the standard property." - }, - "somesass.sass.diagnostics.lint.duplicateProperties": { - "type": "string", - "scope": "resource", - "enum": ["ignore", "warning", "error"], - "default": "ignore", - "description": "Do not use duplicate style definitions." - }, - "somesass.sass.diagnostics.lint.emptyRules": { - "type": "string", - "scope": "resource", - "enum": ["ignore", "warning", "error"], - "default": "warning", - "description": "Do not use empty rulesets." - }, - "somesass.sass.diagnostics.lint.importStatement": { - "type": "string", - "scope": "resource", - "enum": ["ignore", "warning", "error"], - "default": "ignore", - "description": "Import statements can lead to sequential loading of CSS." - }, - "somesass.sass.diagnostics.lint.boxModel": { - "type": "string", - "scope": "resource", - "enum": ["ignore", "warning", "error"], - "default": "ignore", - "markdownDescription": "Do not use `width` or `height` when using `padding` or `border`." - }, - "somesass.sass.diagnostics.lint.universalSelector": { - "type": "string", - "scope": "resource", - "enum": ["ignore", "warning", "error"], - "default": "ignore", - "markdownDescription": "The universal selector (`*`) is known to be slow." - }, - "somesass.sass.diagnostics.lint.zeroUnits": { - "type": "string", - "scope": "resource", - "enum": ["ignore", "warning", "error"], - "default": "ignore", - "description": "No unit needed for zero." - }, - "somesass.sass.diagnostics.lint.fontFaceProperties": { - "type": "string", - "scope": "resource", - "enum": ["ignore", "warning", "error"], - "default": "warning", - "markdownDescription": "`@font-face` rule must define `src` and `font-family` properties." - }, - "somesass.sass.diagnostics.lint.hexColorLength": { - "type": "string", - "scope": "resource", - "enum": ["ignore", "warning", "error"], - "default": "error", - "description": "Hex colors must consist of 3, 4, 6 or 8 hex numbers." - }, - "somesass.sass.diagnostics.lint.argumentsInColorFunction": { - "type": "string", - "scope": "resource", - "enum": ["ignore", "warning", "error"], - "default": "error", - "description": "Invalid number of parameters." - }, - "somesass.sass.diagnostics.lint.unknownProperties": { - "type": "string", - "scope": "resource", - "enum": ["ignore", "warning", "error"], - "default": "warning", - "description": "Unknown vendor specific property." - }, - "somesass.sass.diagnostics.lint.validProperties": { - "type": "array", - "uniqueItems": true, - "items": { - "type": "string" - }, - "scope": "resource", - "default": [], - "description": "A list of properties that are not validated against the `unknownProperties` rule." - }, - "somesass.sass.diagnostics.lint.ieHack": { - "type": "string", - "scope": "resource", - "enum": ["ignore", "warning", "error"], - "default": "ignore", - "description": "IE hacks are only necessary when supporting IE7 and older." - }, - "somesass.sass.diagnostics.lint.unknownVendorSpecificProperties": { - "type": "string", - "scope": "resource", - "enum": ["ignore", "warning", "error"], - "default": "ignore", - "description": "Unknown vendor specific property." - }, - "somesass.sass.diagnostics.lint.propertyIgnoredDueToDisplay": { - "type": "string", - "scope": "resource", - "enum": ["ignore", "warning", "error"], - "default": "warning", - "markdownDescription": "Property is ignored due to the display. E.g. with `display: inline`, the `width`, `height`, `margin-top`, `margin-bottom`, and `float` properties have no effect." - }, - "somesass.sass.diagnostics.lint.important": { - "type": "string", - "scope": "resource", - "enum": ["ignore", "warning", "error"], - "default": "ignore", - "markdownDescription": "Avoid using `!important`. It is an indication that the specificity of the entire CSS has gotten out of control and needs to be refactored." - }, - "somesass.sass.diagnostics.lint.float": { - "type": "string", - "scope": "resource", - "enum": ["ignore", "warning", "error"], - "default": "ignore", - "markdownDescription": "Avoid using `float`. Floats lead to fragile CSS that is easy to break if one aspect of the layout changes." - }, - "somesass.sass.diagnostics.lint.idSelector": { - "type": "string", - "scope": "resource", - "enum": ["ignore", "warning", "error"], - "default": "ignore", - "description": "Selectors should not contain IDs because these rules are too tightly coupled with the HTML." - }, - "somesass.sass.diagnostics.lint.unknownAtRules": { - "type": "string", - "scope": "resource", - "enum": ["ignore", "warning", "error"], - "default": "warning", - "description": "Unknown at-rule." - }, - "somesass.sass.foldingRanges.enabled": { - "type": "boolean", - "scope": "resource", - "default": true, - "description": "Enable or disable folding ranges." - }, - "somesass.sass.highlights.enabled": { - "type": "boolean", - "scope": "resource", - "default": true, - "description": "Enable or disable highlights." - }, - "somesass.sass.hover.enabled": { - "type": "boolean", - "scope": "resource", - "default": true, - "description": "Enable or disable all hover information." - }, - "somesass.sass.hover.documentation": { - "type": "boolean", - "scope": "resource", - "default": true, - "description": "Show property and value documentation in CSS hovers." - }, - "somesass.sass.hover.references": { - "type": "boolean", - "scope": "resource", - "default": true, - "description": "Show references to MDN in CSS hovers, Sass documentation for Sass built-in modules and SassDoc for annotations." - }, - "somesass.sass.links.enabled": { - "type": "boolean", - "scope": "resource", - "default": true, - "description": "Enable or disable the link provider that lets you click an import and open the file." - }, - "somesass.sass.references.enabled": { - "type": "boolean", - "scope": "resource", - "default": true, - "description": "Enable or disable Find all references." - }, - "somesass.sass.rename.enabled": { - "type": "boolean", - "scope": "resource", - "default": true, - "description": "Enable or disable Rename." - }, - "somesass.sass.selectionRanges.enabled": { - "type": "boolean", - "scope": "resource", - "default": true, - "description": "Enable or disable selection ranges." - }, - "somesass.sass.signatureHelp.enabled": { - "type": "boolean", - "scope": "resource", - "default": true, - "description": "Enable or disable selection ranges." - }, - "somesass.sass.workspaceSymbol.enabled": { - "type": "boolean", - "scope": "resource", - "default": true, - "description": "Enable or disable selection ranges." - } + } + }, + { + "title": "SCSS", + "properties": { + "somesass.scss.codeAction.enabled": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Enable or disable all code actions." + }, + "somesass.scss.colors.enabled": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Enable or disable all color decorators." + }, + "somesass.scss.colors.includeFromCurrentDocument": { + "type": "boolean", + "scope": "resource", + "default": false, + "description": "Compatibility setting for VS Code. By default the built-in SCSS server shows color decorators for variables declared in the current document. To avoid duplicates Some Sass will not show them unless you opt in." + }, + "somesass.scss.completion.enabled": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Enable or disable all completions (IntelliSense)." + }, + "somesass.scss.completion.includeFromCurrentDocument": { + "type": "boolean", + "default": false, + "description": "Compatibility setting for VS Code. By default the built-in SCSS server shows suggestions for variables, mixins and functions declared in the current document. To avoid duplicates Some Sass will not suggest them unless you opt in." + }, + "somesass.scss.completion.suggestFromUseOnly": { + "type": "boolean", + "default": false, + "description": "If your project uses the new module system with @use and @forward, you may want to only include suggestions from your used modules." + }, + "somesass.scss.completion.mixinStyle": { + "type": "string", + "default": "all", + "description": "Controls the style of suggestions for mixins.", + "enum": [ + "all", + "nobracket", + "bracket" + ], + "enumItemLabels": [ + "All", + "No brackets", + "Only brackets" + ], + "enumDescriptions": [ + "Show all suggestions", + "Only show suggestions without brackets", + "Where brackets are suggested, don't suggest without brackets" + ] + }, + "somesass.scss.completion.triggerPropertyValueCompletion": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "By default, Some Sass triggers property value completion after selecting a CSS property. Use this setting to disable this behavior." + }, + "somesass.scss.completion.completePropertyWithSemicolon": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Insert semicolon at end of line when completing CSS properties." + }, + "somesass.scss.definition.enabled": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Enable or disable Go to Definition." + }, + "somesass.scss.diagnostics.enabled": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Enable or disable all diagnostics (deprecation, errors and lint rules)." + }, + "somesass.scss.diagnostics.deprecation.enabled": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Enable or disable deprecation diagnostics (strike-through)." + }, + "somesass.scss.diagnostics.lint.enabled": { + "type": "boolean", + "scope": "resource", + "default": false, + "description": "Enable or disable all linting." + }, + "somesass.scss.diagnostics.lint.compatibleVendorPrefixes": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "ignore", + "description": "When using a vendor-specific prefix make sure to also include all other vendor-specific properties." + }, + "somesass.scss.diagnostics.lint.vendorPrefix": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "warning", + "description": "When using a vendor-specific prefix, also include the standard property." + }, + "somesass.scss.diagnostics.lint.duplicateProperties": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "ignore", + "description": "Do not use duplicate style definitions." + }, + "somesass.scss.diagnostics.lint.emptyRules": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "warning", + "description": "Do not use empty rulesets." + }, + "somesass.scss.diagnostics.lint.importStatement": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "ignore", + "description": "Import statements can lead to sequential loading of CSS." + }, + "somesass.scss.diagnostics.lint.boxModel": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "ignore", + "markdownDescription": "Do not use `width` or `height` when using `padding` or `border`." + }, + "somesass.scss.diagnostics.lint.universalSelector": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "ignore", + "markdownDescription": "The universal selector (`*`) is known to be slow." + }, + "somesass.scss.diagnostics.lint.zeroUnits": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "ignore", + "description": "No unit needed for zero." + }, + "somesass.scss.diagnostics.lint.fontFaceProperties": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "warning", + "markdownDescription": "`@font-face` rule must define `src` and `font-family` properties." + }, + "somesass.scss.diagnostics.lint.hexColorLength": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "error", + "description": "Hex colors must consist of 3, 4, 6 or 8 hex numbers." + }, + "somesass.scss.diagnostics.lint.argumentsInColorFunction": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "error", + "description": "Invalid number of parameters." + }, + "somesass.scss.diagnostics.lint.unknownProperties": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "warning", + "description": "Unknown vendor specific property." + }, + "somesass.scss.diagnostics.lint.validProperties": { + "type": "array", + "uniqueItems": true, + "items": { + "type": "string" + }, + "scope": "resource", + "default": [], + "description": "A list of properties that are not validated against the `unknownProperties` rule." + }, + "somesass.scss.diagnostics.lint.ieHack": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "ignore", + "description": "IE hacks are only necessary when supporting IE7 and older." + }, + "somesass.scss.diagnostics.lint.unknownVendorSpecificProperties": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "ignore", + "description": "Unknown vendor specific property." + }, + "somesass.scss.diagnostics.lint.propertyIgnoredDueToDisplay": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "warning", + "markdownDescription": "Property is ignored due to the display. E.g. with `display: inline`, the `width`, `height`, `margin-top`, `margin-bottom`, and `float` properties have no effect." + }, + "somesass.scss.diagnostics.lint.important": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "ignore", + "markdownDescription": "Avoid using `!important`. It is an indication that the specificity of the entire CSS has gotten out of control and needs to be refactored." + }, + "somesass.scss.diagnostics.lint.float": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "ignore", + "markdownDescription": "Avoid using `float`. Floats lead to fragile CSS that is easy to break if one aspect of the layout changes." + }, + "somesass.scss.diagnostics.lint.idSelector": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "ignore", + "description": "Selectors should not contain IDs because these rules are too tightly coupled with the HTML." + }, + "somesass.scss.diagnostics.lint.unknownAtRules": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "warning", + "description": "Unknown at-rule." + }, + "somesass.scss.foldingRanges.enabled": { + "type": "boolean", + "scope": "resource", + "default": false, + "description": "Enable or disable folding ranges." + }, + "somesass.scss.highlights.enabled": { + "type": "boolean", + "scope": "resource", + "default": false, + "description": "Enable or disable highlights." + }, + "somesass.scss.hover.enabled": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Enable or disable all hover information." + }, + "somesass.scss.hover.documentation": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Show property and value documentation in CSS hovers." + }, + "somesass.scss.hover.references": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Show references to MDN in CSS hovers, Sass documentation for Sass built-in modules and SassDoc for annotations." + }, + "somesass.scss.links.enabled": { + "type": "boolean", + "scope": "resource", + "default": false, + "description": "Enable or disable the link provider that lets you click an import and open the file." + }, + "somesass.scss.references.enabled": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Enable or disable Find all references." + }, + "somesass.scss.rename.enabled": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Enable or disable Rename." + }, + "somesass.scss.selectionRanges.enabled": { + "type": "boolean", + "scope": "resource", + "default": false, + "description": "Enable or disable selection ranges." + }, + "somesass.scss.signatureHelp.enabled": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Enable or disable signature help." + }, + "somesass.scss.workspaceSymbol.enabled": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Enable or disable workspace symbols." + }, + "some-sass.trace.server": { + "type": "string", + "scope": "window", + "enum": [ + "off", + "messages", + "verbose" + ], + "default": "off", + "description": "Log the messages sent between VS Code and the Some Sass language server." } - }, - { - "title": "CSS", - "properties": { - "somesass.css.customData": { - "type": "array", - "markdownDescription": "A list of relative file paths pointing to JSON files following the [custom data format](https://github.com/microsoft/vscode-css-languageservice/blob/master/docs/customData.md).\n\nSome Sass loads custom data on startup to enhance its CSS support for CSS custom properties (variables), at-rules, pseudo-classes, and pseudo-elements you specify in the JSON files.\n\nThe file paths are relative to workspace and only workspace folder settings are considered.", - "default": [], - "items": { - "type": "string" - }, - "scope": "resource" - }, - "somesass.css.codeAction.enabled": { - "type": "boolean", - "scope": "resource", - "default": false, - "description": "Enables or disables all code actions." - }, - "somesass.css.colors.enabled": { - "type": "boolean", - "scope": "resource", - "default": false, - "description": "Enables or disables all color decorators." - }, - "somesass.css.completion.enabled": { - "type": "boolean", - "scope": "resource", - "default": false, - "description": "Enables or disables all completions (IntelliSense)." - }, - "somesass.css.completion.triggerPropertyValueCompletion": { - "type": "boolean", - "scope": "resource", - "default": true, - "description": "By default, Some Sass triggers property value completion after selecting a CSS property. Use this setting to disable this behavior." - }, - "somesass.css.completion.completePropertyWithSemicolon": { - "type": "boolean", - "scope": "resource", - "default": true, - "description": "Insert semicolon at end of line when completing CSS properties." - }, - "somesass.css.definition.enabled": { - "type": "boolean", - "scope": "resource", - "default": false, - "description": "Enables or disables Go to Definition." - }, - "somesass.css.diagnostics.enabled": { - "type": "boolean", - "scope": "resource", - "default": false, - "description": "Enables or disables all diagnostics (deprecation, errors and lint rules)." - }, - "somesass.css.diagnostics.deprecation.enabled": { - "type": "boolean", - "scope": "resource", - "default": true, - "description": "Enables or disables deprecation diagnostics (strike-through)." - }, - "somesass.css.diagnostics.lint.enabled": { - "type": "boolean", - "scope": "resource", - "default": true, - "description": "Enables or disables all linting." - }, - "somesass.css.diagnostics.lint.compatibleVendorPrefixes": { - "type": "string", - "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], - "default": "ignore", - "description": "When using a vendor-specific prefix make sure to also include all other vendor-specific properties." - }, - "somesass.css.diagnostics.lint.vendorPrefix": { - "type": "string", - "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], - "default": "warning", - "description": "When using a vendor-specific prefix, also include the standard property." - }, - "somesass.css.diagnostics.lint.duplicateProperties": { - "type": "string", - "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], - "default": "ignore", - "description": "Do not use duplicate style definitions." - }, - "somesass.css.diagnostics.lint.emptyRules": { - "type": "string", - "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], - "default": "warning", - "description": "Do not use empty rulesets." - }, - "somesass.css.diagnostics.lint.importStatement": { - "type": "string", - "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], - "default": "ignore", - "description": "Import statements can lead to sequential loading of CSS." - }, - "somesass.css.diagnostics.lint.boxModel": { - "type": "string", - "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], - "default": "ignore", - "markdownDescription": "Do not use `width` or `height` when using `padding` or `border`." - }, - "somesass.css.diagnostics.lint.universalSelector": { - "type": "string", - "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], - "default": "ignore", - "markdownDescription": "The universal selector (`*`) is known to be slow." - }, - "somesass.css.diagnostics.lint.zeroUnits": { - "type": "string", - "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], - "default": "ignore", - "description": "No unit needed for zero." - }, - "somesass.css.diagnostics.lint.fontFaceProperties": { - "type": "string", - "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], - "default": "warning", - "markdownDescription": "`@font-face` rule must define `src` and `font-family` properties." - }, - "somesass.css.diagnostics.lint.hexColorLength": { - "type": "string", - "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], - "default": "error", - "description": "Hex colors must consist of 3, 4, 6 or 8 hex numbers." - }, - "somesass.css.diagnostics.lint.argumentsInColorFunction": { - "type": "string", - "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], - "default": "error", - "description": "Invalid number of parameters." - }, - "somesass.css.diagnostics.lint.unknownProperties": { - "type": "string", - "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], - "default": "warning", - "description": "Unknown vendor specific property." - }, - "somesass.css.diagnostics.lint.validProperties": { - "type": "array", - "uniqueItems": true, - "items": { - "type": "string" - }, - "scope": "resource", - "default": [], - "description": "A list of properties that are not validated against the `unknownProperties` rule." - }, - "somesass.css.diagnostics.lint.ieHack": { - "type": "string", - "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], - "default": "ignore", - "description": "IE hacks are only necessary when supporting IE7 and older." - }, - "somesass.css.diagnostics.lint.unknownVendorSpecificProperties": { - "type": "string", - "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], - "default": "ignore", - "description": "Unknown vendor specific property." - }, - "somesass.css.diagnostics.lint.propertyIgnoredDueToDisplay": { - "type": "string", - "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], - "default": "warning", - "markdownDescription": "Property is ignored due to the display. E.g. with `display: inline`, the `width`, `height`, `margin-top`, `margin-bottom`, and `float` properties have no effect." - }, - "somesass.css.diagnostics.lint.important": { - "type": "string", - "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], - "default": "ignore", - "markdownDescription": "Avoid using `!important`. It is an indication that the specificity of the entire CSS has gotten out of control and needs to be refactored." - }, - "somesass.css.diagnostics.lint.float": { - "type": "string", - "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], - "default": "ignore", - "markdownDescription": "Avoid using `float`. Floats lead to fragile CSS that is easy to break if one aspect of the layout changes." - }, - "somesass.css.diagnostics.lint.idSelector": { - "type": "string", - "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], - "default": "ignore", - "description": "Selectors should not contain IDs because these rules are too tightly coupled with the HTML." - }, - "somesass.css.diagnostics.lint.unknownAtRules": { - "type": "string", - "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], - "default": "warning", - "description": "Unknown at-rule." - }, - "somesass.css.foldingRanges.enabled": { - "type": "boolean", - "scope": "resource", - "default": false, - "description": "Enable or disable folding ranges." - }, - "somesass.css.highlights.enabled": { - "type": "boolean", - "scope": "resource", - "default": false, - "description": "Enable or disable highlights." - }, - "somesass.css.hover.enabled": { - "type": "boolean", - "scope": "resource", - "default": false, - "description": "Enable or disable all hover information." - }, - "somesass.css.hover.documentation": { - "type": "boolean", - "scope": "resource", - "default": false, - "description": "Show property and value documentation in CSS hovers." - }, - "somesass.css.hover.references": { - "type": "boolean", - "scope": "resource", - "default": false, - "description": "Show references to MDN in CSS hovers." - }, - "somesass.css.links.enabled": { - "type": "boolean", - "scope": "resource", - "default": false, - "description": "Enable or disable the link provider that lets you click an import and open the file." - }, - "somesass.css.references.enabled": { - "type": "boolean", - "scope": "resource", - "default": false, - "description": "Enable or disable Find all references." - }, - "somesass.css.rename.enabled": { - "type": "boolean", - "scope": "resource", - "default": false, - "description": "Enable or disable Rename." - }, - "somesass.css.selectionRanges.enabled": { - "type": "boolean", - "scope": "resource", - "default": false, - "description": "Enable or disable selection ranges." - }, - "somesass.css.signatureHelp.enabled": { - "type": "boolean", - "scope": "resource", - "default": false, - "description": "Enable or disable selection ranges." - }, - "somesass.css.workspaceSymbol.enabled": { - "type": "boolean", - "scope": "resource", - "default": false, - "description": "Enable or disable selection ranges." - } + } + }, + { + "title": "Sass (Indented)", + "properties": { + "somesass.sass.codeAction.enabled": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Enable or disable all code actions." + }, + "somesass.sass.colors.enabled": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Enable or disable all color decorators." + }, + "somesass.sass.completion.enabled": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Enable or disable all completions (IntelliSense)." + }, + "somesass.sass.completion.mixinStyle": { + "type": "string", + "default": "all", + "description": "Controls the style of suggestions for mixins and placeholders.", + "enum": [ + "all", + "nobracket", + "bracket" + ], + "enumItemLabels": [ + "All", + "No brackets", + "Only brackets" + ], + "enumDescriptions": [ + "Show all suggestions", + "Only show suggestions without brackets", + "Where brackets are suggested, omit duplicates without brackets" + ] + }, + "somesass.sass.completion.suggestFromUseOnly": { + "type": "boolean", + "default": false, + "description": "If your project uses the new module system with @use and @forward, you may want to only include suggestions from your used modules." + }, + "somesass.sass.completion.triggerPropertyValueCompletion": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "By default, Some Sass triggers property value completion after selecting a CSS property. Use this setting to disable this behavior." + }, + "somesass.sass.definition.enabled": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Enable or disable Go to Definition." + }, + "somesass.sass.diagnostics.enabled": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Enable or disable all diagnostics (deprecation, errors and lint rules)." + }, + "somesass.sass.diagnostics.deprecation.enabled": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Enable or disable deprecation diagnostics (strike-through)." + }, + "somesass.sass.diagnostics.lint.enabled": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Enable or disable all linting." + }, + "somesass.sass.diagnostics.lint.compatibleVendorPrefixes": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "ignore", + "description": "When using a vendor-specific prefix make sure to also include all other vendor-specific properties." + }, + "somesass.sass.diagnostics.lint.vendorPrefix": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "warning", + "description": "When using a vendor-specific prefix, also include the standard property." + }, + "somesass.sass.diagnostics.lint.duplicateProperties": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "ignore", + "description": "Do not use duplicate style definitions." + }, + "somesass.sass.diagnostics.lint.emptyRules": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "warning", + "description": "Do not use empty rulesets." + }, + "somesass.sass.diagnostics.lint.importStatement": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "ignore", + "description": "Import statements can lead to sequential loading of CSS." + }, + "somesass.sass.diagnostics.lint.boxModel": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "ignore", + "markdownDescription": "Do not use `width` or `height` when using `padding` or `border`." + }, + "somesass.sass.diagnostics.lint.universalSelector": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "ignore", + "markdownDescription": "The universal selector (`*`) is known to be slow." + }, + "somesass.sass.diagnostics.lint.zeroUnits": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "ignore", + "description": "No unit needed for zero." + }, + "somesass.sass.diagnostics.lint.fontFaceProperties": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "warning", + "markdownDescription": "`@font-face` rule must define `src` and `font-family` properties." + }, + "somesass.sass.diagnostics.lint.hexColorLength": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "error", + "description": "Hex colors must consist of 3, 4, 6 or 8 hex numbers." + }, + "somesass.sass.diagnostics.lint.argumentsInColorFunction": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "error", + "description": "Invalid number of parameters." + }, + "somesass.sass.diagnostics.lint.unknownProperties": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "warning", + "description": "Unknown vendor specific property." + }, + "somesass.sass.diagnostics.lint.validProperties": { + "type": "array", + "uniqueItems": true, + "items": { + "type": "string" + }, + "scope": "resource", + "default": [], + "description": "A list of properties that are not validated against the `unknownProperties` rule." + }, + "somesass.sass.diagnostics.lint.ieHack": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "ignore", + "description": "IE hacks are only necessary when supporting IE7 and older." + }, + "somesass.sass.diagnostics.lint.unknownVendorSpecificProperties": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "ignore", + "description": "Unknown vendor specific property." + }, + "somesass.sass.diagnostics.lint.propertyIgnoredDueToDisplay": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "warning", + "markdownDescription": "Property is ignored due to the display. E.g. with `display: inline`, the `width`, `height`, `margin-top`, `margin-bottom`, and `float` properties have no effect." + }, + "somesass.sass.diagnostics.lint.important": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "ignore", + "markdownDescription": "Avoid using `!important`. It is an indication that the specificity of the entire CSS has gotten out of control and needs to be refactored." + }, + "somesass.sass.diagnostics.lint.float": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "ignore", + "markdownDescription": "Avoid using `float`. Floats lead to fragile CSS that is easy to break if one aspect of the layout changes." + }, + "somesass.sass.diagnostics.lint.idSelector": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "ignore", + "description": "Selectors should not contain IDs because these rules are too tightly coupled with the HTML." + }, + "somesass.sass.diagnostics.lint.unknownAtRules": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "warning", + "description": "Unknown at-rule." + }, + "somesass.sass.foldingRanges.enabled": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Enable or disable folding ranges." + }, + "somesass.sass.highlights.enabled": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Enable or disable highlights." + }, + "somesass.sass.hover.enabled": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Enable or disable all hover information." + }, + "somesass.sass.hover.documentation": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Show property and value documentation in CSS hovers." + }, + "somesass.sass.hover.references": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Show references to MDN in CSS hovers, Sass documentation for Sass built-in modules and SassDoc for annotations." + }, + "somesass.sass.links.enabled": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Enable or disable the link provider that lets you click an import and open the file." + }, + "somesass.sass.references.enabled": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Enable or disable Find all references." + }, + "somesass.sass.rename.enabled": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Enable or disable Rename." + }, + "somesass.sass.selectionRanges.enabled": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Enable or disable selection ranges." + }, + "somesass.sass.signatureHelp.enabled": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Enable or disable selection ranges." + }, + "somesass.sass.workspaceSymbol.enabled": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Enable or disable selection ranges." + } + } + }, + { + "title": "CSS", + "properties": { + "somesass.css.customData": { + "type": "array", + "markdownDescription": "A list of relative file paths pointing to JSON files following the [custom data format](https://github.com/microsoft/vscode-css-languageservice/blob/master/docs/customData.md).\n\nSome Sass loads custom data on startup to enhance its CSS support for CSS custom properties (variables), at-rules, pseudo-classes, and pseudo-elements you specify in the JSON files.\n\nThe file paths are relative to workspace and only workspace folder settings are considered.", + "default": [], + "items": { + "type": "string" + }, + "scope": "resource" + }, + "somesass.css.codeAction.enabled": { + "type": "boolean", + "scope": "resource", + "default": false, + "description": "Enable or disable all code actions." + }, + "somesass.css.colors.enabled": { + "type": "boolean", + "scope": "resource", + "default": false, + "description": "Enable or disable all color decorators." + }, + "somesass.css.completion.enabled": { + "type": "boolean", + "scope": "resource", + "default": false, + "description": "Enable or disable all completions (IntelliSense)." + }, + "somesass.css.completion.triggerPropertyValueCompletion": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "By default, Some Sass triggers property value completion after selecting a CSS property. Use this setting to disable this behavior." + }, + "somesass.css.completion.completePropertyWithSemicolon": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Insert semicolon at end of line when completing CSS properties." + }, + "somesass.css.definition.enabled": { + "type": "boolean", + "scope": "resource", + "default": false, + "description": "Enable or disable Go to Definition." + }, + "somesass.css.diagnostics.enabled": { + "type": "boolean", + "scope": "resource", + "default": false, + "description": "Enable or disable all diagnostics (deprecation, errors and lint rules)." + }, + "somesass.css.diagnostics.deprecation.enabled": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Enable or disable deprecation diagnostics (strike-through)." + }, + "somesass.css.diagnostics.lint.enabled": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Enable or disable all linting." + }, + "somesass.css.diagnostics.lint.compatibleVendorPrefixes": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "ignore", + "description": "When using a vendor-specific prefix make sure to also include all other vendor-specific properties." + }, + "somesass.css.diagnostics.lint.vendorPrefix": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "warning", + "description": "When using a vendor-specific prefix, also include the standard property." + }, + "somesass.css.diagnostics.lint.duplicateProperties": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "ignore", + "description": "Do not use duplicate style definitions." + }, + "somesass.css.diagnostics.lint.emptyRules": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "warning", + "description": "Do not use empty rulesets." + }, + "somesass.css.diagnostics.lint.importStatement": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "ignore", + "description": "Import statements can lead to sequential loading of CSS." + }, + "somesass.css.diagnostics.lint.boxModel": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "ignore", + "markdownDescription": "Do not use `width` or `height` when using `padding` or `border`." + }, + "somesass.css.diagnostics.lint.universalSelector": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "ignore", + "markdownDescription": "The universal selector (`*`) is known to be slow." + }, + "somesass.css.diagnostics.lint.zeroUnits": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "ignore", + "description": "No unit needed for zero." + }, + "somesass.css.diagnostics.lint.fontFaceProperties": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "warning", + "markdownDescription": "`@font-face` rule must define `src` and `font-family` properties." + }, + "somesass.css.diagnostics.lint.hexColorLength": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "error", + "description": "Hex colors must consist of 3, 4, 6 or 8 hex numbers." + }, + "somesass.css.diagnostics.lint.argumentsInColorFunction": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "error", + "description": "Invalid number of parameters." + }, + "somesass.css.diagnostics.lint.unknownProperties": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "warning", + "description": "Unknown vendor specific property." + }, + "somesass.css.diagnostics.lint.validProperties": { + "type": "array", + "uniqueItems": true, + "items": { + "type": "string" + }, + "scope": "resource", + "default": [], + "description": "A list of properties that are not validated against the `unknownProperties` rule." + }, + "somesass.css.diagnostics.lint.ieHack": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "ignore", + "description": "IE hacks are only necessary when supporting IE7 and older." + }, + "somesass.css.diagnostics.lint.unknownVendorSpecificProperties": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "ignore", + "description": "Unknown vendor specific property." + }, + "somesass.css.diagnostics.lint.propertyIgnoredDueToDisplay": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "warning", + "markdownDescription": "Property is ignored due to the display. E.g. with `display: inline`, the `width`, `height`, `margin-top`, `margin-bottom`, and `float` properties have no effect." + }, + "somesass.css.diagnostics.lint.important": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "ignore", + "markdownDescription": "Avoid using `!important`. It is an indication that the specificity of the entire CSS has gotten out of control and needs to be refactored." + }, + "somesass.css.diagnostics.lint.float": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "ignore", + "markdownDescription": "Avoid using `float`. Floats lead to fragile CSS that is easy to break if one aspect of the layout changes." + }, + "somesass.css.diagnostics.lint.idSelector": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "ignore", + "description": "Selectors should not contain IDs because these rules are too tightly coupled with the HTML." + }, + "somesass.css.diagnostics.lint.unknownAtRules": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "warning", + "description": "Unknown at-rule." + }, + "somesass.css.foldingRanges.enabled": { + "type": "boolean", + "scope": "resource", + "default": false, + "description": "Enable or disable folding ranges." + }, + "somesass.css.highlights.enabled": { + "type": "boolean", + "scope": "resource", + "default": false, + "description": "Enable or disable highlights." + }, + "somesass.css.hover.enabled": { + "type": "boolean", + "scope": "resource", + "default": false, + "description": "Enable or disable all hover information." + }, + "somesass.css.hover.documentation": { + "type": "boolean", + "scope": "resource", + "default": false, + "description": "Show property and value documentation in CSS hovers." + }, + "somesass.css.hover.references": { + "type": "boolean", + "scope": "resource", + "default": false, + "description": "Show references to MDN in CSS hovers." + }, + "somesass.css.links.enabled": { + "type": "boolean", + "scope": "resource", + "default": false, + "description": "Enable or disable the link provider that lets you click an import and open the file." + }, + "somesass.css.references.enabled": { + "type": "boolean", + "scope": "resource", + "default": false, + "description": "Enable or disable Find all references." + }, + "somesass.css.rename.enabled": { + "type": "boolean", + "scope": "resource", + "default": false, + "description": "Enable or disable Rename." + }, + "somesass.css.selectionRanges.enabled": { + "type": "boolean", + "scope": "resource", + "default": false, + "description": "Enable or disable selection ranges." + }, + "somesass.css.signatureHelp.enabled": { + "type": "boolean", + "scope": "resource", + "default": false, + "description": "Enable or disable selection ranges." + }, + "somesass.css.workspaceSymbol.enabled": { + "type": "boolean", + "scope": "resource", + "default": false, + "description": "Enable or disable selection ranges." } } + } ], "jsonValidation": [ - { - "fileMatch": "*.css-data.json", - "url": "https://raw.githubusercontent.com/microsoft/vscode-css-languageservice/master/docs/customData.schema.json" - }, - { - "fileMatch": "package.json", - "url": "./schemas/package.schema.json" - } - ] - }, - "dependencies": { - "fast-glob": "3.3.2", - "some-sass-language-server": "1.8.3", - "vscode-css-languageservice": "6.3.1", - "vscode-languageclient": "9.0.1", - "vscode-uri": "3.0.7" - }, - "devDependencies": { - "@types/mocha": "10.0.7", - "@types/vscode": "1.86.0", - "@vscode/test-electron": "2.4.1", - "@vscode/test-web": "0.0.60", - "assert": "2.1.0", - "mocha": "10.7.3", - "shx": "0.3.4" - }, - "scripts": { - "vscode:prepublish": "run-s clean build:production:*", - "clean": "shx rm -rf dist", - "build": "run-s build:development:*", - "build:node": "rspack --config ./rspack.node.config.js", - "build:browser": "rspack --config ./rspack.browser.config.js", - "build:development:node": "npm run build:node -- --mode=development", - "build:development:browser": "npm run build:browser -- --mode=development", - "build:production:node": "npm run build:node -- --mode=production", - "build:production:browser": "npm run build:browser -- --mode=production", - "start:web": "vscode-test-web --browserType=chromium --extensionDevelopmentPath=.", - "lint": "eslint \"**/*.ts\" --cache", - "pretest:e2e": "run-s clean build:production:*", - "test:e2e": "node ./test/e2e/runTest.js", - "pretest:web": "rspack --config ./rspack.test-web.config.js ", - "test:web": "node ./test/web/runTest.js" - }, - "__metadata": { - "id": "6d35099c-3671-464c-ac0b-34a0c3823927", - "publisherDisplayName": "Somewhat Stationery", - "publisherId": "02638283-c13a-4acf-9f26-24bdcfdfce24", - "isPreReleaseVersion": false - } + { + "fileMatch": "*.css-data.json", + "url": "https://raw.githubusercontent.com/microsoft/vscode-css-languageservice/master/docs/customData.schema.json" + }, + { + "fileMatch": "package.json", + "url": "./schemas/package.schema.json" + } + ] + }, + "dependencies": { + "fast-glob": "3.3.2", + "some-sass-language-server": "1.8.3", + "vscode-css-languageservice": "6.3.1", + "vscode-languageclient": "9.0.1", + "vscode-uri": "3.0.7" + }, + "devDependencies": { + "@types/mocha": "10.0.7", + "@types/vscode": "1.86.0", + "@vscode/test-electron": "2.4.1", + "@vscode/test-web": "0.0.60", + "assert": "2.1.0", + "mocha": "10.7.3", + "shx": "0.3.4" + }, + "scripts": { + "vscode:prepublish": "run-s clean build:production:*", + "clean": "shx rm -rf dist", + "build": "run-s build:development:*", + "build:node": "rspack --config ./rspack.node.config.js", + "build:browser": "rspack --config ./rspack.browser.config.js", + "build:development:node": "npm run build:node -- --mode=development", + "build:development:browser": "npm run build:browser -- --mode=development", + "build:production:node": "npm run build:node -- --mode=production", + "build:production:browser": "npm run build:browser -- --mode=production", + "start:web": "vscode-test-web --browserType=chromium --extensionDevelopmentPath=.", + "lint": "eslint \"**/*.ts\" --cache", + "pretest:e2e": "run-s clean build:production:*", + "test:e2e": "node ./test/e2e/runTest.js", + "pretest:web": "rspack --config ./rspack.test-web.config.js ", + "test:web": "node ./test/web/runTest.js" + }, + "__metadata": { + "id": "6d35099c-3671-464c-ac0b-34a0c3823927", + "publisherDisplayName": "Somewhat Stationery", + "publisherId": "02638283-c13a-4acf-9f26-24bdcfdfce24", + "isPreReleaseVersion": false + } } From 3da7b02ef24f0dfe9b03cd2c5695fe3b98b1eb49 Mon Sep 17 00:00:00 2001 From: William Killerud Date: Mon, 23 Sep 2024 18:50:30 +0200 Subject: [PATCH 10/23] refactor: fix loglevel type --- packages/language-services/src/configuration.ts | 2 +- packages/language-services/src/language-services-types.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/language-services/src/configuration.ts b/packages/language-services/src/configuration.ts index b065711d..0f790a10 100644 --- a/packages/language-services/src/configuration.ts +++ b/packages/language-services/src/configuration.ts @@ -1,11 +1,11 @@ import { LanguageServerConfiguration } from "./language-services-types"; export const defaultConfiguration: LanguageServerConfiguration = { - logLevel: "info", workspace: { exclude: ["**/.git/**", "**/node_modules/**"], importAliases: {}, loadPaths: [], + logLevel: "info", }, editor: { colorDecoratorsLimit: 500, diff --git a/packages/language-services/src/language-services-types.ts b/packages/language-services/src/language-services-types.ts index dc4a7d46..12d98874 100644 --- a/packages/language-services/src/language-services-types.ts +++ b/packages/language-services/src/language-services-types.ts @@ -317,6 +317,7 @@ export interface WorkspaceConfiguration { */ loadPaths: string[]; workspaceRoot?: URI; + logLevel: "trace" | "debug" | "info" | "warn" | "error" | "fatal" | "silent"; } export interface LanguageServerConfiguration { @@ -325,7 +326,6 @@ export interface LanguageServerConfiguration { scss: LanguageConfiguration; editor: EditorConfiguration; workspace: WorkspaceConfiguration; - logLevel: "trace" | "debug" | "info" | "warn" | "error" | "fatal" | "silent"; } export interface EditorConfiguration { From f572214c42a0d2aaa015c409fe0b5f13e3b6aad7 Mon Sep 17 00:00:00 2001 From: William Killerud Date: Mon, 23 Sep 2024 19:33:07 +0200 Subject: [PATCH 11/23] feat: turn off features with settings --- packages/language-server/src/server.ts | 561 +++++++++++------- .../src/features/do-diagnostics.ts | 6 +- .../src/features/find-colors.ts | 11 +- .../src/features/find-definition.ts | 14 +- .../src/features/find-symbols.ts | 25 +- .../src/cssLanguageTypes.ts | 2 +- .../src/services/cssValidation.ts | 2 +- 7 files changed, 396 insertions(+), 225 deletions(-) diff --git a/packages/language-server/src/server.ts b/packages/language-server/src/server.ts index 3b17082f..c22914f9 100644 --- a/packages/language-server/src/server.ts +++ b/packages/language-server/src/server.ts @@ -31,19 +31,22 @@ import { import { getSassRegionsDocument } from "./utils/embedded"; import WorkspaceScanner from "./workspace-scanner"; import { createLogger, type Logger } from "./logger"; -import { EditorConfiguration } from "@somesass/language-services/dist/language-services-types"; +import { + EditorConfiguration, + LanguageConfiguration, +} from "@somesass/language-services/dist/language-services-types"; import merge from "lodash.merge"; export class SomeSassServer { private readonly connection: Connection; private readonly runtime: RuntimeEnvironment; private readonly log: Logger; + private configuration: LanguageServiceConfiguration = defaultConfiguration; constructor(connection: Connection, runtime: RuntimeEnvironment) { this.connection = connection; this.runtime = runtime; this.log = createLogger(connection); - this.log.info(`Some Sass language server is starting`); this.log.trace(`Process ID ${process.pid}`); } @@ -55,16 +58,9 @@ export class SomeSassServer { let clientCapabilities: ClientCapabilities | undefined = undefined; let initialScan: Promise | null = null; - // Create a simple text document manager. The text document manager - // _supports full document sync only const documents = new TextDocuments(TextDocument); - - // Make the text document manager listen on the connection - // _for open, change and close text document events documents.listen(this.connection); - // After the server has started the client sends an initilize request. The server receives - // _in the passed params the rootPath of the workspace plus the client capabilites this.connection.onInitialize((params) => { clientCapabilities = params.capabilities; @@ -76,10 +72,8 @@ export class SomeSassServer { logger: this.log, }); - // TODO: migrate to workspace folders. Workspace was an unnecessary older workaround of mine. - workspaceRoot = URI.parse( - params.initializationOptions?.workspace || params.rootUri!, - ); + // TODO: migrate to workspace folders + workspaceRoot = URI.parse(params.rootUri!); this.log.info(`Workspace root ${workspaceRoot}`); return { @@ -142,7 +136,7 @@ export class SomeSassServer { ): LanguageServiceConfiguration => { if (isOldConfiguration(somesass)) { this.log.warn( - `Your somesass configuration uses old setting names. They will continue to work for some time, but it's recommended you change your settings to the new names. See https://wkillerud.github.io/some-sass/user-guide/settings.html`, + `Your somesass configuration uses old setting names. They will continue to work for some time, but it's recommended you change your settings to the new names. For new setting IDs see https://wkillerud.github.io/some-sass/user-guide/settings.html`, ); somesass = toNewConfiguration(somesass as Partial); } @@ -162,10 +156,14 @@ export class SomeSassServer { this.log.setLogLevel(settings.workspace.logLevel); } + this.configuration = settings; if (ls) { ls.configure(settings); } + this.log.debug("Applied user configuration"); + this.log.trace(JSON.stringify(this.configuration)); + return settings; }; @@ -199,9 +197,7 @@ export class SomeSassServer { const configuration = applyConfiguration(somesass, editor); - this.log.debug( - `[Server${process.pid ? `(${process.pid})` : ""} ${workspaceRoot}] scanning workspace for files`, - ); + this.log.debug("Scanning workspace for files"); return fileSystemProvider .findFiles( @@ -209,9 +205,7 @@ export class SomeSassServer { configuration.workspace.exclude, ) .then((files) => { - this.log.debug( - `[Server${process.pid ? `(${process.pid})` : ""} ${workspaceRoot}] found ${files.length} files, starting parse`, - ); + this.log.debug(`Found ${files.length} files, starting parse`); workspaceScanner = new WorkspaceScanner( ls!, @@ -222,7 +216,7 @@ export class SomeSassServer { }) .then((promises) => { this.log.debug( - `[Server${process.pid ? `(${process.pid})` : ""} ${workspaceRoot}] parsed ${promises.length} files`, + `Initial scan finished, parsed ${promises.length} files`, ); resolve(); }); @@ -234,23 +228,29 @@ export class SomeSassServer { } }); - const onDocumentChanged = async ( - params: TextDocumentChangeEvent, - ) => { - if (!workspaceScanner || !ls) return; + this.connection.onDidChangeConfiguration((params) => { + applyConfiguration(params.settings.somesass, params.settings.editor); + }); - try { - ls.onDocumentChanged(params.document); + const doDiagnostics = async ( + params: TextDocumentChangeEvent, + ): Promise => { + if (!ls) return; - // TODO: look into this so we can get diagnostics on first open, not working properly + const document = getSassRegionsDocument( + documents.get(params.document.uri), + ); + if (!document) return; - // Check that no new version has been made while we waited, - // in which case the diagnostics may no longer be valid. + const config = this.languageConfiguration(document); + if (config.diagnostics.enabled) { let latest = documents.get(params.document.uri); if (!latest || latest.version !== params.document.version) return; const diagnostics = await ls.doDiagnostics(params.document); + // Check that no new version has been made while we waited, + // in which case the diagnostics may no longer be valid. latest = documents.get(params.document.uri); if (!latest || latest.version !== params.document.version) return; @@ -258,16 +258,28 @@ export class SomeSassServer { uri: latest.uri, diagnostics, }); - } catch { - // Do nothing, the document might have changed } }; - documents.onDidOpen(onDocumentChanged); - documents.onDidChangeContent(onDocumentChanged); + documents.onDidOpen(async (params) => { + try { + if (initialScan) { + await initialScan; + } + await doDiagnostics(params); + } catch (e) { + this.log.debug((e as Error).message); + } + }); - this.connection.onDidChangeConfiguration((params) => { - applyConfiguration(params.settings.somesass, params.settings.editor); + documents.onDidChangeContent(async (params) => { + if (!workspaceScanner || !ls) return; + try { + ls.onDocumentChanged(params.document); + await doDiagnostics(params); + } catch (e) { + this.log.debug((e as Error).message); + } }); this.connection.onDidChangeWatchedFiles(async (event) => { @@ -293,260 +305,388 @@ export class SomeSassServer { } await workspaceScanner.scan(newFiles); - } catch { - // do nothing + } catch (e) { + this.log.debug((e as Error).message); } }); this.connection.onCompletion(async (params) => { if (!ls) return null; + try { + const document = getSassRegionsDocument( + documents.get(params.textDocument.uri), + params.position, + ); + if (!document) return null; - const document = getSassRegionsDocument( - documents.get(params.textDocument.uri), - params.position, - ); - if (!document) return null; - - const result = await ls.doComplete(document, params.position); - if (result.items.length === 0) { - result.isIncomplete = true; + const config = this.languageConfiguration(document); + if (config.completion.enabled) { + const result = await ls.doComplete(document, params.position); + if (result.items.length === 0) { + result.isIncomplete = true; + } + return result; + } else { + return null; + } + } catch (e) { + this.log.debug((e as Error).message); + return null; } - return result; }); this.connection.onHover((params) => { if (!ls) return null; + try { + const document = getSassRegionsDocument( + documents.get(params.textDocument.uri), + params.position, + ); + if (!document) return null; - const document = getSassRegionsDocument( - documents.get(params.textDocument.uri), - params.position, - ); - if (!document) return null; - - const result = ls.doHover(document, params.position); - return result; + const config = this.languageConfiguration(document); + if (config.hover.enabled) { + const result = ls.doHover(document, params.position); + return result; + } else { + return null; + } + } catch (e) { + this.log.debug((e as Error).message); + return null; + } }); this.connection.onSignatureHelp(async (params) => { if (!ls) return null; + try { + const document = getSassRegionsDocument( + documents.get(params.textDocument.uri), + params.position, + ); + if (!document) return null; - const document = getSassRegionsDocument( - documents.get(params.textDocument.uri), - params.position, - ); - if (!document) return null; - - const result = await ls.doSignatureHelp(document, params.position); - return result; + const config = this.languageConfiguration(document); + if (config.signatureHelp.enabled) { + const result = await ls.doSignatureHelp(document, params.position); + return result; + } else { + return null; + } + } catch (e) { + this.log.debug((e as Error).message); + return null; + } }); this.connection.onDefinition((params) => { if (!ls) return null; + try { + const document = getSassRegionsDocument( + documents.get(params.textDocument.uri), + params.position, + ); + if (!document) return null; - const document = getSassRegionsDocument( - documents.get(params.textDocument.uri), - params.position, - ); - if (!document) return null; - - const result = ls.findDefinition(document, params.position); - return result; + const config = this.languageConfiguration(document); + if (config.definition.enabled) { + const result = ls.findDefinition(document, params.position); + return result; + } else { + return null; + } + } catch (e) { + this.log.debug((e as Error).message); + return null; + } }); this.connection.onDocumentHighlight(async (params) => { if (!ls) return null; - - const document = getSassRegionsDocument( - documents.get(params.textDocument.uri), - params.position, - ); - if (!document) return null; - try { - if (initialScan) { - await initialScan; + const document = getSassRegionsDocument( + documents.get(params.textDocument.uri), + params.position, + ); + if (!document) return null; + + const config = this.languageConfiguration(document); + if (config.highlights.enabled) { + try { + if (initialScan) { + await initialScan; + } + const result = ls.findDocumentHighlights(document, params.position); + return result; + } catch { + // Do nothing + } + } else { + return null; } - const result = ls.findDocumentHighlights(document, params.position); - return result; - } catch { - // Do nothing + } catch (e) { + this.log.debug((e as Error).message); + return null; } }); this.connection.onDocumentLinks(async (params) => { if (!ls) return null; - - const document = getSassRegionsDocument( - documents.get(params.textDocument.uri), - ); - if (!document) return null; - try { - if (initialScan) { - await initialScan; + const document = getSassRegionsDocument( + documents.get(params.textDocument.uri), + ); + if (!document) return null; + + const config = this.languageConfiguration(document); + if (config.links.enabled) { + if (initialScan) { + await initialScan; + } + const result = await ls.findDocumentLinks(document); + return result; + } else { + return null; } - const result = await ls.findDocumentLinks(document); - return result; - } catch { - // Do nothing + } catch (e) { + this.log.debug((e as Error).message); + return null; } }); this.connection.onReferences(async (params) => { if (!ls) return null; - - const document = getSassRegionsDocument( - documents.get(params.textDocument.uri), - params.position, - ); - if (!document) return null; - - const references = await ls.findReferences( - document, - params.position, - params.context, - ); - return references; + try { + const document = getSassRegionsDocument( + documents.get(params.textDocument.uri), + params.position, + ); + if (!document) return null; + + const config = this.languageConfiguration(document); + if (config.references.enabled) { + const references = await ls.findReferences( + document, + params.position, + params.context, + ); + return references; + } else { + return null; + } + } catch (e) { + this.log.debug((e as Error).message); + return null; + } }); this.connection.onWorkspaceSymbol((params) => { if (!ls) return null; - - const result = ls.findWorkspaceSymbols(params.query); - return result; + try { + const result = ls.findWorkspaceSymbols(params.query); + return result; + } catch (e) { + this.log.debug((e as Error).message); + return null; + } }); this.connection.onCodeAction(async (params) => { if (!ls) return null; + try { + const document = getSassRegionsDocument( + documents.get(params.textDocument.uri), + ); + if (!document) return null; - const document = getSassRegionsDocument( - documents.get(params.textDocument.uri), - ); - if (!document) return null; + const config = this.languageConfiguration(document); + if (!config.codeAction.enabled) { + return null; + } - const result: (Command | CodeAction)[] = []; + const result: (Command | CodeAction)[] = []; - const actions = await ls.getCodeActions( - document, - params.range, - params.context, - ); + const actions = await ls.getCodeActions( + document, + params.range, + params.context, + ); - for (const action of actions) { - if (action.kind?.startsWith("refactor.extract")) { - // TODO: can we detect support for the custom command here before we do this? + for (const action of actions) { + if (action.kind?.startsWith("refactor.extract")) { + // TODO: can we detect support for the custom command here before we do this? - // Replace with a custom command that immediately starts a rename after applying the edit. - // If this causes problems for other clients, look into passing some kind of client identifier (optional) - // with initOptions that indicate this command exists in the client. + // Replace with a custom command that immediately starts a rename after applying the edit. + // If this causes problems for other clients, look into passing some kind of client identifier (optional) + // with initOptions that indicate this command exists in the client. - const edit: TextDocumentEdit | undefined = action.edit - ?.documentChanges?.[0] as TextDocumentEdit; + const edit: TextDocumentEdit | undefined = action.edit + ?.documentChanges?.[0] as TextDocumentEdit; - const command = Command.create( - action.title, - "_somesass.applyExtractCodeAction", - document.uri, - document.version, - edit && edit.edits[0], - ); + const command = Command.create( + action.title, + "_somesass.applyExtractCodeAction", + document.uri, + document.version, + edit && edit.edits[0], + ); - result.push(CodeAction.create(action.title, command, action.kind)); - } else { - result.push(action); + result.push(CodeAction.create(action.title, command, action.kind)); + } else { + result.push(action); + } } - } - return result; + return result; + } catch (e) { + this.log.debug((e as Error).message); + return null; + } }); this.connection.onPrepareRename(async (params) => { if (!ls) return null; + try { + const document = getSassRegionsDocument( + documents.get(params.textDocument.uri), + params.position, + ); + if (!document) return null; - const document = getSassRegionsDocument( - documents.get(params.textDocument.uri), - params.position, - ); - if (!document) return null; - - const preparations = await ls.prepareRename(document, params.position); - return preparations; + const config = this.languageConfiguration(document); + if (config.rename.enabled) { + const preparations = await ls.prepareRename( + document, + params.position, + ); + return preparations; + } else { + return null; + } + } catch (e) { + this.log.debug((e as Error).message); + return null; + } }); this.connection.onRenameRequest(async (params) => { if (!ls) return null; - - const document = getSassRegionsDocument( - documents.get(params.textDocument.uri), - params.position, - ); - if (!document) return null; - - const edits = await ls.doRename( - document, - params.position, - params.newName, - ); - return edits; + try { + const document = getSassRegionsDocument( + documents.get(params.textDocument.uri), + params.position, + ); + if (!document) return null; + + const config = this.languageConfiguration(document); + if (config.rename.enabled) { + const edits = await ls.doRename( + document, + params.position, + params.newName, + ); + return edits; + } else { + return null; + } + } catch (e) { + this.log.debug((e as Error).message); + return null; + } }); this.connection.onDocumentColor(async (params) => { if (!ls) return null; - - const document = getSassRegionsDocument( - documents.get(params.textDocument.uri), - ); - if (!document) return null; - try { - if (initialScan) { - await initialScan; + const document = getSassRegionsDocument( + documents.get(params.textDocument.uri), + ); + if (!document) return null; + + const config = this.languageConfiguration(document); + if (config.colors.enabled) { + if (initialScan) { + await initialScan; + } + const information = await ls.findColors(document); + return information; + } else { + return null; } - const information = await ls.findColors(document); - return information; - } catch { - // Do nothing + } catch (e) { + this.log.debug((e as Error).message); + return null; } }); this.connection.onColorPresentation((params) => { if (!ls) return null; - - const document = getSassRegionsDocument( - documents.get(params.textDocument.uri), - ); - if (!document) return null; - - const result = ls.getColorPresentations( - document, - params.color, - params.range, - ); - return result; + try { + const document = getSassRegionsDocument( + documents.get(params.textDocument.uri), + ); + if (!document) return null; + + const config = this.languageConfiguration(document); + if (config.colors.enabled) { + const result = ls.getColorPresentations( + document, + params.color, + params.range, + ); + return result; + } else { + return null; + } + } catch (e) { + this.log.debug((e as Error).message); + return null; + } }); this.connection.onFoldingRanges(async (params) => { if (!ls) return null; + try { + const document = getSassRegionsDocument( + documents.get(params.textDocument.uri), + ); + if (!document) return null; - const document = getSassRegionsDocument( - documents.get(params.textDocument.uri), - ); - if (!document) return null; - - const result = await ls.getFoldingRanges(document); - return result; + const config = this.languageConfiguration(document); + if (config.foldingRanges.enabled) { + const result = await ls.getFoldingRanges(document); + return result; + } else { + return null; + } + } catch (e) { + this.log.debug((e as Error).message); + return null; + } }); this.connection.onSelectionRanges(async (params) => { if (!ls) return null; + try { + const document = getSassRegionsDocument( + documents.get(params.textDocument.uri), + ); + if (!document) return null; - const document = getSassRegionsDocument( - documents.get(params.textDocument.uri), - ); - if (!document) return null; - - const result = await ls.getSelectionRanges(document, params.positions); - return result; + const config = this.languageConfiguration(document); + if (config.selectionRanges.enabled) { + const result = await ls.getSelectionRanges( + document, + params.positions, + ); + return result; + } else { + return null; + } + } catch (e) { + this.log.debug((e as Error).message); + return null; + } }); this.connection.onShutdown(() => { @@ -556,6 +696,21 @@ export class SomeSassServer { }); this.connection.listen(); - this.log.debug(`Some Sass language server is listening`); + this.log.debug(`Some Sass language server is running`); + } + + languageConfiguration(document: TextDocument): LanguageConfiguration { + switch (document.languageId) { + case "css": { + return this.configuration.css; + } + case "sass": { + return this.configuration.sass; + } + case "scss": { + return this.configuration.scss; + } + } + throw new Error(`Unsupported language ${document.languageId}`); } } diff --git a/packages/language-services/src/features/do-diagnostics.ts b/packages/language-services/src/features/do-diagnostics.ts index 67be34bc..44c4dbe7 100644 --- a/packages/language-services/src/features/do-diagnostics.ts +++ b/packages/language-services/src/features/do-diagnostics.ts @@ -74,12 +74,16 @@ export class DoDiagnostics extends LanguageFeature { return []; } - // TODO: move cssValidation in here so we can apply settings more easliy (turn off linting globally) + const config = this.languageConfiguration(document); const stylesheet = this.ls.parseStylesheet(document); const diagnostics = this.getUpstreamLanguageServer(document).doValidation( document, stylesheet, + { + validate: config.diagnostics.enabled, + lint: config.diagnostics.lint.enabled ? config.diagnostics.lint : false, + }, ); return diagnostics; } diff --git a/packages/language-services/src/features/find-colors.ts b/packages/language-services/src/features/find-colors.ts index 117a2faa..b2c8a97c 100644 --- a/packages/language-services/src/features/find-colors.ts +++ b/packages/language-services/src/features/find-colors.ts @@ -71,14 +71,13 @@ export class FindColors extends LanguageFeature { }), ); - if (config.colors.includeFromCurrentDocument === false) { - return result.filter((c) => c !== null); + if (config.colors.includeFromCurrentDocument) { + const upstream = this.getUpstreamLanguageServer( + document, + ).findDocumentColors(document, stylesheet); + result.push(...upstream); } - const upstream = this.getUpstreamLanguageServer( - document, - ).findDocumentColors(document, stylesheet); - result.push(...upstream); return result.filter((c) => c !== null); } diff --git a/packages/language-services/src/features/find-definition.ts b/packages/language-services/src/features/find-definition.ts index 9c4653c3..ffa602d8 100644 --- a/packages/language-services/src/features/find-definition.ts +++ b/packages/language-services/src/features/find-definition.ts @@ -138,10 +138,16 @@ export class FindDefinition extends LanguageFeature { } // If not found, go through the old fashioned way and assume everything is in scope via @import - const symbols = this.ls.findWorkspaceSymbols(name); - for (const symbol of symbols) { - if (kinds.includes(symbol.kind)) { - return symbol.location; + const documents = this.cache.documents(); + for (const document of documents) { + const symbols = this.ls.findDocumentSymbols(document); + for (const symbol of symbols) { + if (!symbol.name.includes(name)) { + continue; + } + if (kinds.includes(symbol.kind)) { + return Location.create(document.uri, symbol.selectionRange); + } } } diff --git a/packages/language-services/src/features/find-symbols.ts b/packages/language-services/src/features/find-symbols.ts index 0341c5c7..6521fba9 100644 --- a/packages/language-services/src/features/find-symbols.ts +++ b/packages/language-services/src/features/find-symbols.ts @@ -69,16 +69,23 @@ export class FindSymbols extends LanguageFeature { const documents = this.cache.documents(); const result: SymbolInformation[] = []; for (const document of documents) { - const symbols = this.findDocumentSymbols(document); - for (const symbol of symbols) { - if (query && !symbol.name.includes(query)) { - continue; + // This is the exception to the rule that this enabled check + // should happen at the server edge. It's only at this point + // we know if the document should be included or not. + // Maybe a sign that this method should be lifted out of language-services. + const config = this.languageConfiguration(document); + if (config.workspaceSymbol.enabled) { + const symbols = this.findDocumentSymbols(document); + for (const symbol of symbols) { + if (query && !symbol.name.includes(query)) { + continue; + } + result.push({ + name: symbol.name, + kind: symbol.kind, + location: Location.create(document.uri, symbol.selectionRange), + }); } - result.push({ - name: symbol.name, - kind: symbol.kind, - location: Location.create(document.uri, symbol.selectionRange), - }); } } return result; diff --git a/packages/vscode-css-languageservice/src/cssLanguageTypes.ts b/packages/vscode-css-languageservice/src/cssLanguageTypes.ts index f4ddc21d..70886d90 100644 --- a/packages/vscode-css-languageservice/src/cssLanguageTypes.ts +++ b/packages/vscode-css-languageservice/src/cssLanguageTypes.ts @@ -96,7 +96,7 @@ export interface CompletionSettings { export interface LanguageSettings { validate?: boolean; - lint?: LintSettings; + lint?: false | LintSettings; completion?: CompletionSettings; hover?: HoverSettings; importAliases?: AliasSettings; diff --git a/packages/vscode-css-languageservice/src/services/cssValidation.ts b/packages/vscode-css-languageservice/src/services/cssValidation.ts index e785c496..afe13ab7 100644 --- a/packages/vscode-css-languageservice/src/services/cssValidation.ts +++ b/packages/vscode-css-languageservice/src/services/cssValidation.ts @@ -35,7 +35,7 @@ export class CSSValidation { LintVisitor.entries( stylesheet, document, - new LintConfigurationSettings(settings && settings.lint), + new LintConfigurationSettings(settings && settings.lint !== false ? settings.lint : undefined), this.cssDataManager, ), ); From 32c2a5ab5d5d157da66ff76162936eb34fabcad2 Mon Sep 17 00:00:00 2001 From: William Killerud Date: Mon, 23 Sep 2024 19:54:46 +0200 Subject: [PATCH 12/23] test: assertion --- vscode-extension/test/web/suite/hover.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vscode-extension/test/web/suite/hover.test.js b/vscode-extension/test/web/suite/hover.test.js index 84c4e819..ddba088f 100644 --- a/vscode-extension/test/web/suite/hover.test.js +++ b/vscode-extension/test/web/suite/hover.test.js @@ -75,7 +75,7 @@ test("for SassDoc annotations", async () => { // Prefixed symbols are shown with their original names const expectedContents = { contents: [ - "@type\n____\n[SassDoc reference](http://sassdoc.com/annotations/#type)", + "@type\n\n[SassDoc reference](http://sassdoc.com/annotations/#type)", ], }; From 37c71fac9f1a6c550811b5a1d3864a3af98d411d Mon Sep 17 00:00:00 2001 From: William Killerud Date: Wed, 25 Sep 2024 18:21:09 +0200 Subject: [PATCH 13/23] refactor: tweak settings UI --- vscode-extension/package.json | 181 +++++++++++++++++++++++++++++----- 1 file changed, 157 insertions(+), 24 deletions(-) diff --git a/vscode-extension/package.json b/vscode-extension/package.json index e40bad4b..2e6a95a1 100644 --- a/vscode-extension/package.json +++ b/vscode-extension/package.json @@ -67,14 +67,17 @@ "properties": { "somesass.workspace.loadPaths": { "type": "array", + "scope": "resource", "items": { "type": "string" }, "default": [], - "markdownDescription": "A list of paths relative to the workspace root where the language server should look for stylesheets loaded by `@use` and `@import`. `node_modules` is always included.\n\nNote that you will have to [configure your Sass compiler separately](https://sass-lang.com/documentation/cli/dart-sass/#load-path)." + "markdownDescription": "A list of paths relative to the workspace root where the language server should look for stylesheets loaded by `@use` and `@import`. `node_modules` is always included.\n\nNote that you will have to [configure your Sass compiler separately](https://sass-lang.com/documentation/cli/dart-sass/#load-path).", + "order": 0 }, "somesass.workspace.exclude": { "type": "array", + "scope": "resource", "items": { "type": "string" }, @@ -82,10 +85,12 @@ "**/.git/**", "**/node_modules/**" ], - "description": "List of glob patterns for directories that are excluded when scanning." + "description": "List of glob patterns for directories that are excluded when scanning.", + "order": 1 }, "somesass.workspace.logLevel": { "type": "string", + "scope": "resource", "default": "info", "enum": [ "silent", @@ -96,7 +101,20 @@ "debug", "trace" ], - "description": "Control how much gets logged to the Output window." + "description": "Control how much gets logged to the Output window.", + "order": 2 + }, + "some-sass.trace.server": { + "type": "string", + "scope": "window", + "enum": [ + "off", + "messages", + "verbose" + ], + "default": "off", + "description": "Log the messages sent between VS Code and the Some Sass language server.", + "order": 999 } } }, @@ -104,40 +122,41 @@ "title": "SCSS", "properties": { "somesass.scss.codeAction.enabled": { + "order": 10, "type": "boolean", "scope": "resource", "default": true, "description": "Enable or disable all code actions." }, "somesass.scss.colors.enabled": { + "order": 20, "type": "boolean", "scope": "resource", "default": true, "description": "Enable or disable all color decorators." }, "somesass.scss.colors.includeFromCurrentDocument": { + "order": 21, "type": "boolean", "scope": "resource", "default": false, "description": "Compatibility setting for VS Code. By default the built-in SCSS server shows color decorators for variables declared in the current document. To avoid duplicates Some Sass will not show them unless you opt in." }, "somesass.scss.completion.enabled": { + "order": 30, "type": "boolean", "scope": "resource", "default": true, "description": "Enable or disable all completions (IntelliSense)." }, - "somesass.scss.completion.includeFromCurrentDocument": { - "type": "boolean", - "default": false, - "description": "Compatibility setting for VS Code. By default the built-in SCSS server shows suggestions for variables, mixins and functions declared in the current document. To avoid duplicates Some Sass will not suggest them unless you opt in." - }, "somesass.scss.completion.suggestFromUseOnly": { + "order": 31, "type": "boolean", "default": false, "description": "If your project uses the new module system with @use and @forward, you may want to only include suggestions from your used modules." }, "somesass.scss.completion.mixinStyle": { + "order": 32, "type": "string", "default": "all", "description": "Controls the style of suggestions for mixins.", @@ -158,42 +177,55 @@ ] }, "somesass.scss.completion.triggerPropertyValueCompletion": { + "order": 33, "type": "boolean", "scope": "resource", "default": true, "description": "By default, Some Sass triggers property value completion after selecting a CSS property. Use this setting to disable this behavior." }, "somesass.scss.completion.completePropertyWithSemicolon": { + "order": 34, "type": "boolean", "scope": "resource", "default": true, "description": "Insert semicolon at end of line when completing CSS properties." }, + "somesass.scss.completion.includeFromCurrentDocument": { + "order": 35, + "type": "boolean", + "default": false, + "description": "Compatibility setting for VS Code. By default the built-in SCSS server shows suggestions for variables, mixins and functions declared in the current document. To avoid duplicates Some Sass will not suggest them unless you opt in." + }, "somesass.scss.definition.enabled": { + "order": 40, "type": "boolean", "scope": "resource", "default": true, "description": "Enable or disable Go to Definition." }, "somesass.scss.diagnostics.enabled": { + "order": 50, "type": "boolean", "scope": "resource", "default": true, "description": "Enable or disable all diagnostics (deprecation, errors and lint rules)." }, "somesass.scss.diagnostics.deprecation.enabled": { + "order": 51, "type": "boolean", "scope": "resource", "default": true, "description": "Enable or disable deprecation diagnostics (strike-through)." }, "somesass.scss.diagnostics.lint.enabled": { + "order": 52, "type": "boolean", "scope": "resource", "default": false, "description": "Enable or disable all linting." }, "somesass.scss.diagnostics.lint.compatibleVendorPrefixes": { + "order": 53, "type": "string", "scope": "resource", "enum": [ @@ -205,6 +237,7 @@ "description": "When using a vendor-specific prefix make sure to also include all other vendor-specific properties." }, "somesass.scss.diagnostics.lint.vendorPrefix": { + "order": 53, "type": "string", "scope": "resource", "enum": [ @@ -216,6 +249,7 @@ "description": "When using a vendor-specific prefix, also include the standard property." }, "somesass.scss.diagnostics.lint.duplicateProperties": { + "order": 53, "type": "string", "scope": "resource", "enum": [ @@ -227,6 +261,7 @@ "description": "Do not use duplicate style definitions." }, "somesass.scss.diagnostics.lint.emptyRules": { + "order": 53, "type": "string", "scope": "resource", "enum": [ @@ -238,6 +273,7 @@ "description": "Do not use empty rulesets." }, "somesass.scss.diagnostics.lint.importStatement": { + "order": 53, "type": "string", "scope": "resource", "enum": [ @@ -249,6 +285,7 @@ "description": "Import statements can lead to sequential loading of CSS." }, "somesass.scss.diagnostics.lint.boxModel": { + "order": 53, "type": "string", "scope": "resource", "enum": [ @@ -260,6 +297,7 @@ "markdownDescription": "Do not use `width` or `height` when using `padding` or `border`." }, "somesass.scss.diagnostics.lint.universalSelector": { + "order": 53, "type": "string", "scope": "resource", "enum": [ @@ -271,6 +309,7 @@ "markdownDescription": "The universal selector (`*`) is known to be slow." }, "somesass.scss.diagnostics.lint.zeroUnits": { + "order": 53, "type": "string", "scope": "resource", "enum": [ @@ -282,6 +321,7 @@ "description": "No unit needed for zero." }, "somesass.scss.diagnostics.lint.fontFaceProperties": { + "order": 53, "type": "string", "scope": "resource", "enum": [ @@ -293,6 +333,7 @@ "markdownDescription": "`@font-face` rule must define `src` and `font-family` properties." }, "somesass.scss.diagnostics.lint.hexColorLength": { + "order": 53, "type": "string", "scope": "resource", "enum": [ @@ -304,6 +345,7 @@ "description": "Hex colors must consist of 3, 4, 6 or 8 hex numbers." }, "somesass.scss.diagnostics.lint.argumentsInColorFunction": { + "order": 53, "type": "string", "scope": "resource", "enum": [ @@ -315,6 +357,7 @@ "description": "Invalid number of parameters." }, "somesass.scss.diagnostics.lint.unknownProperties": { + "order": 53, "type": "string", "scope": "resource", "enum": [ @@ -326,6 +369,7 @@ "description": "Unknown vendor specific property." }, "somesass.scss.diagnostics.lint.validProperties": { + "order": 53, "type": "array", "uniqueItems": true, "items": { @@ -336,6 +380,7 @@ "description": "A list of properties that are not validated against the `unknownProperties` rule." }, "somesass.scss.diagnostics.lint.ieHack": { + "order": 53, "type": "string", "scope": "resource", "enum": [ @@ -347,6 +392,7 @@ "description": "IE hacks are only necessary when supporting IE7 and older." }, "somesass.scss.diagnostics.lint.unknownVendorSpecificProperties": { + "order": 53, "type": "string", "scope": "resource", "enum": [ @@ -358,6 +404,7 @@ "description": "Unknown vendor specific property." }, "somesass.scss.diagnostics.lint.propertyIgnoredDueToDisplay": { + "order": 53, "type": "string", "scope": "resource", "enum": [ @@ -369,6 +416,7 @@ "markdownDescription": "Property is ignored due to the display. E.g. with `display: inline`, the `width`, `height`, `margin-top`, `margin-bottom`, and `float` properties have no effect." }, "somesass.scss.diagnostics.lint.important": { + "order": 53, "type": "string", "scope": "resource", "enum": [ @@ -380,6 +428,7 @@ "markdownDescription": "Avoid using `!important`. It is an indication that the specificity of the entire CSS has gotten out of control and needs to be refactored." }, "somesass.scss.diagnostics.lint.float": { + "order": 53, "type": "string", "scope": "resource", "enum": [ @@ -391,6 +440,7 @@ "markdownDescription": "Avoid using `float`. Floats lead to fragile CSS that is easy to break if one aspect of the layout changes." }, "somesass.scss.diagnostics.lint.idSelector": { + "order": 53, "type": "string", "scope": "resource", "enum": [ @@ -402,6 +452,7 @@ "description": "Selectors should not contain IDs because these rules are too tightly coupled with the HTML." }, "somesass.scss.diagnostics.lint.unknownAtRules": { + "order": 53, "type": "string", "scope": "resource", "enum": [ @@ -413,81 +464,81 @@ "description": "Unknown at-rule." }, "somesass.scss.foldingRanges.enabled": { + "order": 60, "type": "boolean", "scope": "resource", "default": false, "description": "Enable or disable folding ranges." }, "somesass.scss.highlights.enabled": { + "order": 70, "type": "boolean", "scope": "resource", "default": false, "description": "Enable or disable highlights." }, "somesass.scss.hover.enabled": { + "order": 80, "type": "boolean", "scope": "resource", "default": true, "description": "Enable or disable all hover information." }, "somesass.scss.hover.documentation": { + "order": 81, "type": "boolean", "scope": "resource", "default": true, "description": "Show property and value documentation in CSS hovers." }, "somesass.scss.hover.references": { + "order": 82, "type": "boolean", "scope": "resource", "default": true, "description": "Show references to MDN in CSS hovers, Sass documentation for Sass built-in modules and SassDoc for annotations." }, "somesass.scss.links.enabled": { + "order": 90, "type": "boolean", "scope": "resource", "default": false, "description": "Enable or disable the link provider that lets you click an import and open the file." }, "somesass.scss.references.enabled": { + "order": 100, "type": "boolean", "scope": "resource", "default": true, "description": "Enable or disable Find all references." }, "somesass.scss.rename.enabled": { + "order": 110, "type": "boolean", "scope": "resource", "default": true, "description": "Enable or disable Rename." }, "somesass.scss.selectionRanges.enabled": { + "order": 120, "type": "boolean", "scope": "resource", "default": false, "description": "Enable or disable selection ranges." }, "somesass.scss.signatureHelp.enabled": { + "order": 130, "type": "boolean", "scope": "resource", "default": true, "description": "Enable or disable signature help." }, "somesass.scss.workspaceSymbol.enabled": { + "order": 140, "type": "boolean", "scope": "resource", "default": true, "description": "Enable or disable workspace symbols." - }, - "some-sass.trace.server": { - "type": "string", - "scope": "window", - "enum": [ - "off", - "messages", - "verbose" - ], - "default": "off", - "description": "Log the messages sent between VS Code and the Some Sass language server." } } }, @@ -495,24 +546,34 @@ "title": "Sass (Indented)", "properties": { "somesass.sass.codeAction.enabled": { + "order": 10, "type": "boolean", "scope": "resource", "default": true, "description": "Enable or disable all code actions." }, "somesass.sass.colors.enabled": { + "order": 20, "type": "boolean", "scope": "resource", "default": true, "description": "Enable or disable all color decorators." }, "somesass.sass.completion.enabled": { + "order": 30, "type": "boolean", "scope": "resource", "default": true, "description": "Enable or disable all completions (IntelliSense)." }, + "somesass.sass.completion.suggestFromUseOnly": { + "order": 31, + "type": "boolean", + "default": false, + "description": "If your project uses the new module system with @use and @forward, you may want to only include suggestions from your used modules." + }, "somesass.sass.completion.mixinStyle": { + "order": 32, "type": "string", "default": "all", "description": "Controls the style of suggestions for mixins and placeholders.", @@ -532,42 +593,43 @@ "Where brackets are suggested, omit duplicates without brackets" ] }, - "somesass.sass.completion.suggestFromUseOnly": { - "type": "boolean", - "default": false, - "description": "If your project uses the new module system with @use and @forward, you may want to only include suggestions from your used modules." - }, "somesass.sass.completion.triggerPropertyValueCompletion": { + "order": 33, "type": "boolean", "scope": "resource", "default": true, "description": "By default, Some Sass triggers property value completion after selecting a CSS property. Use this setting to disable this behavior." }, "somesass.sass.definition.enabled": { + "order": 40, "type": "boolean", "scope": "resource", "default": true, "description": "Enable or disable Go to Definition." }, "somesass.sass.diagnostics.enabled": { + "order": 50, "type": "boolean", "scope": "resource", "default": true, "description": "Enable or disable all diagnostics (deprecation, errors and lint rules)." }, "somesass.sass.diagnostics.deprecation.enabled": { + "order": 51, "type": "boolean", "scope": "resource", "default": true, "description": "Enable or disable deprecation diagnostics (strike-through)." }, "somesass.sass.diagnostics.lint.enabled": { + "order": 52, "type": "boolean", "scope": "resource", "default": true, "description": "Enable or disable all linting." }, "somesass.sass.diagnostics.lint.compatibleVendorPrefixes": { + "order": 53, "type": "string", "scope": "resource", "enum": [ @@ -579,6 +641,7 @@ "description": "When using a vendor-specific prefix make sure to also include all other vendor-specific properties." }, "somesass.sass.diagnostics.lint.vendorPrefix": { + "order": 53, "type": "string", "scope": "resource", "enum": [ @@ -590,6 +653,7 @@ "description": "When using a vendor-specific prefix, also include the standard property." }, "somesass.sass.diagnostics.lint.duplicateProperties": { + "order": 53, "type": "string", "scope": "resource", "enum": [ @@ -601,6 +665,7 @@ "description": "Do not use duplicate style definitions." }, "somesass.sass.diagnostics.lint.emptyRules": { + "order": 53, "type": "string", "scope": "resource", "enum": [ @@ -612,6 +677,7 @@ "description": "Do not use empty rulesets." }, "somesass.sass.diagnostics.lint.importStatement": { + "order": 53, "type": "string", "scope": "resource", "enum": [ @@ -623,6 +689,7 @@ "description": "Import statements can lead to sequential loading of CSS." }, "somesass.sass.diagnostics.lint.boxModel": { + "order": 53, "type": "string", "scope": "resource", "enum": [ @@ -634,6 +701,7 @@ "markdownDescription": "Do not use `width` or `height` when using `padding` or `border`." }, "somesass.sass.diagnostics.lint.universalSelector": { + "order": 53, "type": "string", "scope": "resource", "enum": [ @@ -645,6 +713,7 @@ "markdownDescription": "The universal selector (`*`) is known to be slow." }, "somesass.sass.diagnostics.lint.zeroUnits": { + "order": 53, "type": "string", "scope": "resource", "enum": [ @@ -656,6 +725,7 @@ "description": "No unit needed for zero." }, "somesass.sass.diagnostics.lint.fontFaceProperties": { + "order": 53, "type": "string", "scope": "resource", "enum": [ @@ -667,6 +737,7 @@ "markdownDescription": "`@font-face` rule must define `src` and `font-family` properties." }, "somesass.sass.diagnostics.lint.hexColorLength": { + "order": 53, "type": "string", "scope": "resource", "enum": [ @@ -678,6 +749,7 @@ "description": "Hex colors must consist of 3, 4, 6 or 8 hex numbers." }, "somesass.sass.diagnostics.lint.argumentsInColorFunction": { + "order": 53, "type": "string", "scope": "resource", "enum": [ @@ -689,6 +761,7 @@ "description": "Invalid number of parameters." }, "somesass.sass.diagnostics.lint.unknownProperties": { + "order": 53, "type": "string", "scope": "resource", "enum": [ @@ -700,6 +773,7 @@ "description": "Unknown vendor specific property." }, "somesass.sass.diagnostics.lint.validProperties": { + "order": 53, "type": "array", "uniqueItems": true, "items": { @@ -710,6 +784,7 @@ "description": "A list of properties that are not validated against the `unknownProperties` rule." }, "somesass.sass.diagnostics.lint.ieHack": { + "order": 53, "type": "string", "scope": "resource", "enum": [ @@ -721,6 +796,7 @@ "description": "IE hacks are only necessary when supporting IE7 and older." }, "somesass.sass.diagnostics.lint.unknownVendorSpecificProperties": { + "order": 53, "type": "string", "scope": "resource", "enum": [ @@ -732,6 +808,7 @@ "description": "Unknown vendor specific property." }, "somesass.sass.diagnostics.lint.propertyIgnoredDueToDisplay": { + "order": 53, "type": "string", "scope": "resource", "enum": [ @@ -743,6 +820,7 @@ "markdownDescription": "Property is ignored due to the display. E.g. with `display: inline`, the `width`, `height`, `margin-top`, `margin-bottom`, and `float` properties have no effect." }, "somesass.sass.diagnostics.lint.important": { + "order": 53, "type": "string", "scope": "resource", "enum": [ @@ -754,6 +832,7 @@ "markdownDescription": "Avoid using `!important`. It is an indication that the specificity of the entire CSS has gotten out of control and needs to be refactored." }, "somesass.sass.diagnostics.lint.float": { + "order": 53, "type": "string", "scope": "resource", "enum": [ @@ -765,6 +844,7 @@ "markdownDescription": "Avoid using `float`. Floats lead to fragile CSS that is easy to break if one aspect of the layout changes." }, "somesass.sass.diagnostics.lint.idSelector": { + "order": 53, "type": "string", "scope": "resource", "enum": [ @@ -776,6 +856,7 @@ "description": "Selectors should not contain IDs because these rules are too tightly coupled with the HTML." }, "somesass.sass.diagnostics.lint.unknownAtRules": { + "order": 53, "type": "string", "scope": "resource", "enum": [ @@ -787,66 +868,77 @@ "description": "Unknown at-rule." }, "somesass.sass.foldingRanges.enabled": { + "order": 60, "type": "boolean", "scope": "resource", "default": true, "description": "Enable or disable folding ranges." }, "somesass.sass.highlights.enabled": { + "order": 70, "type": "boolean", "scope": "resource", "default": true, "description": "Enable or disable highlights." }, "somesass.sass.hover.enabled": { + "order": 80, "type": "boolean", "scope": "resource", "default": true, "description": "Enable or disable all hover information." }, "somesass.sass.hover.documentation": { + "order": 81, "type": "boolean", "scope": "resource", "default": true, "description": "Show property and value documentation in CSS hovers." }, "somesass.sass.hover.references": { + "order": 82, "type": "boolean", "scope": "resource", "default": true, "description": "Show references to MDN in CSS hovers, Sass documentation for Sass built-in modules and SassDoc for annotations." }, "somesass.sass.links.enabled": { + "order": 90, "type": "boolean", "scope": "resource", "default": true, "description": "Enable or disable the link provider that lets you click an import and open the file." }, "somesass.sass.references.enabled": { + "order": 100, "type": "boolean", "scope": "resource", "default": true, "description": "Enable or disable Find all references." }, "somesass.sass.rename.enabled": { + "order": 110, "type": "boolean", "scope": "resource", "default": true, "description": "Enable or disable Rename." }, "somesass.sass.selectionRanges.enabled": { + "order": 120, "type": "boolean", "scope": "resource", "default": true, "description": "Enable or disable selection ranges." }, "somesass.sass.signatureHelp.enabled": { + "order": 130, "type": "boolean", "scope": "resource", "default": true, "description": "Enable or disable selection ranges." }, "somesass.sass.workspaceSymbol.enabled": { + "order": 140, "type": "boolean", "scope": "resource", "default": true, @@ -858,6 +950,7 @@ "title": "CSS", "properties": { "somesass.css.customData": { + "order": 999, "type": "array", "markdownDescription": "A list of relative file paths pointing to JSON files following the [custom data format](https://github.com/microsoft/vscode-css-languageservice/blob/master/docs/customData.md).\n\nSome Sass loads custom data on startup to enhance its CSS support for CSS custom properties (variables), at-rules, pseudo-classes, and pseudo-elements you specify in the JSON files.\n\nThe file paths are relative to workspace and only workspace folder settings are considered.", "default": [], @@ -867,60 +960,70 @@ "scope": "resource" }, "somesass.css.codeAction.enabled": { + "order": 10, "type": "boolean", "scope": "resource", "default": false, "description": "Enable or disable all code actions." }, "somesass.css.colors.enabled": { + "order": 20, "type": "boolean", "scope": "resource", "default": false, "description": "Enable or disable all color decorators." }, "somesass.css.completion.enabled": { + "order": 30, "type": "boolean", "scope": "resource", "default": false, "description": "Enable or disable all completions (IntelliSense)." }, "somesass.css.completion.triggerPropertyValueCompletion": { + "order": 31, "type": "boolean", "scope": "resource", "default": true, "description": "By default, Some Sass triggers property value completion after selecting a CSS property. Use this setting to disable this behavior." }, "somesass.css.completion.completePropertyWithSemicolon": { + "order": 32, "type": "boolean", "scope": "resource", "default": true, "description": "Insert semicolon at end of line when completing CSS properties." }, "somesass.css.definition.enabled": { + "order": 40, "type": "boolean", "scope": "resource", "default": false, "description": "Enable or disable Go to Definition." }, "somesass.css.diagnostics.enabled": { + "order": 50, "type": "boolean", "scope": "resource", "default": false, "description": "Enable or disable all diagnostics (deprecation, errors and lint rules)." }, "somesass.css.diagnostics.deprecation.enabled": { + "order": 51, "type": "boolean", "scope": "resource", "default": true, "description": "Enable or disable deprecation diagnostics (strike-through)." }, "somesass.css.diagnostics.lint.enabled": { + "order": 52, "type": "boolean", "scope": "resource", "default": true, "description": "Enable or disable all linting." }, "somesass.css.diagnostics.lint.compatibleVendorPrefixes": { + "order": 53, "type": "string", "scope": "resource", "enum": [ @@ -932,6 +1035,7 @@ "description": "When using a vendor-specific prefix make sure to also include all other vendor-specific properties." }, "somesass.css.diagnostics.lint.vendorPrefix": { + "order": 53, "type": "string", "scope": "resource", "enum": [ @@ -943,6 +1047,7 @@ "description": "When using a vendor-specific prefix, also include the standard property." }, "somesass.css.diagnostics.lint.duplicateProperties": { + "order": 53, "type": "string", "scope": "resource", "enum": [ @@ -954,6 +1059,7 @@ "description": "Do not use duplicate style definitions." }, "somesass.css.diagnostics.lint.emptyRules": { + "order": 53, "type": "string", "scope": "resource", "enum": [ @@ -965,6 +1071,7 @@ "description": "Do not use empty rulesets." }, "somesass.css.diagnostics.lint.importStatement": { + "order": 53, "type": "string", "scope": "resource", "enum": [ @@ -976,6 +1083,7 @@ "description": "Import statements can lead to sequential loading of CSS." }, "somesass.css.diagnostics.lint.boxModel": { + "order": 53, "type": "string", "scope": "resource", "enum": [ @@ -987,6 +1095,7 @@ "markdownDescription": "Do not use `width` or `height` when using `padding` or `border`." }, "somesass.css.diagnostics.lint.universalSelector": { + "order": 53, "type": "string", "scope": "resource", "enum": [ @@ -998,6 +1107,7 @@ "markdownDescription": "The universal selector (`*`) is known to be slow." }, "somesass.css.diagnostics.lint.zeroUnits": { + "order": 53, "type": "string", "scope": "resource", "enum": [ @@ -1009,6 +1119,7 @@ "description": "No unit needed for zero." }, "somesass.css.diagnostics.lint.fontFaceProperties": { + "order": 53, "type": "string", "scope": "resource", "enum": [ @@ -1020,6 +1131,7 @@ "markdownDescription": "`@font-face` rule must define `src` and `font-family` properties." }, "somesass.css.diagnostics.lint.hexColorLength": { + "order": 53, "type": "string", "scope": "resource", "enum": [ @@ -1031,6 +1143,7 @@ "description": "Hex colors must consist of 3, 4, 6 or 8 hex numbers." }, "somesass.css.diagnostics.lint.argumentsInColorFunction": { + "order": 53, "type": "string", "scope": "resource", "enum": [ @@ -1042,6 +1155,7 @@ "description": "Invalid number of parameters." }, "somesass.css.diagnostics.lint.unknownProperties": { + "order": 53, "type": "string", "scope": "resource", "enum": [ @@ -1053,6 +1167,7 @@ "description": "Unknown vendor specific property." }, "somesass.css.diagnostics.lint.validProperties": { + "order": 53, "type": "array", "uniqueItems": true, "items": { @@ -1063,6 +1178,7 @@ "description": "A list of properties that are not validated against the `unknownProperties` rule." }, "somesass.css.diagnostics.lint.ieHack": { + "order": 53, "type": "string", "scope": "resource", "enum": [ @@ -1074,6 +1190,7 @@ "description": "IE hacks are only necessary when supporting IE7 and older." }, "somesass.css.diagnostics.lint.unknownVendorSpecificProperties": { + "order": 53, "type": "string", "scope": "resource", "enum": [ @@ -1085,6 +1202,7 @@ "description": "Unknown vendor specific property." }, "somesass.css.diagnostics.lint.propertyIgnoredDueToDisplay": { + "order": 53, "type": "string", "scope": "resource", "enum": [ @@ -1096,6 +1214,7 @@ "markdownDescription": "Property is ignored due to the display. E.g. with `display: inline`, the `width`, `height`, `margin-top`, `margin-bottom`, and `float` properties have no effect." }, "somesass.css.diagnostics.lint.important": { + "order": 53, "type": "string", "scope": "resource", "enum": [ @@ -1107,6 +1226,7 @@ "markdownDescription": "Avoid using `!important`. It is an indication that the specificity of the entire CSS has gotten out of control and needs to be refactored." }, "somesass.css.diagnostics.lint.float": { + "order": 53, "type": "string", "scope": "resource", "enum": [ @@ -1118,6 +1238,7 @@ "markdownDescription": "Avoid using `float`. Floats lead to fragile CSS that is easy to break if one aspect of the layout changes." }, "somesass.css.diagnostics.lint.idSelector": { + "order": 53, "type": "string", "scope": "resource", "enum": [ @@ -1129,6 +1250,7 @@ "description": "Selectors should not contain IDs because these rules are too tightly coupled with the HTML." }, "somesass.css.diagnostics.lint.unknownAtRules": { + "order": 53, "type": "string", "scope": "resource", "enum": [ @@ -1140,66 +1262,77 @@ "description": "Unknown at-rule." }, "somesass.css.foldingRanges.enabled": { + "order": 60, "type": "boolean", "scope": "resource", "default": false, "description": "Enable or disable folding ranges." }, "somesass.css.highlights.enabled": { + "order": 70, "type": "boolean", "scope": "resource", "default": false, "description": "Enable or disable highlights." }, "somesass.css.hover.enabled": { + "order": 80, "type": "boolean", "scope": "resource", "default": false, "description": "Enable or disable all hover information." }, "somesass.css.hover.documentation": { + "order": 81, "type": "boolean", "scope": "resource", "default": false, "description": "Show property and value documentation in CSS hovers." }, "somesass.css.hover.references": { + "order": 82, "type": "boolean", "scope": "resource", "default": false, "description": "Show references to MDN in CSS hovers." }, "somesass.css.links.enabled": { + "order": 90, "type": "boolean", "scope": "resource", "default": false, "description": "Enable or disable the link provider that lets you click an import and open the file." }, "somesass.css.references.enabled": { + "order": 100, "type": "boolean", "scope": "resource", "default": false, "description": "Enable or disable Find all references." }, "somesass.css.rename.enabled": { + "order": 110, "type": "boolean", "scope": "resource", "default": false, "description": "Enable or disable Rename." }, "somesass.css.selectionRanges.enabled": { + "order": 120, "type": "boolean", "scope": "resource", "default": false, "description": "Enable or disable selection ranges." }, "somesass.css.signatureHelp.enabled": { + "order": 130, "type": "boolean", "scope": "resource", "default": false, "description": "Enable or disable selection ranges." }, "somesass.css.workspaceSymbol.enabled": { + "order": 140, "type": "boolean", "scope": "resource", "default": false, From c12b8ee455ef332e0740ef96fbd71738ad33c622 Mon Sep 17 00:00:00 2001 From: William Killerud Date: Wed, 25 Sep 2024 18:31:33 +0200 Subject: [PATCH 14/23] fix: don't lose default settings from Code if v1 exists --- packages/language-server/src/configuration.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/language-server/src/configuration.ts b/packages/language-server/src/configuration.ts index b3c08ea7..41784515 100644 --- a/packages/language-server/src/configuration.ts +++ b/packages/language-server/src/configuration.ts @@ -6,7 +6,7 @@ import { export function toNewConfiguration( v1: Partial, ): LanguageServiceConfiguration { - const newSettings = Object.assign({}, defaultConfiguration); + const newSettings = Object.assign({}, defaultConfiguration, v1); if (v1.loadPaths) newSettings.workspace.loadPaths = v1.loadPaths; if (v1.scannerExclude) newSettings.workspace.exclude = v1.scannerExclude; From c1a02dd7a4487e08c5b80d03401ceea3f7b2750d Mon Sep 17 00:00:00 2001 From: William Killerud Date: Wed, 25 Sep 2024 18:33:48 +0200 Subject: [PATCH 15/23] fix: look for name equality Had an odd findDefinition where a Go to defintion for $_var found $_var and $_varsling. I don't recall why this was includes in the first place. --- packages/language-services/src/features/find-definition.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/language-services/src/features/find-definition.ts b/packages/language-services/src/features/find-definition.ts index ffa602d8..ec9ddf96 100644 --- a/packages/language-services/src/features/find-definition.ts +++ b/packages/language-services/src/features/find-definition.ts @@ -142,7 +142,7 @@ export class FindDefinition extends LanguageFeature { for (const document of documents) { const symbols = this.ls.findDocumentSymbols(document); for (const symbol of symbols) { - if (!symbol.name.includes(name)) { + if (symbol.name !== name) { continue; } if (kinds.includes(symbol.kind)) { From 6466f97452f8c6deda9633792eb735703f4b15bc Mon Sep 17 00:00:00 2001 From: William Killerud Date: Wed, 25 Sep 2024 19:03:16 +0200 Subject: [PATCH 16/23] fix: loglevel --- .../{utils => }/__tests__/embedded.test.ts | 0 .../src/__tests__/logger.test.ts | 116 ++++++++++++++++++ .../src/{utils => }/embedded.ts | 0 packages/language-server/src/logger.ts | 41 ++++--- packages/language-server/src/server.ts | 4 +- .../language-server/src/workspace-scanner.ts | 2 +- 6 files changed, 142 insertions(+), 21 deletions(-) rename packages/language-server/src/{utils => }/__tests__/embedded.test.ts (100%) create mode 100644 packages/language-server/src/__tests__/logger.test.ts rename packages/language-server/src/{utils => }/embedded.ts (100%) diff --git a/packages/language-server/src/utils/__tests__/embedded.test.ts b/packages/language-server/src/__tests__/embedded.test.ts similarity index 100% rename from packages/language-server/src/utils/__tests__/embedded.test.ts rename to packages/language-server/src/__tests__/embedded.test.ts diff --git a/packages/language-server/src/__tests__/logger.test.ts b/packages/language-server/src/__tests__/logger.test.ts new file mode 100644 index 00000000..1fa765eb --- /dev/null +++ b/packages/language-server/src/__tests__/logger.test.ts @@ -0,0 +1,116 @@ +import { assert, test, vi } from "vitest"; +import { createLogger } from "../logger"; + +test("default log level is info", () => { + const remote = { + debug: vi.fn(), + info: vi.fn(), + error: vi.fn(), + warn: vi.fn(), + }; + const log = createLogger(remote); + + log.trace("hello"); + log.debug("hello"); + log.info("hello"); + log.warn("hello"); + log.error("hello"); + log.fatal("hello"); + + assert.equal(remote.debug.mock.calls.length, 0); + assert.equal(remote.info.mock.calls.length, 1); + assert.equal(remote.warn.mock.calls.length, 1); + assert.equal(remote.error.mock.calls.length, 2); +}); + +test("trace logs all the things", () => { + const remote = { + debug: vi.fn(), + info: vi.fn(), + error: vi.fn(), + warn: vi.fn(), + }; + const log = createLogger(remote); + log.setLogLevel("trace"); + + log.trace("hello"); + log.debug("hello"); + log.info("hello"); + log.warn("hello"); + log.error("hello"); + log.fatal("hello"); + + assert.equal(remote.debug.mock.calls.length, 2); + assert.equal(remote.info.mock.calls.length, 1); + assert.equal(remote.warn.mock.calls.length, 1); + assert.equal(remote.error.mock.calls.length, 2); +}); + +test("warn logs warn, error and fatal", () => { + const remote = { + debug: vi.fn(), + info: vi.fn(), + error: vi.fn(), + warn: vi.fn(), + }; + const log = createLogger(remote); + log.setLogLevel("warn"); + + log.trace("hello"); + log.debug("hello"); + log.info("hello"); + log.warn("hello"); + log.error("hello"); + log.fatal("hello"); + + assert.equal(remote.debug.mock.calls.length, 0); + assert.equal(remote.info.mock.calls.length, 0); + assert.equal(remote.warn.mock.calls.length, 1); + assert.equal(remote.error.mock.calls.length, 2); +}); + +test("error logs error and fatal", () => { + const remote = { + debug: vi.fn(), + info: vi.fn(), + error: vi.fn(), + warn: vi.fn(), + }; + const log = createLogger(remote); + log.setLogLevel("error"); + + log.trace("hello"); + log.debug("hello"); + log.info("hello"); + log.warn("hello"); + log.error("hello"); + log.fatal("hello"); + + assert.equal(remote.debug.mock.calls.length, 0); + assert.equal(remote.info.mock.calls.length, 0); + assert.equal(remote.warn.mock.calls.length, 0); + assert.equal(remote.error.mock.calls.length, 2); +}); + +test("silent logs nothing", () => { + const remote = { + debug: vi.fn(), + info: vi.fn(), + error: vi.fn(), + warn: vi.fn(), + }; + const log = createLogger(remote); + log.setLogLevel("silent"); + + log.trace("hello"); + log.debug("hello"); + log.info("hello"); + log.warn("hello"); + log.error("hello"); + log.fatal("hello"); + + assert.equal(remote.debug.mock.calls.length, 0); + assert.equal(remote.info.mock.calls.length, 0); + assert.equal(remote.warn.mock.calls.length, 0); + assert.equal(remote.error.mock.calls.length, 0); +}); diff --git a/packages/language-server/src/utils/embedded.ts b/packages/language-server/src/embedded.ts similarity index 100% rename from packages/language-server/src/utils/embedded.ts rename to packages/language-server/src/embedded.ts diff --git a/packages/language-server/src/logger.ts b/packages/language-server/src/logger.ts index 97886a7e..c332e993 100644 --- a/packages/language-server/src/logger.ts +++ b/packages/language-server/src/logger.ts @@ -1,4 +1,9 @@ -import type { Connection } from "vscode-languageserver"; +import type { RemoteConsole } from "vscode-languageserver"; + +export type RemoteLogger = Pick< + RemoteConsole, + "debug" | "info" | "warn" | "error" +>; export interface Logger { fatal(message: string): void; @@ -42,11 +47,11 @@ function levelToRank(level: string): number { } class LoggerImpl implements Logger { - #connection: Connection; + #remoteConsole: RemoteLogger; #level: number = levelToRank("info"); - constructor(connection: Connection) { - this.#connection = connection; + constructor(remoteConsole: RemoteLogger) { + this.#remoteConsole = remoteConsole; try { const levelArg = process.argv.indexOf("--loglevel"); if (levelArg !== -1) { @@ -60,42 +65,42 @@ class LoggerImpl implements Logger { } fatal(message: string): void { - if (this.#level <= fatal) { - this.#connection.console.error(message); + if (this.#level >= fatal) { + this.#remoteConsole.error(message); } } error(message: string): void { - if (this.#level <= error) { - this.#connection.console.error(message); + if (this.#level >= error) { + this.#remoteConsole.error(message); } } warn(message: string): void { - if (this.#level <= warn) { - this.#connection.console.warn(message); + if (this.#level >= warn) { + this.#remoteConsole.warn(message); } } info(message: string): void { - if (this.#level <= info) { - this.#connection.console.info(message); + if (this.#level >= info) { + this.#remoteConsole.info(message); } } debug(message: string): void { - if (this.#level <= debug) { - this.#connection.console.debug(message); + if (this.#level >= debug) { + this.#remoteConsole.debug(message); } } trace(message: string): void { - if (this.#level <= trace) { - this.#connection.console.debug(message); + if (this.#level >= trace) { + this.#remoteConsole.debug(message); } } } -export function createLogger(connection: Connection): Logger { - return new LoggerImpl(connection); +export function createLogger(remoteConsole: RemoteLogger): Logger { + return new LoggerImpl(remoteConsole); } diff --git a/packages/language-server/src/server.ts b/packages/language-server/src/server.ts index c22914f9..e96757fe 100644 --- a/packages/language-server/src/server.ts +++ b/packages/language-server/src/server.ts @@ -28,7 +28,7 @@ import { isOldConfiguration, toNewConfiguration, } from "./configuration"; -import { getSassRegionsDocument } from "./utils/embedded"; +import { getSassRegionsDocument } from "./embedded"; import WorkspaceScanner from "./workspace-scanner"; import { createLogger, type Logger } from "./logger"; import { @@ -46,7 +46,7 @@ export class SomeSassServer { constructor(connection: Connection, runtime: RuntimeEnvironment) { this.connection = connection; this.runtime = runtime; - this.log = createLogger(connection); + this.log = createLogger(connection.console); this.log.trace(`Process ID ${process.pid}`); } diff --git a/packages/language-server/src/workspace-scanner.ts b/packages/language-server/src/workspace-scanner.ts index 8e8585f9..a6b1c5d1 100644 --- a/packages/language-server/src/workspace-scanner.ts +++ b/packages/language-server/src/workspace-scanner.ts @@ -4,7 +4,7 @@ import { } from "@somesass/language-services"; import { TextDocument } from "vscode-languageserver-textdocument"; import { URI } from "vscode-uri"; -import { getSassRegionsDocument } from "./utils/embedded"; +import { getSassRegionsDocument } from "./embedded"; export default class WorkspaceScanner { #ls: LanguageService; From 9ca727a2d8a70e32c795be6b79895be49c81be96 Mon Sep 17 00:00:00 2001 From: William Killerud Date: Wed, 25 Sep 2024 19:16:57 +0200 Subject: [PATCH 17/23] fix: log migration help for old settings --- packages/language-server/src/configuration.ts | 30 ++++++++++++++----- packages/language-server/src/server.ts | 8 +++-- 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/packages/language-server/src/configuration.ts b/packages/language-server/src/configuration.ts index 41784515..72f894c4 100644 --- a/packages/language-server/src/configuration.ts +++ b/packages/language-server/src/configuration.ts @@ -2,24 +2,26 @@ import { defaultConfiguration, type LanguageServiceConfiguration, } from "@somesass/language-services"; +import { Logger } from "./logger"; export function toNewConfiguration( v1: Partial, + log: Logger, ): LanguageServiceConfiguration { const newSettings = Object.assign({}, defaultConfiguration, v1); - if (v1.loadPaths) newSettings.workspace.loadPaths = v1.loadPaths; - if (v1.scannerExclude) newSettings.workspace.exclude = v1.scannerExclude; + if (v1.loadPaths) { + log.info("somesass.loadPaths is now somesass.workspace.loadPaths"); + newSettings.workspace.loadPaths = v1.loadPaths; + } + if (v1.scannerExclude) { + log.info("somesass.scannerExclude is now somesass.workspace.exclude"); + newSettings.workspace.exclude = v1.scannerExclude; + } if (typeof v1.suggestAllFromOpenDocument !== "undefined") { newSettings.css.completion.includeFromCurrentDocument = v1.suggestAllFromOpenDocument; } - if (typeof v1.suggestionStyle !== "undefined") { - newSettings.css.completion.mixinStyle = v1.suggestionStyle; - } - if (typeof v1.suggestFromUseOnly !== "undefined") { - newSettings.css.completion.suggestFromUseOnly = v1.suggestFromUseOnly; - } if (typeof v1.triggerPropertyValueCompletion !== "undefined") { newSettings.css.completion.triggerPropertyValueCompletion = v1.triggerPropertyValueCompletion; @@ -41,16 +43,28 @@ export function toNewConfiguration( } if (typeof v1.suggestAllFromOpenDocument !== "undefined") { + log.info( + "somesass.suggestAllFromOpenDocument is now somesass.scss.completion.includeFromCurrentDocument and somesass.sass.completion.includeFromCurrentDocument", + ); newSettings.scss.completion.includeFromCurrentDocument = v1.suggestAllFromOpenDocument; } if (typeof v1.suggestionStyle !== "undefined") { + log.info( + "somesass.suggestionStyle is now somesass.scss.completion.mixinStyle and somesass.sass.completion.mixinStyle", + ); newSettings.scss.completion.mixinStyle = v1.suggestionStyle; } if (typeof v1.suggestFromUseOnly !== "undefined") { + log.info( + "somesass.suggestFromUseOnly is now somesass.scss.completion.suggestFromUseOnly and somesass.sass.completion.suggestFromUseOnly", + ); newSettings.scss.completion.suggestFromUseOnly = v1.suggestFromUseOnly; } if (typeof v1.triggerPropertyValueCompletion !== "undefined") { + log.info( + "somesass.triggerPropertyValueCompletion is now somesass.scss.completion.triggerPropertyValueCompletion and somesass.sass.completion.triggerPropertyValueCompletion", + ); newSettings.scss.completion.triggerPropertyValueCompletion = v1.triggerPropertyValueCompletion; } diff --git a/packages/language-server/src/server.ts b/packages/language-server/src/server.ts index e96757fe..ef0b43d4 100644 --- a/packages/language-server/src/server.ts +++ b/packages/language-server/src/server.ts @@ -136,9 +136,13 @@ export class SomeSassServer { ): LanguageServiceConfiguration => { if (isOldConfiguration(somesass)) { this.log.warn( - `Your somesass configuration uses old setting names. They will continue to work for some time, but it's recommended you change your settings to the new names. For new setting IDs see https://wkillerud.github.io/some-sass/user-guide/settings.html`, + `Your somesass configuration uses old setting names. They will continue to work for some time, but it's recommended you change your settings to the new names. For all the available settings see https://wkillerud.github.io/some-sass/user-guide/settings.html`, + ); + + somesass = toNewConfiguration( + somesass as Partial, + this.log, ); - somesass = toNewConfiguration(somesass as Partial); } const settings: LanguageServiceConfiguration = merge( From 6c24f345b338cefe66bc027112dfb8e86f52cc96 Mon Sep 17 00:00:00 2001 From: William Killerud Date: Wed, 25 Sep 2024 19:23:27 +0200 Subject: [PATCH 18/23] fix: await things so we can log --- packages/language-server/src/server.ts | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/packages/language-server/src/server.ts b/packages/language-server/src/server.ts index ef0b43d4..8cb76139 100644 --- a/packages/language-server/src/server.ts +++ b/packages/language-server/src/server.ts @@ -143,6 +143,10 @@ export class SomeSassServer { somesass as Partial, this.log, ); + + this.log.info( + "Replace old setting IDs with new ones to remove these messages", + ); } const settings: LanguageServiceConfiguration = merge( @@ -166,7 +170,7 @@ export class SomeSassServer { } this.log.debug("Applied user configuration"); - this.log.trace(JSON.stringify(this.configuration)); + this.log.trace(JSON.stringify(this.configuration, null, 2)); return settings; }; @@ -339,7 +343,7 @@ export class SomeSassServer { } }); - this.connection.onHover((params) => { + this.connection.onHover(async (params) => { if (!ls) return null; try { const document = getSassRegionsDocument( @@ -350,7 +354,7 @@ export class SomeSassServer { const config = this.languageConfiguration(document); if (config.hover.enabled) { - const result = ls.doHover(document, params.position); + const result = await ls.doHover(document, params.position); return result; } else { return null; @@ -383,7 +387,7 @@ export class SomeSassServer { } }); - this.connection.onDefinition((params) => { + this.connection.onDefinition(async (params) => { if (!ls) return null; try { const document = getSassRegionsDocument( @@ -394,7 +398,7 @@ export class SomeSassServer { const config = this.languageConfiguration(document); if (config.definition.enabled) { - const result = ls.findDefinition(document, params.position); + const result = await ls.findDefinition(document, params.position); return result; } else { return null; @@ -416,15 +420,11 @@ export class SomeSassServer { const config = this.languageConfiguration(document); if (config.highlights.enabled) { - try { - if (initialScan) { - await initialScan; - } - const result = ls.findDocumentHighlights(document, params.position); - return result; - } catch { - // Do nothing + if (initialScan) { + await initialScan; } + const result = ls.findDocumentHighlights(document, params.position); + return result; } else { return null; } From 35da87b0f91c1e1f4e7c12ce6657664cb992a58b Mon Sep 17 00:00:00 2001 From: William Killerud Date: Wed, 25 Sep 2024 19:45:26 +0200 Subject: [PATCH 19/23] fix: setting for css completions in Sass, SCSS --- docs/src/user-guide/settings.md | 2 ++ packages/language-server/rspack.node.config.js | 1 + .../language-services/src/configuration.ts | 3 +++ .../__tests__/do-complete-modules.test.ts | 1 + .../src/features/__tests__/do-complete.test.ts | 3 ++- .../src/features/do-complete.ts | 10 +++++----- .../language-services/src/features/do-hover.ts | 6 +++--- .../src/language-services-types.ts | 4 ++++ vscode-extension/package.json | 18 ++++++++++++++++-- 9 files changed, 37 insertions(+), 11 deletions(-) diff --git a/docs/src/user-guide/settings.md b/docs/src/user-guide/settings.md index 5eb562d4..64aa3c4d 100644 --- a/docs/src/user-guide/settings.md +++ b/docs/src/user-guide/settings.md @@ -60,6 +60,7 @@ Open your user settings JSON and paste this configuration. You may want to resta "somesass.scss.colors.enabled": true, "somesass.scss.colors.includeFromCurrentDocument": true, "somesass.scss.completion.enabled": true, + "somesass.scss.completion.css": true, "somesass.scss.completion.includeFromCurrentDocument": true, "somesass.scss.definition.enabled": true, "somesass.scss.diagnostics.enabled": true, @@ -67,6 +68,7 @@ Open your user settings JSON and paste this configuration. You may want to resta "somesass.scss.foldingRanges.enabled": true, "somesass.scss.highlights.enabled": true, "somesass.scss.hover.enabled": true, + "somesass.scss.hover.documentation": true, "somesass.scss.links.enabled": true, "somesass.scss.references.enabled": true, "somesass.scss.rename.enabled": true, diff --git a/packages/language-server/rspack.node.config.js b/packages/language-server/rspack.node.config.js index a8c4892f..9fa940bd 100644 --- a/packages/language-server/rspack.node.config.js +++ b/packages/language-server/rspack.node.config.js @@ -28,6 +28,7 @@ const config = { syntax: "typescript", }, externalHelpers: true, + target: "es2022", }, }, }, diff --git a/packages/language-services/src/configuration.ts b/packages/language-services/src/configuration.ts index 0f790a10..39f4c302 100644 --- a/packages/language-services/src/configuration.ts +++ b/packages/language-services/src/configuration.ts @@ -19,6 +19,7 @@ export const defaultConfiguration: LanguageServerConfiguration = { }, completion: { enabled: true, + css: true, includeFromCurrentDocument: true, completePropertyWithSemicolon: true, triggerPropertyValueCompletion: true, @@ -98,6 +99,7 @@ export const defaultConfiguration: LanguageServerConfiguration = { }, completion: { enabled: true, + css: true, mixinStyle: "all", includeFromCurrentDocument: true, suggestFromUseOnly: false, @@ -178,6 +180,7 @@ export const defaultConfiguration: LanguageServerConfiguration = { }, completion: { enabled: true, + css: true, mixinStyle: "all", includeFromCurrentDocument: true, suggestFromUseOnly: false, diff --git a/packages/language-services/src/features/__tests__/do-complete-modules.test.ts b/packages/language-services/src/features/__tests__/do-complete-modules.test.ts index d6c1b8f7..effd42d6 100644 --- a/packages/language-services/src/features/__tests__/do-complete-modules.test.ts +++ b/packages/language-services/src/features/__tests__/do-complete-modules.test.ts @@ -16,6 +16,7 @@ beforeEach(() => { scss: { completion: { suggestFromUseOnly: true, + css: false, }, }, sass: { diff --git a/packages/language-services/src/features/__tests__/do-complete.test.ts b/packages/language-services/src/features/__tests__/do-complete.test.ts index b1f1204c..8b8c9332 100644 --- a/packages/language-services/src/features/__tests__/do-complete.test.ts +++ b/packages/language-services/src/features/__tests__/do-complete.test.ts @@ -9,8 +9,9 @@ const ls = getLanguageService({ fileSystemProvider, ...rest }); ls.configure({ scss: { completion: { - suggestAllFromOpenDocument: true, + includeFromCurrentDocument: true, suggestFromUseOnly: false, + css: false, }, }, }); diff --git a/packages/language-services/src/features/do-complete.ts b/packages/language-services/src/features/do-complete.ts index f940d7cb..5ea68f66 100644 --- a/packages/language-services/src/features/do-complete.ts +++ b/packages/language-services/src/features/do-complete.ts @@ -353,15 +353,15 @@ export class DoComplete extends LanguageFeature { } } - if (document.languageId === "sass") { - const upstreamResult = await upstreamLs.doComplete2( + if (config.completion.css) { + const cssResults = await upstreamLs.doComplete2( document, position, stylesheet, this.getDocumentContext(), ); - if (upstreamResult.items.length > 0) { - result.items.push(...upstreamResult.items); + if (cssResults.items.length > 0) { + result.items.push(...cssResults.items); } } @@ -520,7 +520,7 @@ export class DoComplete extends LanguageFeature { const items: CompletionItem[] = []; const result = await this.findInWorkspace((document) => { // keep track of visited to avoid duplicates - // if completionSettings?.suggestFromUseOnly is false + // if suggestFromUseOnly is false visited.add(document.uri); const symbols = this.ls.findDocumentSymbols(document); diff --git a/packages/language-services/src/features/do-hover.ts b/packages/language-services/src/features/do-hover.ts index 6e4e16ba..b8e5376e 100644 --- a/packages/language-services/src/features/do-hover.ts +++ b/packages/language-services/src/features/do-hover.ts @@ -68,9 +68,9 @@ export class DoHover extends LanguageFeature { type = SymbolKind.Method; } if (type === null) { - if (document.languageId === "sass") { - // We are probably hovering over a CSS identifier - // and want to defer this to vscode-css-languageservice's hover handler + if (config.hover.documentation) { + // We are probably hovering over a CSS identifier. + // In VS Code, by default we defer this to vscode-css-languageservice's hover handler. return this.getUpstreamLanguageServer(document).doHover( document, position, diff --git a/packages/language-services/src/language-services-types.ts b/packages/language-services/src/language-services-types.ts index 12d98874..88d72abd 100644 --- a/packages/language-services/src/language-services-types.ts +++ b/packages/language-services/src/language-services-types.ts @@ -209,6 +209,10 @@ export interface LanguageConfiguration { }; completion: { enabled: boolean; + /** + * Include CSS completions. + */ + css?: boolean; /** * Mixins with `@content` SassDoc annotations and `%placeholders` get two suggestions by default: * - One without `{ }`. diff --git a/vscode-extension/package.json b/vscode-extension/package.json index 2e6a95a1..5bdbcb8b 100644 --- a/vscode-extension/package.json +++ b/vscode-extension/package.json @@ -176,6 +176,13 @@ "Where brackets are suggested, don't suggest without brackets" ] }, + "somesass.scss.completion.css": { + "order": 33, + "type": "boolean", + "scope": "resource", + "default": false, + "description": "Compatibility setting for VS Code. Enable or disable CSS completions (IntelliSense). The built-in SCSS language server provides this, so by default it's turned off in Some Sass." + }, "somesass.scss.completion.triggerPropertyValueCompletion": { "order": 33, "type": "boolean", @@ -488,7 +495,7 @@ "order": 81, "type": "boolean", "scope": "resource", - "default": true, + "default": false, "description": "Show property and value documentation in CSS hovers." }, "somesass.scss.hover.references": { @@ -496,7 +503,7 @@ "type": "boolean", "scope": "resource", "default": true, - "description": "Show references to MDN in CSS hovers, Sass documentation for Sass built-in modules and SassDoc for annotations." + "description": "Show references to Sass documentation for Sass built-in modules and SassDoc for annotations." }, "somesass.scss.links.enabled": { "order": 90, @@ -593,6 +600,13 @@ "Where brackets are suggested, omit duplicates without brackets" ] }, + "somesass.sass.completion.css": { + "order": 33, + "type": "boolean", + "scope": "resource", + "default": true, + "description": "Enable or disable CSS completions (IntelliSense)." + }, "somesass.sass.completion.triggerPropertyValueCompletion": { "order": 33, "type": "boolean", From 7eb2c186a48a566c013dad63f33afaf6bd9c7d50 Mon Sep 17 00:00:00 2001 From: William Killerud Date: Thu, 26 Sep 2024 17:59:34 +0200 Subject: [PATCH 20/23] chore: configure rsdoctor --- package-lock.json | 778 +++++++++++++++++- packages/language-server/package.json | 17 +- .../language-server/rspack.browser.config.js | 5 +- .../language-server/rspack.node.config.js | 5 + 4 files changed, 794 insertions(+), 11 deletions(-) diff --git a/package-lock.json b/package-lock.json index b4499e3a..ff02f117 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4968,6 +4968,441 @@ "win32" ] }, + "node_modules/@rsdoctor/client": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/@rsdoctor/client/-/client-0.4.4.tgz", + "integrity": "sha512-xMtOWtLR9qidnXhQTRaaMVHhNqPYApk3uN5cGQJwWJDzmNNmmVeB663sIpHPKXD8cmC/w0z4SDjWA4jue8LM2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rsdoctor/core": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/@rsdoctor/core/-/core-0.4.4.tgz", + "integrity": "sha512-cV1f9Fu/S9cjZ9F/oWhgIZHaX0qZJVNh2/DS9vh0gWBZJhBVPz5NBCKjA322W7hGT343sadVdys2PqIxjCHcOw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rsdoctor/graph": "0.4.4", + "@rsdoctor/sdk": "0.4.4", + "@rsdoctor/types": "0.4.4", + "@rsdoctor/utils": "0.4.4", + "axios": "^1.7.2", + "enhanced-resolve": "5.12.0", + "filesize": "^10.1.6", + "fs-extra": "^11.1.1", + "lodash": "^4.17.21", + "path-browserify": "1.0.1", + "semver": "^7.6.3", + "source-map": "^0.7.4", + "webpack-bundle-analyzer": "^4.10.2" + } + }, + "node_modules/@rsdoctor/core/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/@rsdoctor/core/node_modules/enhanced-resolve": { + "version": "5.12.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.12.0.tgz", + "integrity": "sha512-QHTXI/sZQmko1cbDoNAa3mJ5qhWUUNAq3vR0/YiD379fWQrcfuoX1+HW2S0MTt7XmoPLapdaDKUtelUSPic7hQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/@rsdoctor/core/node_modules/mrmime": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.0.tgz", + "integrity": "sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/@rsdoctor/core/node_modules/sirv": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-2.0.4.tgz", + "integrity": "sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@polka/url": "^1.0.0-next.24", + "mrmime": "^2.0.0", + "totalist": "^3.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@rsdoctor/core/node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@rsdoctor/core/node_modules/totalist": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", + "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/@rsdoctor/core/node_modules/webpack-bundle-analyzer": { + "version": "4.10.2", + "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.10.2.tgz", + "integrity": "sha512-vJptkMm9pk5si4Bv922ZbKLV8UTT4zib4FPgXMhgzUny0bfDDkLXAVQs3ly3fS4/TN9ROFtb0NFrm04UXFE/Vw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@discoveryjs/json-ext": "0.5.7", + "acorn": "^8.0.4", + "acorn-walk": "^8.0.0", + "commander": "^7.2.0", + "debounce": "^1.2.1", + "escape-string-regexp": "^4.0.0", + "gzip-size": "^6.0.0", + "html-escaper": "^2.0.2", + "opener": "^1.5.2", + "picocolors": "^1.0.0", + "sirv": "^2.0.3", + "ws": "^7.3.1" + }, + "bin": { + "webpack-bundle-analyzer": "lib/bin/analyzer.js" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/@rsdoctor/core/node_modules/ws": { + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/@rsdoctor/graph": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/@rsdoctor/graph/-/graph-0.4.4.tgz", + "integrity": "sha512-ZcCRo9ydqyNI5otai+qUGxw4HZQAE0Rolb9tV4aadNudl7A2Mcm6FT6yECB4jlbNECqc8B5kHKZuz971WgFkLA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rsdoctor/types": "0.4.4", + "@rsdoctor/utils": "0.4.4", + "lodash": "^4.17.21", + "socket.io": "4.7.2", + "source-map": "^0.7.4" + } + }, + "node_modules/@rsdoctor/graph/node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@rsdoctor/rspack-plugin": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/@rsdoctor/rspack-plugin/-/rspack-plugin-0.4.4.tgz", + "integrity": "sha512-HwYnP82HqP5p6z8kdCJ5owULCHw1smNBd90sggElZlphzo2ihdR1SLjg8mcaE5ttDhRGqhYjaXcRCZFyaexTzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rsdoctor/core": "0.4.4", + "@rsdoctor/graph": "0.4.4", + "@rsdoctor/sdk": "0.4.4", + "@rsdoctor/types": "0.4.4", + "@rsdoctor/utils": "0.4.4", + "lodash": "^4.17.21" + }, + "peerDependencies": { + "@rspack/core": "*" + } + }, + "node_modules/@rsdoctor/sdk": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/@rsdoctor/sdk/-/sdk-0.4.4.tgz", + "integrity": "sha512-Y+ySVfrFAT0GVwI0xTU/BdEsufnC/+1eLYISWTEa19MdWU/RpcLqsIdglKNbDUbS6k0AELOvl7CUuOiI0go8gw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rsdoctor/client": "0.4.4", + "@rsdoctor/graph": "0.4.4", + "@rsdoctor/types": "0.4.4", + "@rsdoctor/utils": "0.4.4", + "@types/fs-extra": "^11.0.4", + "body-parser": "1.20.3", + "cors": "2.8.5", + "dayjs": "1.11.13", + "fs-extra": "^11.1.1", + "lodash": "^4.17.21", + "open": "^8.4.2", + "serve-static": "1.16.0", + "socket.io": "4.7.2", + "source-map": "^0.7.4", + "tapable": "2.2.1" + } + }, + "node_modules/@rsdoctor/sdk/node_modules/body-parser": { + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", + "dev": true, + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.13.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/@rsdoctor/sdk/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/@rsdoctor/sdk/node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@rsdoctor/sdk/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rsdoctor/sdk/node_modules/qs": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.0.6" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/@rsdoctor/sdk/node_modules/serve-static": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.0.tgz", + "integrity": "sha512-pDLK8zwl2eKaYrs8mrPZBJua4hMplRWJ1tIFksVC3FtBEBnl8dxgeHtsaMS8DhS9i4fLObaon6ABoc4/hQGdPA==", + "dev": true, + "license": "MIT", + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/@rsdoctor/sdk/node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@rsdoctor/types": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/@rsdoctor/types/-/types-0.4.4.tgz", + "integrity": "sha512-Ltf03hd/gAazRTmrwz7SqNDqB+BHC0BBVwQi7wUVsF6MphvTaqSdAocNefTgWDeXj0WEP0Vy5wrj+aUPTbPWtg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/connect": "3.4.38", + "@types/estree": "1.0.5", + "@types/tapable": "2.2.7", + "source-map": "^0.7.4" + }, + "peerDependencies": { + "@rspack/core": "*", + "webpack": "5.x" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + } + } + }, + "node_modules/@rsdoctor/types/node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@rsdoctor/utils": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/@rsdoctor/utils/-/utils-0.4.4.tgz", + "integrity": "sha512-J61vLwKdNnuToeU7ZfCIy5rYH4biMH7LfinQG9m4ySveyT9hD8z/CyxbpOlr7vdmnzBVzZCy+0aHm9UbhUpjxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "7.24.7", + "@rsdoctor/types": "0.4.4", + "@types/estree": "1.0.5", + "acorn": "^8.10.0", + "acorn-import-assertions": "1.9.0", + "acorn-walk": "8.3.4", + "chalk": "^4.1.2", + "connect": "3.7.0", + "deep-eql": "4.1.4", + "envinfo": "7.14.0", + "filesize": "^10.1.6", + "fs-extra": "^11.1.1", + "get-port": "5.1.1", + "json-stream-stringify": "3.0.1", + "lines-and-columns": "2.0.4", + "lodash": "^4.17.21", + "rslog": "^1.2.3", + "strip-ansi": "^6.0.1" + } + }, + "node_modules/@rsdoctor/utils/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@rsdoctor/utils/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@rsdoctor/utils/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@rsdoctor/utils/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rsdoctor/utils/node_modules/deep-eql": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.4.tgz", + "integrity": "sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-detect": "^4.0.0" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/@rspack/binding": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@rspack/binding/-/binding-1.0.3.tgz", @@ -5566,6 +6001,13 @@ "dev": true, "license": "MIT" }, + "node_modules/@socket.io/component-emitter": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz", + "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==", + "dev": true, + "license": "MIT" + }, "node_modules/@somesass/language-services": { "resolved": "packages/language-services", "link": true @@ -5974,6 +6416,23 @@ "@types/node": "*" } }, + "node_modules/@types/cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/cors": { + "version": "2.8.17", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz", + "integrity": "sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/eslint": { "version": "9.6.1", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", @@ -6028,6 +6487,17 @@ "@types/send": "*" } }, + "node_modules/@types/fs-extra": { + "version": "11.0.4", + "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-11.0.4.tgz", + "integrity": "sha512-yTbItCNreRooED33qjunPthRcSjERP1r4MqCZc7wv0u2sUkzTFp45tgUfS5+r7FrZPdmCCNflLhVSP/o+SemsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/jsonfile": "*", + "@types/node": "*" + } + }, "node_modules/@types/http-errors": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", @@ -6079,6 +6549,16 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/jsonfile": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/@types/jsonfile/-/jsonfile-6.1.4.tgz", + "integrity": "sha512-D5qGUYwjvnNNextdU59/+fI+spnwtTFmyQP0h+PfIOSkNfpU6AOICUOkm4i0OnSk+NyjdPJrxCDro0sJsWlRpQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/lodash": { "version": "4.17.7", "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.7.tgz", @@ -6199,6 +6679,16 @@ "@types/node": "*" } }, + "node_modules/@types/tapable": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/@types/tapable/-/tapable-2.2.7.tgz", + "integrity": "sha512-D6QzACV9vNX3r8HQQNTOnpG+Bv1rko+yEA82wKs3O9CQ5+XW7HI7TED17/UE7+5dIxyxZIWTxKbsBeF6uKFCwA==", + "dev": true, + "license": "MIT", + "dependencies": { + "tapable": "^2.2.0" + } + }, "node_modules/@types/vscode": { "version": "1.86.0", "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.86.0.tgz", @@ -7584,6 +8074,16 @@ "node": ">=0.4.0" } }, + "node_modules/acorn-import-assertions": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz", + "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^8" + } + }, "node_modules/acorn-import-attributes": { "version": "1.9.5", "resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz", @@ -7605,9 +8105,9 @@ } }, "node_modules/acorn-walk": { - "version": "8.3.3", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.3.tgz", - "integrity": "sha512-MxXdReSRhGO7VlFe1bRG/oI7/mdLV9B9JJT0N8vZOhF7gFRR5l3M8W9G8JxmKV+JC5mGqJ0QvqfSOLsCPa4nUw==", + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", + "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", "dev": true, "license": "MIT", "dependencies": { @@ -8177,6 +8677,16 @@ ], "license": "MIT" }, + "node_modules/base64id": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", + "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^4.5.0 || >= 5.9" + } + }, "node_modules/basic-auth": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", @@ -9159,6 +9669,22 @@ "dev": true, "license": "MIT" }, + "node_modules/connect": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", + "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "finalhandler": "1.1.2", + "parseurl": "~1.3.3", + "utils-merge": "1.0.1" + }, + "engines": { + "node": ">= 0.10.0" + } + }, "node_modules/connect-history-api-fallback": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", @@ -9169,6 +9695,65 @@ "node": ">=0.8" } }, + "node_modules/connect/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/connect/node_modules/finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/connect/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true, + "license": "MIT" + }, + "node_modules/connect/node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", + "dev": true, + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/connect/node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/content-disposition": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", @@ -9334,6 +9919,20 @@ "dev": true, "license": "MIT" }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/corser": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/corser/-/corser-2.0.1.tgz", @@ -9732,6 +10331,20 @@ "node": ">=4.0" } }, + "node_modules/dayjs": { + "version": "1.11.13", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz", + "integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==", + "dev": true, + "license": "MIT" + }, + "node_modules/debounce": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz", + "integrity": "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==", + "dev": true, + "license": "MIT" + }, "node_modules/debug": { "version": "4.3.6", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", @@ -10419,6 +11032,48 @@ "once": "^1.4.0" } }, + "node_modules/engine.io": { + "version": "6.5.5", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.5.tgz", + "integrity": "sha512-C5Pn8Wk+1vKBoHghJODM63yk8MvrO9EWZUfkAt5HAqIgPE4/8FF0PEGHXtEd40l223+cE5ABWuPzm38PHFXfMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/cookie": "^0.4.1", + "@types/cors": "^2.8.12", + "@types/node": ">=10.0.0", + "accepts": "~1.3.4", + "base64id": "2.0.0", + "cookie": "~0.4.1", + "cors": "~2.8.5", + "debug": "~4.3.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.17.1" + }, + "engines": { + "node": ">=10.2.0" + } + }, + "node_modules/engine.io-parser": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz", + "integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/engine.io/node_modules/cookie": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/enhanced-resolve": { "version": "5.17.1", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz", @@ -10469,6 +11124,19 @@ "node": ">=6" } }, + "node_modules/envinfo": { + "version": "7.14.0", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.14.0.tgz", + "integrity": "sha512-CO40UI41xDQzhLB1hWyqUKgFhs250pNcGbyGKe1l/e4FSaI/+YE4IMG76GDt0In67WLPACIITC+sOi08x4wIvg==", + "dev": true, + "license": "MIT", + "bin": { + "envinfo": "dist/cli.js" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/environment": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", @@ -11366,6 +12034,16 @@ "node": ">=10" } }, + "node_modules/filesize": { + "version": "10.1.6", + "resolved": "https://registry.npmjs.org/filesize/-/filesize-10.1.6.tgz", + "integrity": "sha512-sJslQKU2uM33qH5nqewAwVB2QgR6w1aMNsYUp3aN5rMRyXEwJGmZvaWzeJFNTOXWlHQyBFCWrdj3fV/fsTOX8w==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">= 10.4.0" + } + }, "node_modules/fill-range": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", @@ -11988,6 +12666,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-port": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/get-port/-/get-port-5.1.1.tgz", + "integrity": "sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/get-stdin": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", @@ -13805,6 +14496,13 @@ "dev": true, "license": "MIT" }, + "node_modules/json-stream-stringify": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-stream-stringify/-/json-stream-stringify-3.0.1.tgz", + "integrity": "sha512-vuxs3G1ocFDiAQ/SX0okcZbtqXwgj1g71qE9+vrjJ2EkjKQlEFDAcUNRxRU8O+GekV4v5cM2qXP0Wyt/EMDBiQ==", + "dev": true, + "license": "MIT" + }, "node_modules/json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", @@ -16532,6 +17230,16 @@ "node": ">=8" } }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/object-inspect": { "version": "1.13.2", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", @@ -19112,6 +19820,15 @@ "fsevents": "~2.3.2" } }, + "node_modules/rslog": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/rslog/-/rslog-1.2.3.tgz", + "integrity": "sha512-antALPJaKBRPBU1X2q9t085K4htWDOOv/K1qhTUk7h0l1ePU/KbDqKJn19eKP0dk7PqMioeA0+fu3gyPXCsXxQ==", + "dev": true, + "engines": { + "node": ">=14.17.6" + } + }, "node_modules/run-applescript": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.0.0.tgz", @@ -19775,6 +20492,50 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/socket.io": { + "version": "4.7.2", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.7.2.tgz", + "integrity": "sha512-bvKVS29/I5fl2FGLNHuXlQaUH/BlzX1IN6S+NKLNZpBsPZIDH+90eQmCs2Railn4YUiww4SzUedJ6+uzwFnKLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "accepts": "~1.3.4", + "base64id": "~2.0.0", + "cors": "~2.8.5", + "debug": "~4.3.2", + "engine.io": "~6.5.2", + "socket.io-adapter": "~2.5.2", + "socket.io-parser": "~4.2.4" + }, + "engines": { + "node": ">=10.2.0" + } + }, + "node_modules/socket.io-adapter": { + "version": "2.5.5", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.5.tgz", + "integrity": "sha512-eLDQas5dzPgOWCk9GuuJC2lBqItuhKI4uxGgo9aIV7MYbk2h9Q6uULEh8WBzThoI7l+qU9Ast9fVUmkqPP9wYg==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "~4.3.4", + "ws": "~8.17.1" + } + }, + "node_modules/socket.io-parser": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", + "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", + "dev": true, + "license": "MIT", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/sockjs": { "version": "0.3.24", "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", @@ -21298,6 +22059,16 @@ "node": ">= 0.8.0" } }, + "node_modules/type-detect": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.1.0.tgz", + "integrity": "sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/type-is": { "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", @@ -22923,6 +23694,7 @@ "some-sass-language-server": "bin/some-sass-language-server" }, "devDependencies": { + "@rsdoctor/rspack-plugin": "0.4.4", "@somesass/language-services": "1.7.1", "@types/lodash.merge": "4.6.9", "@types/node": "20.16.5", diff --git a/packages/language-server/package.json b/packages/language-server/package.json index 481248b8..f1380d5b 100644 --- a/packages/language-server/package.json +++ b/packages/language-server/package.json @@ -41,17 +41,20 @@ "prepublishOnly": "run-s build:production:*", "prebuild": "tsc --noEmit", "build": "run-s build:development:*", - "build:node": "rspack --config ./rspack.node.config.js", - "build:browser": "rspack --config ./rspack.browser.config.js", - "build:development:node": "npm run build:node -- --mode=development", - "build:development:browser": "npm run build:browser -- --mode=development", - "build:production:node": "npm run build:node -- --mode=production", - "build:production:browser": "npm run build:browser -- --mode=production", + "build:node": "rspack --config ./rspack.node.config.js", + "build:browser": "rspack --config ./rspack.browser.config.js", + "build:development:node": "npm run build:node -- --mode=development", + "build:development:browser": "npm run build:browser -- --mode=development", + "build:production:node": "npm run build:node -- --mode=production", + "build:production:browser": "npm run build:browser -- --mode=production", "clean": "shx rm -rf dist node_modules", "test": "vitest", - "coverage": "vitest run --coverage" + "coverage": "vitest run --coverage", + "doctor:node": "RSDOCTOR=true run-s build:production:node", + "doctor:browser": "RSDOCTOR=true run-s build:production:browser" }, "devDependencies": { + "@rsdoctor/rspack-plugin": "0.4.4", "@somesass/language-services": "1.7.1", "@types/lodash.merge": "4.6.9", "@types/node": "20.16.5", diff --git a/packages/language-server/rspack.browser.config.js b/packages/language-server/rspack.browser.config.js index b65f8abe..ec76cd4f 100644 --- a/packages/language-server/rspack.browser.config.js +++ b/packages/language-server/rspack.browser.config.js @@ -1,6 +1,7 @@ /* eslint-disable */ const path = require("path"); const rspack = require("@rspack/core"); +const { RsdoctorRspackPlugin } = require("@rsdoctor/rspack-plugin"); /** @type {import('@rspack/core').Configuration} */ const config = { @@ -53,7 +54,9 @@ const config = { new rspack.ProvidePlugin({ process: "process/browser", }), - ], + // Only register the plugin when RSDOCTOR is true, as the plugin will increase the build time. + process.env.RSDOCTOR && new RsdoctorRspackPlugin(), + ].filter(Boolean), devtool: "cheap-source-map", }; diff --git a/packages/language-server/rspack.node.config.js b/packages/language-server/rspack.node.config.js index 9fa940bd..3b3c971c 100644 --- a/packages/language-server/rspack.node.config.js +++ b/packages/language-server/rspack.node.config.js @@ -1,6 +1,7 @@ /* eslint-disable */ const path = require("path"); const rspack = require("@rspack/core"); +const { RsdoctorRspackPlugin } = require("@rsdoctor/rspack-plugin"); /** @type {import('@rspack/core').Configuration} */ const config = { @@ -35,6 +36,10 @@ const config = { ], }, devtool: "cheap-source-map", + plugins: [ + // Only register the plugin when RSDOCTOR is true, as the plugin will increase the build time. + process.env.RSDOCTOR && new RsdoctorRspackPlugin(), + ].filter(Boolean), }; module.exports = (env, argv) => { From 1e1db61a8d2bf3438a963376d8c48bef4dd9b66e Mon Sep 17 00:00:00 2001 From: William Killerud Date: Thu, 26 Sep 2024 19:09:07 +0200 Subject: [PATCH 21/23] chore: configure build to prefer esm, split --- .scripts/release.mjs | 1 + package-lock.json | 6 +---- .../bin/some-sass-language-server | 7 +++-- .../language-server/rspack.browser.config.js | 6 ++++- .../language-server/rspack.node.config.js | 4 ++- packages/language-server/src/browser-main.ts | 4 +++ packages/language-server/src/node-main.ts | 4 +++ .../src/tsconfig.esm.json | 1 + .../src/tsconfig.json | 1 + vscode-extension/package.json | 4 ++- vscode-extension/rspack.browser.config.js | 25 +++++++++-------- vscode-extension/rspack.node.config.js | 27 ++++++++++--------- vscode-extension/rspack.test-web.config.js | 3 +++ vscode-extension/src/browser-client.ts | 5 +--- vscode-extension/src/node-client.ts | 2 +- 15 files changed, 62 insertions(+), 38 deletions(-) create mode 100644 packages/language-server/src/browser-main.ts create mode 100644 packages/language-server/src/node-main.ts diff --git a/.scripts/release.mjs b/.scripts/release.mjs index 786646e5..2a82e71b 100644 --- a/.scripts/release.mjs +++ b/.scripts/release.mjs @@ -22,6 +22,7 @@ async function call(command) { async function run() { await call(`git checkout main`); await call(`git pull`); + await call(`npm run clean`); await call(`npm clean-install`); await call(`npm run build`); await call(`npm run release`); diff --git a/package-lock.json b/package-lock.json index ff02f117..2230d969 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23805,7 +23805,7 @@ "some-sass-language-server": "1.8.3", "vscode-css-languageservice": "6.3.1", "vscode-languageclient": "9.0.1", - "vscode-uri": "3.0.7" + "vscode-uri": "3.0.8" }, "devDependencies": { "@types/mocha": "10.0.7", @@ -23843,10 +23843,6 @@ "engines": { "node": ">= 6" } - }, - "vscode-extension/node_modules/vscode-uri": { - "version": "3.0.7", - "license": "MIT" } } } diff --git a/packages/language-server/bin/some-sass-language-server b/packages/language-server/bin/some-sass-language-server index 04932a4b..90e12734 100755 --- a/packages/language-server/bin/some-sass-language-server +++ b/packages/language-server/bin/some-sass-language-server @@ -6,7 +6,10 @@ const args = process.argv; if (args.includes("--version") || args.includes("-v") || args.includes("-V")) { try { - const pkg = fs.readFileSync(path.join(__dirname, "..", "package.json"), "utf-8"); + const pkg = fs.readFileSync( + path.join(__dirname, "..", "package.json"), + "utf-8", + ); const json = JSON.parse(pkg); if (!json.version) { throw new Error(); @@ -25,4 +28,4 @@ For documentation, visit https://wkillerud.github.io/some-sass/language-server/g return; } -require(path.join(__dirname, "..", "dist", "node-server.js")); +require(path.join(__dirname, "..", "dist", "node-main.js")); diff --git a/packages/language-server/rspack.browser.config.js b/packages/language-server/rspack.browser.config.js index ec76cd4f..652bc135 100644 --- a/packages/language-server/rspack.browser.config.js +++ b/packages/language-server/rspack.browser.config.js @@ -8,7 +8,7 @@ const config = { context: __dirname, target: "webworker", entry: { - "browser-server": "./src/browser-server.ts", + "browser-main": "./src/browser-main.ts", }, output: { libraryTarget: "var", @@ -42,6 +42,7 @@ const config = { resolve: { extensions: [".ts", ".js"], mainFields: ["browser", "module", "main"], + conditionNames: ["import", "require", "default"], fallback: { events: require.resolve("events/"), path: require.resolve("path-browserify"), @@ -54,6 +55,9 @@ const config = { new rspack.ProvidePlugin({ process: "process/browser", }), + new rspack.optimize.LimitChunkCountPlugin({ + maxChunks: 1, + }), // Only register the plugin when RSDOCTOR is true, as the plugin will increase the build time. process.env.RSDOCTOR && new RsdoctorRspackPlugin(), ].filter(Boolean), diff --git a/packages/language-server/rspack.node.config.js b/packages/language-server/rspack.node.config.js index 3b3c971c..63c35b6a 100644 --- a/packages/language-server/rspack.node.config.js +++ b/packages/language-server/rspack.node.config.js @@ -7,7 +7,7 @@ const { RsdoctorRspackPlugin } = require("@rsdoctor/rspack-plugin"); const config = { target: "node", entry: { - "node-server": "./src/node-server.ts", + "node-main": "./src/node-main.ts", }, output: { filename: "[name].js", @@ -16,6 +16,8 @@ const config = { }, resolve: { extensions: [".ts", ".js"], + conditionNames: ["import", "require", "default"], + mainFields: ["module", "main"], }, module: { rules: [ diff --git a/packages/language-server/src/browser-main.ts b/packages/language-server/src/browser-main.ts new file mode 100644 index 00000000..8f8f229b --- /dev/null +++ b/packages/language-server/src/browser-main.ts @@ -0,0 +1,4 @@ +async function setupBrowser() { + await import("./browser-server"); +} +setupBrowser(); diff --git a/packages/language-server/src/node-main.ts b/packages/language-server/src/node-main.ts new file mode 100644 index 00000000..d7b93a66 --- /dev/null +++ b/packages/language-server/src/node-main.ts @@ -0,0 +1,4 @@ +async function setupNode() { + await import("./node-server"); +} +setupNode(); diff --git a/packages/vscode-css-languageservice/src/tsconfig.esm.json b/packages/vscode-css-languageservice/src/tsconfig.esm.json index bc6eaa7a..99a4c613 100644 --- a/packages/vscode-css-languageservice/src/tsconfig.esm.json +++ b/packages/vscode-css-languageservice/src/tsconfig.esm.json @@ -4,6 +4,7 @@ "module": "es6", "moduleResolution": "node", "sourceMap": true, + "inlineSourceMap": false, "declaration": true, "strict": true, "stripInternal": true, diff --git a/packages/vscode-css-languageservice/src/tsconfig.json b/packages/vscode-css-languageservice/src/tsconfig.json index fce46f01..f0b3655d 100644 --- a/packages/vscode-css-languageservice/src/tsconfig.json +++ b/packages/vscode-css-languageservice/src/tsconfig.json @@ -4,6 +4,7 @@ "module": "umd", "moduleResolution": "node", "sourceMap": true, + "inlineSourceMap": false, "declaration": true, "strict": true, "stripInternal": true, diff --git a/vscode-extension/package.json b/vscode-extension/package.json index 5bdbcb8b..4bc23b8e 100644 --- a/vscode-extension/package.json +++ b/vscode-extension/package.json @@ -1371,7 +1371,7 @@ "some-sass-language-server": "1.8.3", "vscode-css-languageservice": "6.3.1", "vscode-languageclient": "9.0.1", - "vscode-uri": "3.0.7" + "vscode-uri": "3.0.8" }, "devDependencies": { "@types/mocha": "10.0.7", @@ -1392,6 +1392,8 @@ "build:development:browser": "npm run build:browser -- --mode=development", "build:production:node": "npm run build:node -- --mode=production", "build:production:browser": "npm run build:browser -- --mode=production", + "doctor:node": "RSDOCTOR=true run-s build:production:node", + "doctor:browser": "RSDOCTOR=true run-s build:production:browser", "start:web": "vscode-test-web --browserType=chromium --extensionDevelopmentPath=.", "lint": "eslint \"**/*.ts\" --cache", "pretest:e2e": "run-s clean build:production:*", diff --git a/vscode-extension/rspack.browser.config.js b/vscode-extension/rspack.browser.config.js index 780e87c0..8e5f7ed1 100644 --- a/vscode-extension/rspack.browser.config.js +++ b/vscode-extension/rspack.browser.config.js @@ -12,10 +12,9 @@ const config = { "browser-client": "./src/browser-client.ts", }, output: { - libraryTarget: "commonjs", - - path: path.join(__dirname, "./dist"), filename: "[name].js", + path: path.join(__dirname, "./dist"), + libraryTarget: "commonjs", }, externals: { vscode: "commonjs vscode", @@ -24,8 +23,8 @@ const config = { devtool: false, resolve: { extensions: [".ts", ".js"], - - mainFields: ["browser", "module", "main"], // prefer `browser` entry point in imported modules + mainFields: ["browser", "module", "main"], + conditionNames: ["import", "require", "default"], fallback: { events: require.resolve("events/"), assert: require.resolve("assert"), @@ -55,23 +54,27 @@ const config = { }, ], }, -}; - -module.exports = (env, argv) => { - config.plugins?.push( + plugins: [ new rspack.ProvidePlugin({ process: "process/browser", }), + new rspack.optimize.LimitChunkCountPlugin({ + maxChunks: 1, + }), new rspack.CopyRspackPlugin({ patterns: [ { - from: "../node_modules/some-sass-language-server/dist/browser-server.*", + from: "../node_modules/some-sass-language-server/dist/**/*.js", to: "[name][ext]", }, ], }), - ); + // Only register the plugin when RSDOCTOR is true, as the plugin will increase the build time. + process.env.RSDOCTOR && new RsdoctorRspackPlugin(), + ].filter(Boolean), +}; +module.exports = (env, argv) => { if (argv.mode === "development") { config.devtool = "source-map"; } diff --git a/vscode-extension/rspack.node.config.js b/vscode-extension/rspack.node.config.js index d4caeae9..f2cf442d 100644 --- a/vscode-extension/rspack.node.config.js +++ b/vscode-extension/rspack.node.config.js @@ -2,6 +2,7 @@ const path = require("path"); const rspack = require("@rspack/core"); +const { RsdoctorRspackPlugin } = require("@rsdoctor/rspack-plugin"); /** @type {import('@rspack/core').Configuration} **/ const config = { @@ -21,8 +22,21 @@ const config = { }, resolve: { extensions: [".ts", ".js"], + conditionNames: ["import", "require", "default"], + mainFields: ["module", "main"], }, - plugins: [], + plugins: [ + new rspack.CopyRspackPlugin({ + patterns: [ + { + from: "../node_modules/some-sass-language-server/dist/**/*.js", + to: "[name][ext]", + }, + ], + }), + // Only register the plugin when RSDOCTOR is true, as the plugin will increase the build time. + process.env.RSDOCTOR && new RsdoctorRspackPlugin(), + ].filter(Boolean), devtool: false, module: { rules: [ @@ -44,17 +58,6 @@ const config = { }; module.exports = (env, argv) => { - config.plugins?.push( - new rspack.CopyRspackPlugin({ - patterns: [ - { - from: "../node_modules/some-sass-language-server/dist/node-server.*", - to: "[name][ext]", - }, - ], - }), - ); - if (argv.mode === "development") { config.devtool = "source-map"; } diff --git a/vscode-extension/rspack.test-web.config.js b/vscode-extension/rspack.test-web.config.js index 4ceb7dc2..7f9ffcd4 100644 --- a/vscode-extension/rspack.test-web.config.js +++ b/vscode-extension/rspack.test-web.config.js @@ -39,6 +39,9 @@ const browserTestsConfig = { }, ], }, + performance: { + hints: false, + }, plugins: [ new rspack.ProvidePlugin({ process: "process/browser", diff --git a/vscode-extension/src/browser-client.ts b/vscode-extension/src/browser-client.ts index 141c57d0..e3a68b19 100644 --- a/vscode-extension/src/browser-client.ts +++ b/vscode-extension/src/browser-client.ts @@ -145,10 +145,7 @@ function createWorkerLanguageClient( context: ExtensionContext, clientOptions: LanguageClientOptions, ) { - const serverMain = Uri.joinPath( - context.extensionUri, - "dist/browser-server.js", - ); + const serverMain = Uri.joinPath(context.extensionUri, "dist/browser-main.js"); const worker = new Worker(serverMain.toString(/* skipEncoding */ true)); return new LanguageClient( diff --git a/vscode-extension/src/node-client.ts b/vscode-extension/src/node-client.ts index f5e02a08..7974d940 100644 --- a/vscode-extension/src/node-client.ts +++ b/vscode-extension/src/node-client.ts @@ -67,7 +67,7 @@ function getOuterMostWorkspaceFolder(folder: WorkspaceFolder): WorkspaceFolder { } export async function activate(context: ExtensionContext): Promise { - const serverModule = context.asAbsolutePath(`./dist/node-server.js`); + const serverModule = context.asAbsolutePath(`./dist/node-main.js`); async function didOpenTextDocument(document: TextDocument): Promise { if ( From 07bca39453b74ba9005df5209a1d108eca4c4d99 Mon Sep 17 00:00:00 2001 From: William Killerud Date: Thu, 26 Sep 2024 20:50:27 +0200 Subject: [PATCH 22/23] refactor: review feedback --- .../src/language-server/configure-a-client.md | 6 +- docs/src/user-guide/settings.md | 19 ++-- packages/language-server/src/configuration.ts | 6 +- packages/language-server/src/embedded.ts | 6 +- packages/language-server/src/server.ts | 97 ++++++++++++------- .../language-server/src/workspace-scanner.ts | 26 ++--- .../src/features/do-complete.ts | 1 - .../src/features/find-symbols.ts | 1 - .../src/language-services.ts | 6 +- vscode-extension/package.json | 6 +- vscode-extension/src/client.ts | 8 +- vscode-extension/src/node-client.ts | 1 + 12 files changed, 108 insertions(+), 75 deletions(-) diff --git a/docs/src/language-server/configure-a-client.md b/docs/src/language-server/configure-a-client.md index aab5a8ca..eae2996f 100644 --- a/docs/src/language-server/configure-a-client.md +++ b/docs/src/language-server/configure-a-client.md @@ -18,10 +18,8 @@ For example, while we may document `"somesass.scss.workspace.loadPaths": []` (an { "settings": { "somesass": { - "scss": { - "workspace": { - "loadPaths": [] - } + "workspace": { + "loadPaths": [] } } } diff --git a/docs/src/user-guide/settings.md b/docs/src/user-guide/settings.md index 64aa3c4d..8030e574 100644 --- a/docs/src/user-guide/settings.md +++ b/docs/src/user-guide/settings.md @@ -37,7 +37,7 @@ Once you turn off the built-in language features you can configure Some Sass to Now that you disabled the built-in language features you need to turn on those language features in Some Sass. -Open your user settings JSON and paste this configuration. You may want to restart VS Code to make sure the changes apply. +Open your user settings JSON and paste this configuration. Restart VS Code to make sure the changes apply. ```json { @@ -82,6 +82,15 @@ Open your user settings JSON and paste this configuration. You may want to resta You can configure similar settings for both SCSS, Sass (indented) and CSS. There are also some settings that apply to the workspace regardless of syntax. +### Workspace + +| Id | Description | Default | +| ------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------- | +| `somesass.workspace.loadPaths` | A list of paths relative to the workspace root where the language server should look for stylesheets loaded by `@use` and `@import`. `node_modules` is always included. Note that you will have to [configure your Sass compiler separately](https://sass-lang.com/documentation/cli/dart-sass/#load-path). | `[]` | +| `somesass.workspace.exclude` | List of glob patterns for directories that are excluded in the initial scan for Sass files. Files in the exclude list will still be processed if referenced by `@use`, `@forward` and `@import` (for example a depencendy you use from `node_modules`). | `["**/.git/**", "**/node_modules/**"]` | +| `somesass.workspace.logLevel` | Control how much gets logged to the Output window. Possible values are `"silent"`, `"fatal"`, `"error"`, `"warn"`, `"info"`, `"debug"` and `"trace"`. | `"info"` | +| `some-sass.trace.server` | Log the messages sent between VS Code and the Some Sass language server. Possible values are `"off"`, `"messages"` and `"verbose"` | `"off"` | + ### SCSS For brevity the ID column omits the `somesass.scss` prefix. For example, to use the setting `codeAction.enabled` use the ID `somesass.scss.codeAction.enabled`. @@ -171,11 +180,3 @@ For brevity the ID column omits the `somesass.css` prefix. For example, to use t | `signatureHelp.enabled` | Enable or disable signature help. | `false` | | `workspaceSymbol.enabled` | Enable or disable workspace symbol. | `false` | | `customData` | A list of relative file paths pointing to JSON files following the [custom data format](https://github.com/microsoft/vscode-css-languageservice/blob/master/docs/customData.md). Some Sass loads custom data on startup to enhance its CSS support for CSS custom properties (variables), at-rules, pseudo-classes, and pseudo-elements you specify in the JSON files. The file paths are relative to workspace and only workspace folder settings are considered. | `[]` | - -### Workspace - -| Id | Description | Default | -| ------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------- | -| `somesass.workspace.loadPaths` | A list of paths relative to the workspace root where the language server should look for stylesheets loaded by `@use` and `@import`. `node_modules` is always included. Note that you will have to [configure your Sass compiler separately](https://sass-lang.com/documentation/cli/dart-sass/#load-path). | `[]` | -| `somesass.workspace.exclude` | List of glob patterns for directories that are excluded in the initial scan for Sass files. Files in the exclude list will still be processed if referenced by `@use`, `@forward` and `@import` (for example a depencendy you use from `node_modules`). | `["**/.git/**", "**/node_modules/**"]` | -| `somesass.workspace.logLevel` | Control how much gets logged to the Output window. | `"info"` | diff --git a/packages/language-server/src/configuration.ts b/packages/language-server/src/configuration.ts index 72f894c4..4dc2b281 100644 --- a/packages/language-server/src/configuration.ts +++ b/packages/language-server/src/configuration.ts @@ -1,13 +1,13 @@ import { defaultConfiguration, - type LanguageServiceConfiguration, + type LanguageServerConfiguration, } from "@somesass/language-services"; import { Logger } from "./logger"; export function toNewConfiguration( v1: Partial, log: Logger, -): LanguageServiceConfiguration { +): LanguageServerConfiguration { const newSettings = Object.assign({}, defaultConfiguration, v1); if (v1.loadPaths) { log.info("somesass.loadPaths is now somesass.workspace.loadPaths"); @@ -73,7 +73,7 @@ export function toNewConfiguration( } export function isOldConfiguration( - maybeV1: Partial, + maybeV1: Partial, ) { const asV1 = maybeV1 as Partial; if (typeof asV1.loadPaths !== "undefined") return true; diff --git a/packages/language-server/src/embedded.ts b/packages/language-server/src/embedded.ts index bd0bfc88..a11d35ec 100644 --- a/packages/language-server/src/embedded.ts +++ b/packages/language-server/src/embedded.ts @@ -7,7 +7,11 @@ type Region = { }; export function isFileWhereScssCanBeEmbedded(path: string) { - if (path.endsWith(".scss") || path.endsWith(".sass")) { + if ( + path.endsWith(".scss") || + path.endsWith(".sass") || + path.endsWith(".css") + ) { return false; } return true; diff --git a/packages/language-server/src/server.ts b/packages/language-server/src/server.ts index 8cb76139..b904ba73 100644 --- a/packages/language-server/src/server.ts +++ b/packages/language-server/src/server.ts @@ -2,7 +2,9 @@ import { defaultConfiguration, getLanguageService, LanguageService, - LanguageServiceConfiguration, + LanguageServerConfiguration, + LanguageConfiguration, + EditorConfiguration, } from "@somesass/language-services"; import { ClientCapabilities, @@ -31,17 +33,13 @@ import { import { getSassRegionsDocument } from "./embedded"; import WorkspaceScanner from "./workspace-scanner"; import { createLogger, type Logger } from "./logger"; -import { - EditorConfiguration, - LanguageConfiguration, -} from "@somesass/language-services/dist/language-services-types"; import merge from "lodash.merge"; export class SomeSassServer { private readonly connection: Connection; private readonly runtime: RuntimeEnvironment; private readonly log: Logger; - private configuration: LanguageServiceConfiguration = defaultConfiguration; + private configuration: LanguageServerConfiguration = defaultConfiguration; constructor(connection: Connection, runtime: RuntimeEnvironment) { this.connection = connection; @@ -72,7 +70,6 @@ export class SomeSassServer { logger: this.log, }); - // TODO: migrate to workspace folders workspaceRoot = URI.parse(params.rootUri!); this.log.info(`Workspace root ${workspaceRoot}`); @@ -131,9 +128,9 @@ export class SomeSassServer { }); const applyConfiguration = ( - somesass: Partial, + somesass: Partial, editor: Partial, - ): LanguageServiceConfiguration => { + ): LanguageServerConfiguration => { if (isOldConfiguration(somesass)) { this.log.warn( `Your somesass configuration uses old setting names. They will continue to work for some time, but it's recommended you change your settings to the new names. For all the available settings see https://wkillerud.github.io/some-sass/user-guide/settings.html`, @@ -149,7 +146,7 @@ export class SomeSassServer { ); } - const settings: LanguageServiceConfiguration = merge( + const settings: LanguageServerConfiguration = merge( defaultConfiguration, somesass, { @@ -158,17 +155,15 @@ export class SomeSassServer { }, }, ); - settings.workspace.workspaceRoot = workspaceRoot; - if (settings.workspace.logLevel) { - this.log.setLogLevel(settings.workspace.logLevel); - } + settings.workspace.workspaceRoot = workspaceRoot; this.configuration = settings; if (ls) { ls.configure(settings); } + this.log.setLogLevel(settings.workspace.logLevel); this.log.debug("Applied user configuration"); this.log.trace(JSON.stringify(this.configuration, null, 2)); @@ -199,7 +194,7 @@ export class SomeSassServer { } let [somesass, editor] = configs as [ - Partial, + Partial, Partial, ]; @@ -276,7 +271,9 @@ export class SomeSassServer { } await doDiagnostics(params); } catch (e) { - this.log.debug((e as Error).message); + const error = e as Error; + this.log.debug(String(error)); + if (error.stack) this.log.debug(error.stack); } }); @@ -286,7 +283,9 @@ export class SomeSassServer { ls.onDocumentChanged(params.document); await doDiagnostics(params); } catch (e) { - this.log.debug((e as Error).message); + const error = e as Error; + this.log.debug(String(error)); + if (error.stack) this.log.debug(error.stack); } }); @@ -314,7 +313,9 @@ export class SomeSassServer { await workspaceScanner.scan(newFiles); } catch (e) { - this.log.debug((e as Error).message); + const error = e as Error; + this.log.debug(String(error)); + if (error.stack) this.log.debug(error.stack); } }); @@ -338,7 +339,9 @@ export class SomeSassServer { return null; } } catch (e) { - this.log.debug((e as Error).message); + const error = e as Error; + this.log.debug(String(error)); + if (error.stack) this.log.debug(error.stack); return null; } }); @@ -360,7 +363,9 @@ export class SomeSassServer { return null; } } catch (e) { - this.log.debug((e as Error).message); + const error = e as Error; + this.log.debug(String(error)); + if (error.stack) this.log.debug(error.stack); return null; } }); @@ -382,7 +387,9 @@ export class SomeSassServer { return null; } } catch (e) { - this.log.debug((e as Error).message); + const error = e as Error; + this.log.debug(String(error)); + if (error.stack) this.log.debug(error.stack); return null; } }); @@ -404,7 +411,9 @@ export class SomeSassServer { return null; } } catch (e) { - this.log.debug((e as Error).message); + const error = e as Error; + this.log.debug(String(error)); + if (error.stack) this.log.debug(error.stack); return null; } }); @@ -429,7 +438,9 @@ export class SomeSassServer { return null; } } catch (e) { - this.log.debug((e as Error).message); + const error = e as Error; + this.log.debug(String(error)); + if (error.stack) this.log.debug(error.stack); return null; } }); @@ -453,7 +464,9 @@ export class SomeSassServer { return null; } } catch (e) { - this.log.debug((e as Error).message); + const error = e as Error; + this.log.debug(String(error)); + if (error.stack) this.log.debug(error.stack); return null; } }); @@ -479,7 +492,9 @@ export class SomeSassServer { return null; } } catch (e) { - this.log.debug((e as Error).message); + const error = e as Error; + this.log.debug(String(error)); + if (error.stack) this.log.debug(error.stack); return null; } }); @@ -490,7 +505,9 @@ export class SomeSassServer { const result = ls.findWorkspaceSymbols(params.query); return result; } catch (e) { - this.log.debug((e as Error).message); + const error = e as Error; + this.log.debug(String(error)); + if (error.stack) this.log.debug(error.stack); return null; } }); @@ -543,7 +560,9 @@ export class SomeSassServer { return result; } catch (e) { - this.log.debug((e as Error).message); + const error = e as Error; + this.log.debug(String(error)); + if (error.stack) this.log.debug(error.stack); return null; } }); @@ -568,7 +587,9 @@ export class SomeSassServer { return null; } } catch (e) { - this.log.debug((e as Error).message); + const error = e as Error; + this.log.debug(String(error)); + if (error.stack) this.log.debug(error.stack); return null; } }); @@ -594,7 +615,9 @@ export class SomeSassServer { return null; } } catch (e) { - this.log.debug((e as Error).message); + const error = e as Error; + this.log.debug(String(error)); + if (error.stack) this.log.debug(error.stack); return null; } }); @@ -618,7 +641,9 @@ export class SomeSassServer { return null; } } catch (e) { - this.log.debug((e as Error).message); + const error = e as Error; + this.log.debug(String(error)); + if (error.stack) this.log.debug(error.stack); return null; } }); @@ -643,7 +668,9 @@ export class SomeSassServer { return null; } } catch (e) { - this.log.debug((e as Error).message); + const error = e as Error; + this.log.debug(String(error)); + if (error.stack) this.log.debug(error.stack); return null; } }); @@ -664,7 +691,9 @@ export class SomeSassServer { return null; } } catch (e) { - this.log.debug((e as Error).message); + const error = e as Error; + this.log.debug(String(error)); + if (error.stack) this.log.debug(error.stack); return null; } }); @@ -688,7 +717,9 @@ export class SomeSassServer { return null; } } catch (e) { - this.log.debug((e as Error).message); + const error = e as Error; + this.log.debug(String(error)); + if (error.stack) this.log.debug(error.stack); return null; } }); diff --git a/packages/language-server/src/workspace-scanner.ts b/packages/language-server/src/workspace-scanner.ts index a6b1c5d1..9125c274 100644 --- a/packages/language-server/src/workspace-scanner.ts +++ b/packages/language-server/src/workspace-scanner.ts @@ -9,27 +9,17 @@ import { getSassRegionsDocument } from "./embedded"; export default class WorkspaceScanner { #ls: LanguageService; #fs: FileSystemProvider; - #settings: { scannerDepth: number; scanImportedFiles: boolean }; - constructor( - ls: LanguageService, - fs: FileSystemProvider, - settings = { scannerDepth: 256, scanImportedFiles: true }, - ) { + constructor(ls: LanguageService, fs: FileSystemProvider) { this.#ls = ls; this.#fs = fs; - - this.#settings = settings; } public async scan(files: URI[]): Promise { // Populate the cache for the new language services return Promise.all( files.map((uri) => { - if ( - this.#settings.scanImportedFiles && - (uri.path.includes("/_") || uri.path.includes("\\_")) - ) { + if (uri.path.includes("/_") || uri.path.includes("\\_")) { // If we scan imported files (which we do by default), don't include partials in the initial scan. // This way we can be reasonably sure that we scan whatever index files there are _before_ we scan // partials which may or may not have been forwarded with a prefix. @@ -41,8 +31,8 @@ export default class WorkspaceScanner { } private async parse(file: URI, depth = 0) { - const maxDepth = this.#settings.scannerDepth ?? 30; - if (depth > maxDepth || !this.#settings.scanImportedFiles) { + const maxDepth = 256; + if (depth > maxDepth) { return; } @@ -65,7 +55,11 @@ export default class WorkspaceScanner { document = getSassRegionsDocument( TextDocument.create( uriString, - uriString.endsWith(".sass") ? "sass" : "scss", + uriString.endsWith(".sass") + ? "sass" + : uriString.endsWith(".css") + ? "css" + : "scss", 1, content, ), @@ -80,7 +74,7 @@ export default class WorkspaceScanner { for (const link of links) { if ( !link.target || - link.target.endsWith(".css") || + link.target.endsWith(".css") || // we'll get to it via our glob link.target.includes("#{") || link.target.startsWith("sass:") ) { diff --git a/packages/language-services/src/features/do-complete.ts b/packages/language-services/src/features/do-complete.ts index 5ea68f66..20614532 100644 --- a/packages/language-services/src/features/do-complete.ts +++ b/packages/language-services/src/features/do-complete.ts @@ -975,7 +975,6 @@ export class DoComplete extends LanguageFeature { config.completion.mixinStyle !== "nobracket" && document.languageId === "scss" ) { - // TODO: test if this works correctly with multiline, I think so from the spec text const insertSnippet = `${insert} {\n\t$0\n}`; items.push({ ...base, diff --git a/packages/language-services/src/features/find-symbols.ts b/packages/language-services/src/features/find-symbols.ts index 6521fba9..7e6bdebc 100644 --- a/packages/language-services/src/features/find-symbols.ts +++ b/packages/language-services/src/features/find-symbols.ts @@ -72,7 +72,6 @@ export class FindSymbols extends LanguageFeature { // This is the exception to the rule that this enabled check // should happen at the server edge. It's only at this point // we know if the document should be included or not. - // Maybe a sign that this method should be lifted out of language-services. const config = this.languageConfiguration(document); if (config.workspaceSymbol.enabled) { const symbols = this.findDocumentSymbols(document); diff --git a/packages/language-services/src/language-services.ts b/packages/language-services/src/language-services.ts index 24089120..6166d802 100644 --- a/packages/language-services/src/language-services.ts +++ b/packages/language-services/src/language-services.ts @@ -21,6 +21,8 @@ import { LanguageModelCache as LanguageServerCache } from "./language-model-cach import { CodeActionContext, LanguageService, + LanguageConfiguration, + EditorConfiguration, LanguageServerConfiguration, LanguageServiceOptions, Position, @@ -38,7 +40,9 @@ import { mapFsProviders } from "./utils/fs-provider"; export { defaultConfiguration, LanguageService, - LanguageServerConfiguration as LanguageServiceConfiguration, + LanguageServerConfiguration, + LanguageConfiguration, + EditorConfiguration, FileStat, FileSystemProvider, FileType, diff --git a/vscode-extension/package.json b/vscode-extension/package.json index 4bc23b8e..c2d24bac 100644 --- a/vscode-extension/package.json +++ b/vscode-extension/package.json @@ -1,7 +1,7 @@ { "name": "some-sass", "displayName": "Some Sass", - "description": "Full support for @use and @forward, including aliases, prefixes and hiding. Rich documentation through SassDoc. Workspace-wide code navigation and refactoring.", + "description": "Improved support for SCSS, Sass indented and SassDoc. Workspace awareness and full support for Sass modules.", "version": "3.9.3", "private": true, "publisher": "SomewhatStationery", @@ -1300,14 +1300,14 @@ "order": 81, "type": "boolean", "scope": "resource", - "default": false, + "default": true, "description": "Show property and value documentation in CSS hovers." }, "somesass.css.hover.references": { "order": 82, "type": "boolean", "scope": "resource", - "default": false, + "default": true, "description": "Show references to MDN in CSS hovers." }, "somesass.css.links.enabled": { diff --git a/vscode-extension/src/client.ts b/vscode-extension/src/client.ts index 0b958cb4..2135c066 100644 --- a/vscode-extension/src/client.ts +++ b/vscode-extension/src/client.ts @@ -36,9 +36,8 @@ export function log(message: string): void { export function createLanguageClientOptions( currentWorkspace?: WorkspaceFolder, ): LanguageClientOptions { - // TODO: also include CSS if opted in - let documentSelector: DocumentSelector = [ + { scheme: "untitled", language: "css" }, { scheme: "untitled", language: "scss" }, { scheme: "untitled", language: "sass" }, { scheme: "untitled", language: "vue" }, @@ -55,16 +54,19 @@ export function createLanguageClientOptions( const webPattern = `${currentWorkspace.uri.path}**`; documentSelector = [ + { scheme: "file", language: "css", pattern }, { scheme: "file", language: "scss", pattern }, { scheme: "file", language: "sass", pattern }, { scheme: "file", language: "vue", pattern }, { scheme: "file", language: "svelte", pattern }, { scheme: "file", language: "astro", pattern }, + { scheme: "vscode-vfs", language: "css", pattern }, { scheme: "vscode-vfs", language: "scss", pattern }, { scheme: "vscode-vfs", language: "sass", pattern }, { scheme: "vscode-vfs", language: "vue", pattern }, { scheme: "vscode-vfs", language: "svelte", pattern }, { scheme: "vscode-vfs", language: "astro", pattern }, + { scheme: "vscode-test-web", language: "css", pattern: webPattern }, { scheme: "vscode-test-web", language: "scss", pattern: webPattern }, { scheme: "vscode-test-web", language: "sass", pattern: webPattern }, { scheme: "vscode-test-web", language: "vue", pattern: webPattern }, @@ -81,7 +83,7 @@ export function createLanguageClientOptions( ? workspace.createFileSystemWatcher({ baseUri: currentWorkspace.uri, base: currentWorkspace.uri.fsPath, - pattern: "**/*.{scss,sass,vue,svelte,astro}", + pattern: "**/*.{css,scss,sass,vue,svelte,astro}", }) : undefined, }, diff --git a/vscode-extension/src/node-client.ts b/vscode-extension/src/node-client.ts index 7974d940..7e007905 100644 --- a/vscode-extension/src/node-client.ts +++ b/vscode-extension/src/node-client.ts @@ -74,6 +74,7 @@ export async function activate(context: ExtensionContext): Promise { document.uri.scheme !== "file" && document.uri.scheme !== "untitled" && document.uri.scheme !== "vscode-vfs" && + document.languageId !== "css" && document.languageId !== "scss" && document.languageId !== "sass" && document.languageId !== "vue" && From 8afc2ecb96a9da336b722406c1150907bf96154c Mon Sep 17 00:00:00 2001 From: William Killerud Date: Sat, 28 Sep 2024 10:37:41 +0200 Subject: [PATCH 23/23] docs: update readmes [skip ci] --- .../src/language-server/configure-a-client.md | 34 +++++++++---------- docs/src/user-guide/settings.md | 10 +++--- packages/language-server/README.md | 16 ++------- vscode-extension/README.md | 23 ++++++------- 4 files changed, 35 insertions(+), 48 deletions(-) diff --git a/docs/src/language-server/configure-a-client.md b/docs/src/language-server/configure-a-client.md index eae2996f..a4814785 100644 --- a/docs/src/language-server/configure-a-client.md +++ b/docs/src/language-server/configure-a-client.md @@ -2,17 +2,31 @@ An editor needs a language client for the [Language Server Protocol (LSP)][lsp] to use a language server. -To configure a client for an editor that doesn't have one yet, check the documentation for your editor to see if it supports LSP natively. If not, there may be an extension, add-on or plugin that adds support for LSP. +Your editor [may have a client already](./existing-clients.md). If not, check the documentation for your editor to see if it supports LSP natively. There may be an extension, add-on or plugin that adds support for LSP if it's not built in. + +## Language clients + +This list of [language client implementations][languageclients] may be a helpful starting point. You can also look at how [existing clients](./existing-clients.md) are set up. + +### Log messages sent by VS Code to the server + +If you're having trouble it might be helpful to compare your client with VS Code's. To log the messages sent between VS Code and the language server, add this to [your `settings.json`](https://code.visualstudio.com/docs/getstarted/settings#_settingsjson) (thank you to [Stefan Schlichthärle](https://www.sscit.de/2021/04/15/trace-lsp-in-vscode.html)). + +```json +"some-sass.trace.server": "verbose" +``` + +Now you can open a Sass file, then open the Output panel (View menu -> Output) to see the messages. ## Settings -The language server requests settings via the [`workspace/configuration` message](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#workspace_configuration), on the `somesass` key. All fields are optional. +The language server requests [settings](https://wkillerud.github.io/some-sass/user-guide/settings.html) via the [`workspace/configuration` message](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#workspace_configuration), on the `somesass` key. All fields are optional. You can also configure the language server by sending the [`workspace/didChangeConfiguration` message](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#workspace_didChangeConfiguration). While settings keys are documented with dot-notation, the shape of the settings is a nested object. Your editor may be able to translate from dot-notation to a properly formated object, but not every editor allows this. -For example, while we may document `"somesass.scss.workspace.loadPaths": []` (and write it this way in `settings.json` in VS Code), the actual shape of the settings object sent to the server looks like this. +For example, while we may document `"somesass.workspace.loadPaths": []` (and write it this way in `settings.json` in VS Code), the actual shape of the settings object sent to the server looks like this. ```json { @@ -26,19 +40,5 @@ For example, while we may document `"somesass.scss.workspace.loadPaths": []` (an } ``` -## Existing clients - -This list of [language client implementations][languageclients] may be a helpful starting point. You may also want to look at [existing clients](./existing-clients.md). - -### Log messages sent by VS Code to the server - -If you're having trouble it might be helpful to compare your client with VS Code's. To log the messages sent between VS Code and the language server, add this to [your `settings.json`](https://code.visualstudio.com/docs/getstarted/settings#_settingsjson) (thank you to [Stefan Schlichthärle](https://www.sscit.de/2021/04/15/trace-lsp-in-vscode.html)). - -```json -"some-sass.trace.server": "verbose" -``` - -Now you can open a Sass file, then open the Output panel (View menu -> Output) to see the messages. - [lsp]: https://microsoft.github.io/language-server-protocol/ [languageclients]: https://microsoft.github.io/language-server-protocol/implementors/tools/ diff --git a/docs/src/user-guide/settings.md b/docs/src/user-guide/settings.md index 8030e574..fe6ae526 100644 --- a/docs/src/user-guide/settings.md +++ b/docs/src/user-guide/settings.md @@ -19,11 +19,12 @@ These are the recommended settings if you're just getting started. ### Going all in on Some Sass -If you don't need language features for [Less](https://lesscss.org/) and don't rely on the built-in formatter, we recommend turning off the built-in CSS/SCSS/Less language extension in Visual Studio Code. For formating we recommend [Prettier](https://prettier.io/). +If you don't need language features for [Less](https://lesscss.org/) and don't rely on the built-in formatter, we recommend that you: -Some Sass has all the features of the built-in language extension, though they are turned off by default. +1. turn off the built-in CSS/SCSS/Less language extension in Visual Studio Code +2. configure Some Sass to turn on all features for CSS, SCSS and Sass indented -Once you turn off the built-in language features you can configure Some Sass to handle both CSS and Sass for you. This way you get the best experience without Some Sass and VS Code getting in each others way. +This way you get the best experience without Some Sass and VS Code getting in each others way. #### How to turn off the built-in language feature @@ -37,7 +38,8 @@ Once you turn off the built-in language features you can configure Some Sass to Now that you disabled the built-in language features you need to turn on those language features in Some Sass. -Open your user settings JSON and paste this configuration. Restart VS Code to make sure the changes apply. +1. Open your [user settings JSON](https://code.visualstudio.com/docs/getstarted/settings#_settings-json-file) and paste the configuration shown below. +2. Restart VS Code to make sure the changes apply. ```json { diff --git a/packages/language-server/README.md b/packages/language-server/README.md index dac4359f..447d310e 100644 --- a/packages/language-server/README.md +++ b/packages/language-server/README.md @@ -9,29 +9,17 @@ The language server provides: - Rich documentation through [SassDoc](http://sassdoc.com). - Language features for `%placeholder-selectors`, both when using them and writing them. - Suggestions and hover info for built-in Sass modules, when used with `@use`. -- Support for [both Sass syntaxes](https://sass-lang.com/documentation/syntax/). - -This language server is designed to run alongside the [VS Code CSS language server](https://github.com/hrsh7th/vscode-langservers-extracted). See [the settings documentation](https://wkillerud.github.io/some-sass/user-guide/settings.html#suggest-variables-mixins-and-functions-from-the-open-document) for information on tweaking the user experience. +- Support for [both Sass syntaxes](https://sass-lang.com/documentation/syntax/) as well as CSS. ## Usage -See [Editors with clients](https://github.com/wkillerud/some-sass/blob/main/README.md#editors-with-clients). If your editor is not listed, refer to your editor's documentation for integrating with a language server using the Language Server Protocol (LSP). - You can install the language server with `npm`: ```sh npm install --global some-sass-language-server ``` -Then start the language server like so: - -```sh -some-sass-language-server --stdio -``` - -### Workspace configuration - -See [how to configure a client](https://wkillerud.github.io/some-sass/language-server/configure-a-client.html) and the [documentation for the available settings](https://wkillerud.github.io/some-sass/user-guide/settings.html). +Then see [how to configure a client](https://wkillerud.github.io/some-sass/language-server/configure-a-client.html). ## Capabilities diff --git a/vscode-extension/README.md b/vscode-extension/README.md index 8aa19a35..7a8ed7c1 100644 --- a/vscode-extension/README.md +++ b/vscode-extension/README.md @@ -26,32 +26,29 @@ See the [user guide](https://wkillerud.github.io/some-sass/) to get the most out ## Recommended settings -These are the recommended settings: +These are the recommended settings if you're just getting started. ```jsonc { // Recommended if you don't rely on @import - "somesass.suggestFromUseOnly": true, + "somesass.scss.completion.suggestFromUseOnly": true, + "somesass.sass.completion.suggestFromUseOnly": true, - // Optional, if you get suggestions from the current document after namespace.$ (you don't need the $ for narrowing down suggestions) + // Optional, if you get suggestions from the current document after namespace.$ (you don't need to type the $ for narrowing down suggestions) "editor.wordBasedSuggestions": false, } ``` -Note that if you have SCSS IntelliSense (`mrmlnc.vscode-scss`) installed you should disable or uninstall it. Otherwise the two extensions will both provide hover information and code suggestions. +### Going all in on Some Sass -### About word-based suggestions +If you don't need language features for [Less](https://lesscss.org/) and don't rely on the built-in formatter, we recommend that you: -When you get completion suggestions and type `namespace.$`, Visual Studio Code treats `$` as a fresh start for suggestions. It will start matching any variable in the current document. There are two ways to get around this: +1. turn off the built-in CSS/SCSS/Less language extension in Visual Studio Code +2. configure Some Sass to turn on all features for CSS, SCSS and Sass indented -1. Turn off word-based suggestions by setting `"editor.wordBasedSuggestions": false`. -2. Don't type the `$` when you write the variable name, let completions fill it out for you. +See the [Settings reference](https://wkillerud.github.io/some-sass/user-guide/settings.html#going-all-in-on-some-sass) for instructions on how to do this. -With the second approach you can keep word-based suggestions turned on. - -### Settings reference - -See the [settings reference](https://wkillerud.github.io/some-sass/user-guide/settings.html#settings-reference) for more information about the different settings of Some Sass. +If you have SCSS IntelliSense (`mrmlnc.vscode-scss`) installed you should disable or uninstall it. ## Changelog