├── .editorconfig ├── .gitattributes ├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── 01-bug.yml │ └── config.yml ├── pull_request_template.md └── workflows │ ├── publish_docs.yml │ ├── pull_request.yml │ ├── release-vscode.yml │ └── release.yml ├── .gitignore ├── .husky ├── commit-msg └── pre-commit ├── .npmrc ├── .nvmrc ├── .prettierignore ├── .prettierrc ├── .scripts └── release.mjs ├── .vscode ├── extensions.json ├── launch.json └── settings.json ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── README.md ├── commitlint.config.js ├── docs ├── book.toml └── src │ ├── README.md │ ├── SUMMARY.md │ ├── contributing │ ├── architecture.md │ ├── automated-tests.md │ ├── building.md │ ├── debugging-in-browser.md │ ├── debugging-performance.md │ ├── debugging-unit-tests.md │ ├── debugging.md │ ├── development-environment.md │ ├── extensions-for-vs-code.md │ ├── language-server-protocol.md │ ├── new-contributors.md │ ├── releases.md │ ├── reporting-bugs.md │ ├── test-coverage.md │ ├── testing-other-editors.md │ └── writing-documentation.md │ ├── images │ ├── README.md │ ├── architecture │ │ ├── browser.png │ │ ├── node.png │ │ └── parser-cache.png │ ├── debugging │ │ ├── attach-to-server.png │ │ ├── chromium-debugger.png │ │ ├── debug-individual-test.gif │ │ ├── debug-log-output.png │ │ ├── debugging-e2e-test.png │ │ ├── debugging-profiling-controls.png │ │ ├── debugging-unit-test.png │ │ ├── debugging.png │ │ ├── launch-browser-extension.png │ │ └── launch-extension.png │ ├── highlight-reel.gif │ ├── tests │ │ └── coverage-report.png │ └── usage │ │ ├── color-decorators.png │ │ ├── diagnostics-deprecated.png │ │ ├── diagnostics-indented.png │ │ ├── extract.gif │ │ ├── find-references.gif │ │ ├── go-to-definition.gif │ │ ├── import-completions.png │ │ ├── pkg-imports.png │ │ ├── placeholder-declare.png │ │ ├── placeholder-extend.png │ │ ├── rename-symbol.gif │ │ ├── sass-built-in-hover.png │ │ ├── sassdoc-annotation-hover.png │ │ ├── sassdoc-block.gif │ │ ├── sassdoc-hover.png │ │ ├── settings-built-in.png │ │ ├── signature-helper.gif │ │ ├── string-literal-union-type.png │ │ └── suggestions-mixins.gif │ ├── language-server │ ├── configure-a-client.md │ ├── existing-clients.md │ ├── getting-started.md │ ├── helix.md │ ├── neovim.md │ ├── settings.md │ └── sublime-text.md │ └── user-guide │ ├── color.md │ ├── completions.md │ ├── diagnostics.md │ ├── hover.md │ ├── navigation.md │ ├── refactoring.md │ └── settings.md ├── eslint.config.mjs ├── nx.json ├── package-lock.json ├── package.json ├── packages ├── language-server │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── bin │ │ └── some-sass-language-server │ ├── package.json │ ├── rspack.browser.config.js │ ├── rspack.node.config.js │ ├── src │ │ ├── __tests__ │ │ │ ├── embedded.test.ts │ │ │ └── logger.test.ts │ │ ├── browser-main.ts │ │ ├── browser-server.ts │ │ ├── configuration.ts │ │ ├── constants.ts │ │ ├── embedded.ts │ │ ├── file-system-provider.ts │ │ ├── file-system.ts │ │ ├── logger.ts │ │ ├── node-file-system.ts │ │ ├── node-main.ts │ │ ├── node-server.ts │ │ ├── runtime.ts │ │ ├── server.ts │ │ └── workspace-scanner.ts │ ├── tsconfig.json │ └── vitest.config.mts ├── language-services │ ├── CHANGELOG.md │ ├── README.md │ ├── package.json │ ├── src │ │ ├── configuration.ts │ │ ├── facts │ │ │ ├── sass.ts │ │ │ └── sassdoc.ts │ │ ├── features │ │ │ ├── __tests__ │ │ │ │ ├── code-actions-extract.test.ts │ │ │ │ ├── do-complete-at-rules.test.ts │ │ │ │ ├── do-complete-embedded.test.ts │ │ │ │ ├── do-complete-import.test.ts │ │ │ │ ├── do-complete-interpolation.test.ts │ │ │ │ ├── do-complete-modules.test.ts │ │ │ │ ├── do-complete-node-modules.test.ts │ │ │ │ ├── do-complete-placeholders.test.ts │ │ │ │ ├── do-complete-sassdoc.test.ts │ │ │ │ ├── do-complete.test.ts │ │ │ │ ├── do-diagnostics-deprecation.test.ts │ │ │ │ ├── do-diagnostics.test.ts │ │ │ │ ├── do-hover.test.ts │ │ │ │ ├── do-rename-perform.test.ts │ │ │ │ ├── do-rename-prepare.test.ts │ │ │ │ ├── do-signature-help.test.ts │ │ │ │ ├── find-colors.test.ts │ │ │ │ ├── find-definition.test.ts │ │ │ │ ├── find-document-links.test.ts │ │ │ │ ├── find-references.test.ts │ │ │ │ ├── find-symbols-document-indented.test.ts │ │ │ │ ├── find-symbols-document.test.ts │ │ │ │ └── find-symbols-workspace.test.ts │ │ │ ├── code-actions.ts │ │ │ ├── do-complete.ts │ │ │ ├── do-diagnostics.ts │ │ │ ├── do-hover.ts │ │ │ ├── do-rename.ts │ │ │ ├── do-signature-help.ts │ │ │ ├── find-colors.ts │ │ │ ├── find-definition.ts │ │ │ ├── find-document-highlights.ts │ │ │ ├── find-document-links.ts │ │ │ ├── find-references.ts │ │ │ ├── find-symbols.ts │ │ │ ├── folding-ranges.ts │ │ │ └── selection-ranges.ts │ │ ├── language-feature.ts │ │ ├── language-model-cache.ts │ │ ├── language-services-types.ts │ │ ├── language-services.ts │ │ └── utils │ │ │ ├── fs-provider.ts │ │ │ ├── sass.ts │ │ │ ├── sassdoc.ts │ │ │ └── test-helpers.ts │ ├── tsconfig.json │ └── vitest.config.mts └── vscode-css-languageservice │ ├── .eslintrc.json │ ├── .gitignore │ ├── .prettierrc │ ├── CHANGELOG.md │ ├── LICENSE.md │ ├── README.md │ ├── build │ ├── generateData.js │ └── remove-sourcemap-refs.js │ ├── docs │ ├── customData.md │ └── customData.schema.json │ ├── package.json │ ├── src │ ├── cssLanguageService.ts │ ├── cssLanguageTypes.ts │ ├── data │ │ └── webCustomData.ts │ ├── languageFacts │ │ ├── builtinData.ts │ │ ├── colors.ts │ │ ├── dataManager.ts │ │ ├── dataProvider.ts │ │ ├── entry.ts │ │ └── facts.ts │ ├── parser │ │ ├── cssErrors.ts │ │ ├── cssNodes.ts │ │ ├── cssParser.ts │ │ ├── cssScanner.ts │ │ ├── cssSymbolScope.ts │ │ ├── sassErrors.ts │ │ ├── sassParser.ts │ │ └── sassScanner.ts │ ├── services │ │ ├── cssCodeActions.ts │ │ ├── cssCompletion.ts │ │ ├── cssFolding.ts │ │ ├── cssHover.ts │ │ ├── cssNavigation.ts │ │ ├── cssSelectionRange.ts │ │ ├── cssValidation.ts │ │ ├── lint.ts │ │ ├── lintRules.ts │ │ ├── lintUtil.ts │ │ ├── pathCompletion.ts │ │ ├── sassCompletion.ts │ │ ├── sassNavigation.ts │ │ └── selectorPrinting.ts │ ├── test │ │ ├── css │ │ │ ├── codeActions.test.ts │ │ │ ├── completion.test.ts │ │ │ ├── customData.test.ts │ │ │ ├── folding.test.ts │ │ │ ├── hover.test.ts │ │ │ ├── languageFacts.test.ts │ │ │ ├── lint.test.ts │ │ │ ├── navigation.test.ts │ │ │ ├── nodes.test.ts │ │ │ ├── parser.test.ts │ │ │ ├── scanner.test.ts │ │ │ ├── selectionRange.test.ts │ │ │ └── selectorPrinting.test.ts │ │ ├── sass │ │ │ ├── example.sass │ │ │ ├── example.scss │ │ │ ├── languageFacts.test.ts │ │ │ ├── linkFixture │ │ │ │ ├── both │ │ │ │ │ ├── _bar.sass │ │ │ │ │ ├── _foo.scss │ │ │ │ │ ├── bar.sass │ │ │ │ │ ├── foo.scss │ │ │ │ │ └── nested │ │ │ │ │ │ └── bar.sass │ │ │ │ ├── indented-index │ │ │ │ │ ├── bar │ │ │ │ │ │ └── _index.sass │ │ │ │ │ └── foo │ │ │ │ │ │ └── index.sass │ │ │ │ ├── index │ │ │ │ │ ├── bar │ │ │ │ │ │ └── _index.scss │ │ │ │ │ └── foo │ │ │ │ │ │ └── index.scss │ │ │ │ ├── loadPaths │ │ │ │ │ ├── shared │ │ │ │ │ │ └── my-lib │ │ │ │ │ │ │ └── variables.scss │ │ │ │ │ └── src │ │ │ │ │ │ └── styles.scss │ │ │ │ ├── module │ │ │ │ │ ├── bar.sass │ │ │ │ │ └── foo.scss │ │ │ │ ├── noUnderscore │ │ │ │ │ ├── bar.sass │ │ │ │ │ └── foo.scss │ │ │ │ └── underscore │ │ │ │ │ ├── _bar.sass │ │ │ │ │ └── _foo.scss │ │ │ ├── lint.test.ts │ │ │ ├── parser.test.ts │ │ │ ├── parserIndented.test.ts │ │ │ ├── parserSmoketest.test.ts │ │ │ ├── sassCompletion.test.ts │ │ │ ├── sassCompletionIndented.test.ts │ │ │ ├── sassFolding.test.ts │ │ │ ├── sassHover.test.ts │ │ │ ├── sassLint.test.ts │ │ │ ├── sassNavigation.test.ts │ │ │ ├── sassSelectionRange.test.ts │ │ │ └── selectorPrinting.test.ts │ │ └── testUtil │ │ │ ├── documentContext.ts │ │ │ └── fsProvider.ts │ ├── tsconfig.esm.json │ ├── tsconfig.json │ └── utils │ │ ├── arrays.ts │ │ ├── objects.ts │ │ ├── resources.ts │ │ └── strings.ts │ ├── test │ ├── linksTestFixtures │ │ ├── .gitignore │ │ ├── a.css │ │ ├── green │ │ │ ├── c.css │ │ │ └── d.scss │ │ └── node_modules │ │ │ ├── @foo │ │ │ ├── bar │ │ │ │ ├── _baz.scss │ │ │ │ ├── _index.scss │ │ │ │ └── package.json │ │ │ ├── baz │ │ │ │ └── package.json │ │ │ └── foo │ │ │ │ └── package.json │ │ │ ├── bar-indented │ │ │ ├── package.json │ │ │ └── styles │ │ │ │ ├── button.sass │ │ │ │ ├── colors.sass │ │ │ │ └── index.sass │ │ │ ├── bar-pattern-indented │ │ │ ├── package.json │ │ │ └── styles │ │ │ │ ├── button.sass │ │ │ │ ├── colors.sass │ │ │ │ ├── index.sass │ │ │ │ └── theme │ │ │ │ ├── button.sass │ │ │ │ ├── colors.sass │ │ │ │ └── index.sass │ │ │ ├── bar-pattern │ │ │ ├── package.json │ │ │ └── styles │ │ │ │ ├── button.scss │ │ │ │ ├── colors.scss │ │ │ │ ├── index.scss │ │ │ │ └── theme │ │ │ │ ├── button.scss │ │ │ │ ├── colors.scss │ │ │ │ └── index.scss │ │ │ ├── bar │ │ │ ├── package.json │ │ │ └── styles │ │ │ │ ├── button.scss │ │ │ │ ├── colors.scss │ │ │ │ └── index.scss │ │ │ ├── foo │ │ │ └── package.json │ │ │ ├── green │ │ │ ├── _e.scss │ │ │ ├── c.css │ │ │ ├── d.scss │ │ │ └── package.json │ │ │ ├── root-indented │ │ │ ├── package.json │ │ │ └── styles │ │ │ │ └── index.sass │ │ │ ├── root-sass │ │ │ ├── package.json │ │ │ └── styles │ │ │ │ └── index.scss │ │ │ ├── root-style-indented │ │ │ ├── package.json │ │ │ └── styles │ │ │ │ └── index.sass │ │ │ ├── root-style │ │ │ ├── package.json │ │ │ └── styles │ │ │ │ └── index.scss │ │ │ ├── sass-true │ │ │ ├── _index.scss │ │ │ └── package.json │ │ │ └── sass │ │ │ ├── package.json │ │ │ └── styles │ │ │ ├── button.sass │ │ │ ├── colors.sass │ │ │ └── index.sass │ └── pathCompletionFixtures │ │ ├── .foo.js │ │ ├── about │ │ ├── about.css │ │ └── about.html │ │ ├── index.html │ │ ├── sass │ │ ├── _foo.sass │ │ └── main.sass │ │ ├── scss │ │ ├── _foo.scss │ │ └── main.scss │ │ └── src │ │ ├── data │ │ └── foo.asar │ │ ├── feature.js │ │ └── test.js │ └── vitest.config.mts ├── renovate.json ├── tsconfig.base.json └── vscode-extension ├── .vscodeignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── icon.png ├── languages ├── README.md ├── sass.configuration.json └── sass.tmLanguage.json ├── package.json ├── project.json ├── rspack.browser.config.js ├── rspack.node.config.js ├── rspack.test-web.config.js ├── schemas └── package.schema.json ├── src ├── browser-client.ts ├── client.ts ├── constants.ts ├── node-client.ts ├── node │ ├── file-system.ts │ └── node-file-system.ts ├── runtime.ts └── utils │ └── string.ts ├── test ├── README.md ├── e2e │ ├── defaults-sass │ │ ├── completions.test.js │ │ ├── find-definition.test.js │ │ ├── hover.test.js │ │ ├── index.js │ │ ├── navigation.test.js │ │ ├── syntax-mixing.test.js │ │ ├── util.js │ │ └── workspace │ │ │ ├── .editorconfig │ │ │ ├── completions.sass │ │ │ ├── core │ │ │ ├── _theme.sass │ │ │ └── _tokens.sass │ │ │ ├── navigation │ │ │ ├── _circular.sass │ │ │ └── main.sass │ │ │ ├── styles.sass │ │ │ └── syntax-mixing │ │ │ ├── _indented.sass │ │ │ ├── _scss.scss │ │ │ ├── styles.sass │ │ │ └── styles.scss │ ├── defaults-scss │ │ ├── completion-helper.js │ │ ├── completion-placeholders.test.js │ │ ├── completion-sassdoc.test.js │ │ ├── completion.test.js │ │ ├── definition-helper.js │ │ ├── definitions.test.js │ │ ├── hover-helper.js │ │ ├── hover.test.js │ │ ├── index.js │ │ ├── navigation.test.js │ │ ├── signature-helper.js │ │ ├── signature.test.js │ │ ├── util.js │ │ └── workspace │ │ │ ├── .editorconfig │ │ │ ├── _functions.scss │ │ │ ├── _mixins.scss │ │ │ ├── _placeholders.scss │ │ │ ├── _variables.scss │ │ │ ├── completion │ │ │ ├── AppButton.astro │ │ │ ├── AppButton.svelte │ │ │ ├── AppButton.vue │ │ │ ├── _partial.scss │ │ │ ├── circular.scss │ │ │ ├── main.scss │ │ │ ├── modules.scss │ │ │ ├── node_modules │ │ │ │ ├── foo │ │ │ │ │ ├── bar.scss │ │ │ │ │ └── package.json │ │ │ │ └── placeholders │ │ │ │ │ ├── package.json │ │ │ │ │ └── placeholders-module.scss │ │ │ ├── placeholders.scss │ │ │ ├── reverse-placeholders │ │ │ │ ├── _theme.scss │ │ │ │ └── main.scss │ │ │ ├── sassdoc.scss │ │ │ └── use-use │ │ │ │ ├── _first.scss │ │ │ │ ├── _second.scss │ │ │ │ └── main.scss │ │ │ ├── definition │ │ │ ├── AppButton.astro │ │ │ ├── AppButton.svelte │ │ │ ├── AppButton.vue │ │ │ ├── circular.scss │ │ │ └── main.scss │ │ │ ├── diagnostics │ │ │ ├── AppButton.astro │ │ │ ├── AppButton.svelte │ │ │ ├── AppButton.vue │ │ │ ├── _helpers.scss │ │ │ ├── circular.scss │ │ │ └── main.scss │ │ │ ├── hover │ │ │ ├── AppButton.astro │ │ │ ├── AppButton.svelte │ │ │ ├── AppButton.vue │ │ │ ├── _config.scss │ │ │ ├── circular.scss │ │ │ ├── collision.scss │ │ │ └── main.scss │ │ │ ├── namespace │ │ │ ├── _functions.scss │ │ │ ├── _index.scss │ │ │ ├── _mixins.scss │ │ │ ├── _show.scss │ │ │ └── _variables.scss │ │ │ ├── node_modules │ │ │ └── bootstrap │ │ │ │ ├── package.json │ │ │ │ └── scss │ │ │ │ └── bootstrap.scss │ │ │ ├── pkg-import │ │ │ ├── node_modules │ │ │ │ ├── @my-scope │ │ │ │ │ └── my-components │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ ├── package.json │ │ │ │ │ │ └── styles │ │ │ │ │ │ ├── colors.scss │ │ │ │ │ │ └── index.scss │ │ │ │ └── my-components │ │ │ │ │ ├── index.js │ │ │ │ │ ├── package.json │ │ │ │ │ └── styles │ │ │ │ │ ├── colors.scss │ │ │ │ │ └── index.scss │ │ │ └── src │ │ │ │ ├── scoped.scss │ │ │ │ └── styles.scss │ │ │ ├── references │ │ │ ├── _dev.scss │ │ │ ├── _fun.scss │ │ │ ├── circular.scss │ │ │ └── one.scss │ │ │ ├── signature │ │ │ ├── AppButton.astro │ │ │ ├── AppButton.svelte │ │ │ ├── AppButton.vue │ │ │ └── main.scss │ │ │ └── styles.scss │ ├── mocha.js │ ├── runTest.js │ ├── suggest-from-use-only │ │ ├── helper.js │ │ ├── index.js │ │ ├── suggest-from-use-only.test.js │ │ └── workspace │ │ │ ├── .vscode │ │ │ └── settings.json │ │ │ ├── _a.scss │ │ │ ├── _b.scss │ │ │ ├── _c.scss │ │ │ ├── _d.scss │ │ │ └── styles.scss │ └── util.js └── web │ ├── runTest.js │ └── suite │ ├── completion-helper.js │ ├── completion-placeholders.test.js │ ├── completion-sassdoc.test.js │ ├── completion.test.js │ ├── definitions-helper.js │ ├── definitions.test.js │ ├── hover-helper.js │ ├── hover.test.js │ ├── index.js │ ├── signature-helper.js │ ├── signature.test.js │ └── util.js └── tsconfig.json /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = tab 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.yml] 12 | indent_style = space 13 | indent_size = 2 14 | 15 | [*.json] 16 | indent_style = space 17 | indent_size = 2 18 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto eol=lf 2 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [wkillerud] 2 | ko_fi: williamkillerud 3 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/01-bug.yml: -------------------------------------------------------------------------------- 1 | name: "Bug report" 2 | description: Report an issue or possible bug 3 | labels: [] 4 | assignees: [] 5 | body: 6 | - type: markdown 7 | attributes: 8 | value: | 9 | Thank you for taking the time to file a bug report! Please fill out this form as completely as possible. 10 | 11 | ✅ I am using the latest version of Some Sass. 12 | ✅ I am using the latest version of my editor. 13 | - type: input 14 | id: editor 15 | attributes: 16 | label: In which editor is this a problem? 17 | description: If you use an editor other than VS Code or VSCodium, please try to reproduce the issue in either of those editors and let us know if it works there or not. 18 | value: Visual Studio Code 19 | validations: 20 | required: true 21 | - type: textarea 22 | id: bug-description 23 | attributes: 24 | label: Describe the bug 25 | validations: 26 | required: true 27 | - type: textarea 28 | id: bug-expectation 29 | attributes: 30 | label: What's the expected result? 31 | description: Describe what you expect to happen. 32 | validations: 33 | required: true 34 | - type: input 35 | id: bug-reproduction 36 | attributes: 37 | label: Link to minimal reproducible example 38 | description: 'A minimal reproduction is required. If a report is vague (e.g. just a generic error message) and has no reproduction, it may be closed. Not sure how to create a minimal example? [Read our guide](https://wkillerud.github.io/some-sass/contributing/reporting-bugs.html)' 39 | placeholder: 'https://github.com/wkillerud/some-sass-issue-template' 40 | - type: checkboxes 41 | id: will-pr 42 | attributes: 43 | label: Participation 44 | options: 45 | - label: I am willing to submit a pull request for this issue. 46 | required: false 47 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: true 2 | contact_links: 3 | - name: Ideas for new features, improvements 4 | url: https://github.com/wkillerud/some-sass/discussions 5 | about: Suggest additions or improvements to Some Sass in Discussions 6 | - name: Questions when setting up Some Sass in an editor 7 | url: https://github.com/wkillerud/some-sass/discussions 8 | about: Please use Discussions if you have questions when configuring a language server client in a new editor 9 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /.github/workflows/publish_docs.yml: -------------------------------------------------------------------------------- 1 | name: Publish docs 2 | on: 3 | push: 4 | branches: 5 | - main 6 | paths: 7 | - "docs/**" 8 | 9 | jobs: 10 | publish: 11 | runs-on: ubuntu-latest 12 | permissions: 13 | contents: write # To push a branch 14 | pages: write # To push to a GitHub Pages site 15 | id-token: write # To update the deployment status 16 | steps: 17 | - uses: actions/checkout@v4 18 | with: 19 | fetch-depth: 0 20 | - name: Install latest mdbook 21 | run: | 22 | tag=$(curl 'https://api.github.com/repos/rust-lang/mdbook/releases/latest' | jq -r '.tag_name') 23 | url="https://github.com/rust-lang/mdbook/releases/download/${tag}/mdbook-${tag}-x86_64-unknown-linux-gnu.tar.gz" 24 | mkdir mdbook 25 | curl -sSL $url | tar -xz --directory=./mdbook 26 | echo `pwd`/mdbook >> $GITHUB_PATH 27 | - name: Build Book 28 | run: | 29 | cd docs 30 | mdbook build 31 | - name: Setup Pages 32 | uses: actions/configure-pages@v5 33 | - name: Upload artifact 34 | uses: actions/upload-pages-artifact@v3 35 | with: 36 | path: "docs/book" 37 | - name: Deploy to GitHub Pages 38 | id: deployment 39 | uses: actions/deploy-pages@v4 40 | -------------------------------------------------------------------------------- /.github/workflows/pull_request.yml: -------------------------------------------------------------------------------- 1 | name: Pull Request 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - main 7 | 8 | jobs: 9 | test: 10 | strategy: 11 | matrix: 12 | os: [ubuntu-latest, macos-latest, windows-latest] 13 | runs-on: ${{ matrix.os }} 14 | steps: 15 | - name: Checkout 16 | uses: actions/checkout@v4 17 | 18 | - name: Setup Node 19 | uses: actions/setup-node@v4 20 | with: 21 | node-version: "lts/*" 22 | 23 | - name: Update npm for attestation feature 24 | run: npm install -g npm@latest 25 | 26 | - name: Install dependencies 27 | run: npm clean-install 28 | 29 | - name: Verify the integrity of provenance attestations and registry signatures for installed dependencies 30 | run: npm audit signatures 31 | 32 | - name: Run linter 33 | run: npm run lint 34 | 35 | - name: Build extension 36 | run: npm run build:production 37 | 38 | - name: Run tests 39 | run: npm run test 40 | 41 | - name: Run e2e tests in simulated X environment 42 | run: xvfb-run -a npm run test:e2e 43 | if: runner.os == 'Linux' 44 | 45 | - name: Run e2e tests 46 | if: runner.os != 'Linux' 47 | uses: nick-fields/retry@9417ab499314dfe692edb043ded2ff9b3f5f0a68 48 | with: 49 | timeout_minutes: 5 50 | max_attempts: 3 51 | command: npm run test:e2e 52 | 53 | - name: Run web e2e tests 54 | if: runner.os != 'macOS' 55 | uses: nick-fields/retry@9417ab499314dfe692edb043ded2ff9b3f5f0a68 56 | with: 57 | timeout_minutes: 5 58 | max_attempts: 3 59 | command: npm run test:web 60 | -------------------------------------------------------------------------------- /.github/workflows/release-vscode.yml: -------------------------------------------------------------------------------- 1 | name: Release extension 2 | 3 | on: 4 | push: 5 | tags: 6 | - some-sass@*.*.* 7 | 8 | permissions: 9 | contents: read # for checkout 10 | 11 | jobs: 12 | release: 13 | name: Release 14 | runs-on: ubuntu-latest 15 | permissions: 16 | contents: write # to be able to publish a GitHub release 17 | issues: write # to be able to comment on released issues 18 | pull-requests: write # to be able to comment on released pull requests 19 | id-token: write # to enable use of OIDC for npm provenance 20 | 21 | steps: 22 | - name: Checkout 23 | uses: actions/checkout@v4 24 | with: 25 | fetch-depth: 0 26 | 27 | - name: Setup Node.js 28 | uses: actions/setup-node@v4 29 | with: 30 | node-version: "lts/*" 31 | registry-url: "https://registry.npmjs.org" 32 | 33 | - name: Update npm for attestation feature 34 | run: npm install -g npm@latest 35 | 36 | - name: Install dependencies 37 | run: npm clean-install 38 | 39 | - name: Verify the integrity of provenance attestations and registry signatures for installed dependencies 40 | run: npm audit signatures 41 | 42 | - name: Build 43 | run: npm run build:production 44 | 45 | - name: Test 46 | run: npm run test 47 | 48 | - name: Run e2e tests in simulated X environment 49 | run: xvfb-run -a npm run test:e2e 50 | 51 | - name: Run web e2e tests 52 | uses: nick-fields/retry@9417ab499314dfe692edb043ded2ff9b3f5f0a68 53 | with: 54 | timeout_minutes: 5 55 | max_attempts: 3 56 | command: npm run test:web 57 | 58 | - name: Publish extension 59 | run: | 60 | npm run package 61 | npx vsce publish --packagePath vscode-extension/some-sass.vsix -p ${{ secrets.VSCE_PAT }} 62 | npx ovsx publish vscode-extension/some-sass.vsix -p ${{ secrets.OVSX_PAT }} 63 | 64 | - name: Release 65 | uses: softprops/action-gh-release@v2 66 | with: 67 | generate_release_notes: true 68 | files: | 69 | vscode-extension/some-sass.vsix 70 | env: 71 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 72 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | push: 5 | tags: 6 | - some-sass-language-server@*.*.* 7 | 8 | permissions: 9 | contents: read # for checkout 10 | 11 | jobs: 12 | release: 13 | name: Release 14 | runs-on: ubuntu-latest 15 | permissions: 16 | contents: write # to be able to publish a GitHub release 17 | issues: write # to be able to comment on released issues 18 | pull-requests: write # to be able to comment on released pull requests 19 | id-token: write # to enable use of OIDC for npm provenance 20 | 21 | steps: 22 | - name: Checkout 23 | uses: actions/checkout@v4 24 | with: 25 | fetch-depth: 0 26 | 27 | - name: Setup Node.js 28 | uses: actions/setup-node@v4 29 | with: 30 | node-version: "lts/*" 31 | registry-url: "https://registry.npmjs.org" 32 | 33 | - name: Update npm for attestation feature 34 | run: npm install -g npm@latest 35 | 36 | - name: Install dependencies 37 | run: npm clean-install 38 | 39 | - name: Verify the integrity of provenance attestations and registry signatures for installed dependencies 40 | run: npm audit signatures 41 | 42 | - name: Build 43 | run: npm run build:production 44 | 45 | - name: Test 46 | run: npm run test 47 | 48 | - name: Run e2e tests in simulated X environment 49 | run: xvfb-run -a npm run test:e2e 50 | 51 | - name: Run web e2e tests 52 | uses: nick-fields/retry@9417ab499314dfe692edb043ded2ff9b3f5f0a68 53 | with: 54 | timeout_minutes: 5 55 | max_attempts: 3 56 | command: npm run test:web 57 | 58 | - name: Publish packages 59 | run: npx nx release publish 60 | shell: bash 61 | env: 62 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} 63 | NPM_CONFIG_PROVENANCE: true 64 | VSCE_PAT: ${{ secrets.VSCE_PAT }} 65 | OVSX_PAT: ${{ secrets.OVSX_PAT }} 66 | 67 | - name: Release 68 | uses: softprops/action-gh-release@v2 69 | with: 70 | generate_release_notes: true 71 | make_latest: false 72 | env: 73 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 74 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | 3 | # Logs 4 | logs/ 5 | *.log 6 | npm-debug.log* 7 | .cpuprofile 8 | .heapprofile 9 | 10 | # Dependency directory 11 | node_modules/ 12 | !vscode-extension/test/**/node_modules 13 | 14 | # Compiled and temporary files 15 | dist/ 16 | out/ 17 | *.vsix 18 | .vscode-test 19 | .vscode-test-web 20 | .eslintcache 21 | .nyc_output 22 | coverage/ 23 | docs/book/ 24 | 25 | # Configuration 26 | .eslintcache 27 | 28 | 29 | .nx/cache 30 | .nx/workspace-data 31 | 32 | *.cpuprofile 33 | *.heapprofile 34 | -------------------------------------------------------------------------------- /.husky/commit-msg: -------------------------------------------------------------------------------- 1 | npx --no -- commitlint --edit ${1} 2 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | npm run lint-staged 2 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | save-exact=true 2 | ; Workaround for https://github.com/nrwl/nx/issues/22066, should be removed once fixed. 3 | legacy-peer-deps=true 4 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 22.16.0 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | # Add files here to ignore them from prettier formatting 2 | /dist 3 | /coverage 4 | /.nx/cache -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "all" 3 | } 4 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["vitest.explorer", "esbenp.prettier-vscode"] 3 | } 4 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | // A launch configuration that compiles the extension and then opens it inside a new window 2 | { 3 | "version": "0.2.0", 4 | "configurations": [ 5 | { 6 | "name": "Attach to language server running with --inspect", 7 | "port": 9229, 8 | "request": "attach", 9 | "skipFiles": [ 10 | "/**" 11 | ], 12 | "type": "node" 13 | }, 14 | { 15 | "type": "extensionHost", 16 | "request": "launch", 17 | "name": "Launch extension", 18 | "runtimeExecutable": "${execPath}", 19 | "args": ["--extensionDevelopmentPath=${workspaceRoot}/vscode-extension"], 20 | "outFiles": ["${workspaceRoot}/vscode-extension/dist/**/*.js"], 21 | "autoAttachChildProcesses": true 22 | }, 23 | { 24 | "name": "Launch web extension", 25 | "type": "extensionHost", 26 | "debugWebWorkerHost": true, 27 | "request": "launch", 28 | "args": [ 29 | "--extensionDevelopmentPath=${workspaceFolder}/vscode-extension", 30 | "--extensionDevelopmentKind=web" 31 | ], 32 | "outFiles": ["${workspaceFolder}/vscode-extension/dist/browser-*.js"], 33 | "autoAttachChildProcesses": true 34 | } 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "somesass.scannerDepth": 30, 3 | "somesass.scannerExclude": [ 4 | "**/.git/**", 5 | "**/node_modules/**", 6 | "**/bower_components/**" 7 | ], 8 | "somesass.scanImportedFiles": true, 9 | "somesass.suggestAllFromOpenDocument": false, 10 | "somesass.suggestFromUseOnly": false, 11 | "somesass.suggestionStyle": "all", 12 | "somesass.suggestFunctionsInStringContextAfterSymbols": " (+-*%" 13 | } 14 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | While not an official Sass project, we strive to follow the [Sass Community Guidelines](https://sass-lang.com/community-guidelines/). 2 | 3 | - Be considerate 4 | - Be open and inviting 5 | - Be respectful 6 | - Take responsibility for our words and actions 7 | - Be collaborative 8 | - Value decisiveness, clarity and open communication 9 | - Be responsive and helpful 10 | - Step down considerately 11 | -------------------------------------------------------------------------------- /commitlint.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import("@commitlint/config-conventional")} */ 2 | module.exports = { 3 | extends: ["@commitlint/config-conventional"], 4 | rules: { 5 | "header-max-length": [0], 6 | "body-max-line-length": [0], 7 | "footer-max-line-length": [0], 8 | }, 9 | }; 10 | -------------------------------------------------------------------------------- /docs/book.toml: -------------------------------------------------------------------------------- 1 | [book] 2 | authors = ["William Killerud"] 3 | language = "en" 4 | multilingual = false 5 | src = "src" 6 | title = "Documentation for Some Sass" 7 | description = "Some Sass is an extension for Visual Studio Code as well as a standalone LSP server for SCSS. It provides code suggestions, hover information with SassSoc and code navigation for SCSS. It has full support for @use and @forward, including prefixes and hide/show." 8 | -------------------------------------------------------------------------------- /docs/src/SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Summary 2 | 3 | [Introduction](README.md) 4 | 5 | # User guide 6 | 7 | - [IntelliSense](user-guide/completions.md) 8 | - [Navigation](user-guide/navigation.md) 9 | - [Hover info](user-guide/hover.md) 10 | - [Refactoring](user-guide/refactoring.md) 11 | - [Diagnostics](user-guide/diagnostics.md) 12 | - [Color decorators](user-guide/color.md) 13 | - [Settings](user-guide/settings.md) 14 | 15 | # Use outside VS Code 16 | 17 | - [Getting started](language-server/getting-started.md) 18 | - [Configure a client](language-server/configure-a-client.md) 19 | - [Existing clients](language-server/existing-clients.md) 20 | - [Helix](language-server/helix.md) 21 | - [Neovim](language-server/neovim.md) 22 | - [Sublime Text](language-server/sublime-text.md) 23 | 24 | - [Settings](language-server/settings.md) 25 | 26 | # Contributing to Some Sass 27 | 28 | - [New contributors](contributing/new-contributors.md) 29 | - [Reporting bugs](contributing/reporting-bugs.md) 30 | - [Extensions for VS Code](contributing/extensions-for-vs-code.md) 31 | - [Language Server Protocol](contributing/language-server-protocol.md) 32 | - [Development environment](contributing/development-environment.md) 33 | - [Testing in other editors](contributing/testing-other-editors.md) 34 | - [Architecture](contributing/architecture.md) 35 | - [Building](contributing/building.md) 36 | - [Automated tests](contributing/automated-tests.md) 37 | - [Test coverage](contributing/test-coverage.md) 38 | - [Debugging](contributing/debugging.md) 39 | - [Debugging unit tests](contributing/debugging-unit-tests.md) 40 | - [Debugging performance](contributing/debugging-performance.md) 41 | - [Debugging in the browser](contributing/debugging-in-browser.md) 42 | - [Releasing new versions](contributing/releases.md) 43 | - [Writing documentation](contributing/writing-documentation.md) 44 | -------------------------------------------------------------------------------- /docs/src/contributing/automated-tests.md: -------------------------------------------------------------------------------- 1 | # Automated tests 2 | 3 | This document describes how to run the automated tests and what the different tests cover. 4 | 5 | ## Unit tests 6 | 7 | All packages in `packages/` have unit tests. To run them: 8 | 9 | ```sh 10 | npm run test 11 | ``` 12 | 13 | The test runner is [Vitest]. 14 | 15 | Unit tests typically cover either a utility function or a language feature such as `doHover`. For language features the tests are typically split in several files, each focusing on part of the functionality of the language feature. 16 | 17 | ## End-to-end tests 18 | 19 | The Visual Studio Code extension includes end-to-end tests. To run them: 20 | 21 | ```sh 22 | npm run test:e2e 23 | ``` 24 | 25 | It also includes end-to-end tests for the web extension. To run them: 26 | 27 | ```sh 28 | npm run test:web 29 | ``` 30 | 31 | The end-to-end tests have some overlap with the unit tests for language features, but are useful to confirm the communication between client and server works as expected. It's also the most practical way to test the `language-server` module. 32 | 33 | ## Run all tests 34 | 35 | A convenience script lets you run all unit tests and end-to-end tests: 36 | 37 | ```sh 38 | npm run test:all 39 | ``` 40 | 41 | [Vitest]: https://vitest.dev/ 42 | -------------------------------------------------------------------------------- /docs/src/contributing/building.md: -------------------------------------------------------------------------------- 1 | # Building 2 | 3 | This document describes how to build Some Sass. 4 | 5 | ## The workspace 6 | 7 | This repo is an `npm` [workspace] with several packages listed in the `"workspaces"` key in the root `package.json`. The packages are listed in order with the "base" package at the top and the published language server and extension toward the bottom. 8 | 9 | ## A full build 10 | 11 | Run this command at the root level of the repo to build all packages: 12 | 13 | ```sh 14 | npm run build 15 | ``` 16 | 17 | This will build all packages and the Visual Studio Code extension. 18 | 19 | ### Partial builds 20 | 21 | Each package has its own `build` command. If you made a change in the `language-server` folder you only have to build that and the `vscode-extension` packages. Of course you can allways do a full build if you want. 22 | 23 | ## Clean builds 24 | 25 | If something unexpected happens with your build you can do a clean build: 26 | 27 | ```sh 28 | npm run clean 29 | npm run clean-install 30 | npm run build 31 | ``` 32 | 33 | This deletes any old build you may have before doing a new build. 34 | 35 | [workspace]: https://docs.npmjs.com/cli/v10/using-npm/workspaces 36 | -------------------------------------------------------------------------------- /docs/src/contributing/debugging-in-browser.md: -------------------------------------------------------------------------------- 1 | # Debugging in the browser 2 | 3 | You can use Some Sass with Visual Studio Code running in the browser. This document describes how you can test Some Sass running in Chromium. 4 | 5 | ## Run the test command 6 | 7 | In a terminal, run: 8 | 9 | ```sh 10 | npm run start:web 11 | ``` 12 | 13 | This opens Visual Studio Code running as a [web extension host][exthost] in Chromium. The language server runs as a [web worker][worker], and is started when you open a Sass file. 14 | 15 | Open the Sass project you're using to test in the extension host window. 16 | If you don't have one you can find several `workspace/` 17 | directories inside `vscode-extension/test/e2e/` in this repository. 18 | 19 | ## Navigating the Chromium developer tools 20 | 21 | Open the developer tools and click the [Sources tab][sources] to set breakpoints. 22 | 23 | The web worker for `browser-server.js` is in the left panel of the Sources tab. If you don't see it, make sure you open a Sass file to activate the extension. 24 | 25 | ![](../images/debugging/chromium-debugger.png) 26 | 27 | In the WorkerExtensionHost you'll see `localhost:3000` and `serverExportVar`. You may find it easier to navigate in `severExportVar` since it uses source maps to match the source code of the language server package. 28 | 29 | [exthost]: https://code.visualstudio.com/api/advanced-topics/extension-host 30 | [sources]: https://developer.chrome.com/docs/devtools/sources 31 | [worker]: https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers 32 | -------------------------------------------------------------------------------- /docs/src/contributing/debugging-performance.md: -------------------------------------------------------------------------------- 1 | # Debugging performance 2 | 3 | Commonly refered to as performance profiling, this document explains how to run a performance test on Some Sass in Visual Studio Code. 4 | 5 | ## Performance Profiling in Visual Studio Code 6 | 7 | To start a performance profile, first [launch the Some Sass extension](./debugging.md) from the Run and Debug pane in Visual Studio Code, then open a file with Sass code. Your debugging pane should look something like the image below. 8 | 9 | ![](../images/debugging/debugging.png) 10 | 11 | The Call stack section lists Launch extension, which has four list items. The fourth list item, `node-server.js`, is the Some Sass language server. This is the program we want to profile. 12 | 13 | If you've ever done [performance profiling of JavaScript](https://code.visualstudio.com/docs/nodejs/profiling) in VS Code before, profiling Some Sass works the same way. 14 | 15 | Click or hover over the `node-server.js` row to show additional controls. 16 | 17 | ![](../images/debugging/debugging-profiling-controls.png) 18 | 19 | Once the row is active you should see a list of icon buttons. The one we're interested in is the [circle with a dot in the center](https://code.visualstudio.com/docs/nodejs/profiling#_using-the-record-button), Take Performance Profile. Click it, and choose the [type of profile you want](https://code.visualstudio.com/docs/nodejs/profiling#_types-of-profiles). Unless you have specific plans, choose to stop the profile manually when asked. 20 | 21 | Do the operations you want to measure (hover, go to definition, edit some code, or what have you). Then, go back to the debugger and click the button again to stop the performance profiling. 22 | 23 | ## Analyzing a performance profile 24 | 25 | You can open the recorded performance profile in Visual Studio Code and dig into the numbers. The VS Code documentation has some tips on [how to analyze a profile](https://code.visualstudio.com/docs/nodejs/profiling#_analyzing-a-profile). 26 | -------------------------------------------------------------------------------- /docs/src/contributing/debugging-unit-tests.md: -------------------------------------------------------------------------------- 1 | # Debugging unit tests 2 | 3 | This document assumes you use Visual Studio Code and have the [Vitest](https://marketplace.visualstudio.com/items?itemName=vitest.explorer) extension. 4 | 5 | Open a unit test file and find the test you want to debug. 6 | 7 | You should see an icon in the gutter. To debug the test, right click and select Debug test. 8 | 9 | ![](../images/debugging/debug-individual-test.gif) 10 | 11 | If you don't see any icons in the gutter it may be because the Vitest extension expects a different version of the `vitest` module. Try updating `vitest` in the repo and the Vitest extension, then restart VS Code. 12 | 13 | ## Test-driven development 14 | 15 | When you work on a language feature it's useful to set up a test and use that while developing. 16 | 17 | The tests have an in-memory file system provider, so you can test how a language feature works with Sass code without making files on disk. 18 | 19 | By using the Vitest debugger you can shorten the feedback loop significantly compared to building the whole project and testing manually in Visual Studio Code. 20 | 21 | ![](../images/debugging/debugging-unit-test.png) 22 | -------------------------------------------------------------------------------- /docs/src/contributing/extensions-for-vs-code.md: -------------------------------------------------------------------------------- 1 | # Extensions for Visual Studio Code 2 | 3 | This is not required reading, but if you want to learn more about extension development these links are a good place to start. 4 | 5 | - [Your first extension](https://code.visualstudio.com/api/get-started/your-first-extension) 6 | 7 | Some Sass is a language server extension. It can also run in the browser. The project has automated end-to-end tests for both Electron and the browser. 8 | 9 | - [Language server extension guide](https://code.visualstudio.com/api/language-extensions/language-server-extension-guide) 10 | - [Web extensions](https://code.visualstudio.com/api/extension-guides/web-extensions) 11 | -------------------------------------------------------------------------------- /docs/src/contributing/language-server-protocol.md: -------------------------------------------------------------------------------- 1 | # Language Server Protocol 2 | 3 | This is not required reading, but read on if you want to learn more about language servers and the language server protocol (LSP). 4 | 5 | From [Why Language Server?][why-lsp]: 6 | 7 | > [The] Language Server Protocol [...] standardizes the communication between language tooling and code editor. This way [...] any LSP-compliant language toolings can integrate with multiple LSP-compliant code editors, and any LSP-compliant code editors can easily pick up multiple LSP-compliant language toolings. LSP is a win for both language tooling providers and code editor vendors! 8 | 9 | In other words, LSP lets you build the language support tools once and run in any editor that has an LSP client. 10 | 11 | For the most part you don't need to worry about the implementation details of the LSP. Microsoft's [TypeScript implementation][implementation] handles the nitty-gritty. 12 | 13 | ## Language features 14 | 15 | The Visual Studio Code documentation for [Programatic language features][features] gives a good sense of what's possible with LSP. If you want to dive deep, the [specification] lists all the messages and their parameters. 16 | 17 | [why-lsp]: https://code.visualstudio.com/api/language-extensions/language-server-extension-guide#why-language-server 18 | [features]: https://code.visualstudio.com/api/language-extensions/programmatic-language-features 19 | [implementation]: https://github.com/microsoft/vscode-languageserver-node/tree/main 20 | [specification]: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/ 21 | -------------------------------------------------------------------------------- /docs/src/contributing/new-contributors.md: -------------------------------------------------------------------------------- 1 | # New contributors 2 | 3 | Thank you for showing an interest in contributing 🌟 4 | 5 | If you've never worked on Some Sass you're in the right place. There are several ways you can help. 6 | 7 | - Share your setup in Discussions' [Show and tell](https://github.com/wkillerud/some-sass/discussions/categories/show-and-tell). 8 | - [Report bugs](./reporting-bugs.md) with example code that demonstrates the problem. 9 | - Research [open issues](https://github.com/wkillerud/some-sass/issues) to find out what needs to be done. 10 | - [Configure language clients](../language-server/getting-started.md) for more editors. 11 | - Improve this [documentation](./writing-documentation.md), add screenshots or recordings. 12 | - Add unit tests or end-to-end tests where missing. 13 | - Volunteer to fix bugs or add missing features. 14 | 15 | Diving in to code? You may be interested in: 16 | 17 | - Primers on [extensions for Visual Studio Code](./extensions-for-vs-code.md) and the [Language Server Protocol](./language-server-protocol.md) 18 | - How you set up your [development environment](./development-environment.md). 19 | - And before long you'll need to do some [debugging](./debugging.md). 20 | -------------------------------------------------------------------------------- /docs/src/contributing/reporting-bugs.md: -------------------------------------------------------------------------------- 1 | # Reporting bugs 2 | 3 | If you discover something is wrong or unexpected as you're using Some Sass, 4 | it's helpful to create a minimal reproduction of the issue. 5 | 6 | A minimal reproduction is a Sass workspace that has only enough code to demonstrate the issue. 7 | Having a minimal reproduction in a new project helps to confirm that this is a repeatable problem, 8 | and is not caused by something else in your development environment or project. 9 | 10 | Sharing a minimal reproduction is often required when filing a bug report. 11 | 12 | ## Create a Sass workspace with our template repository 13 | 14 | If you can reproduce the issue with a single file, a code snippet included as part of the issue is fine. If not, you can [use this template repository on GitHub](https://github.com/wkillerud/some-sass-issue-template) to quickly set up a minimal reproduction. 15 | 16 | ## Create an issue 17 | 18 | If the bug can be reproduced, then it is time to [create an issue and file a bug report](https://github.com/wkillerud/some-sass/issues/new/choose). 19 | 20 | Remember to include the link to your minimal reproduction. Please also include step by step instructions on how to reproduce the issue. 21 | 22 | ## Want to help fix the problem? 23 | 24 | It can be daunting to jump in, but it's also a very rewarding feeling to improve your own tools. If you're up for it, volunteer to send a pull request. You can always change your mind later, just let us know that you need someone else to try. 25 | 26 | You can learn how to set up the development environment and more later on in the Contributing section of this documentation. 27 | -------------------------------------------------------------------------------- /docs/src/contributing/test-coverage.md: -------------------------------------------------------------------------------- 1 | # Test coverage 2 | 3 | While there's no target for test coverage in the project, coverage reports can be useful to see if there's a corner case that should be tested. 4 | 5 | ## Generate a coverage report 6 | 7 | Coverage reports are generated per package. To generate a report run: 8 | 9 | ```sh 10 | npm run coverage 11 | ``` 12 | 13 | Coverage reports are printed to the terminal. HTML versions you can open in a browser get generated in each package's directory. Look for a `coverage/` folder and open `index.html` in your browser. 14 | 15 | ![](../images/tests/coverage-report.png) 16 | -------------------------------------------------------------------------------- /docs/src/contributing/testing-other-editors.md: -------------------------------------------------------------------------------- 1 | # Testing in other editors 2 | 3 | While it's recommended to use Visual Studio Code or VSCodium, you can use other editors to test and debug the language server. 4 | 5 | In this document we'll look at how we can test our local development build in the Helix editor. 6 | 7 | ## Install the local version globally 8 | 9 | To make the local version of `some-sass-language-server` available on `PATH`, go to its directory and run `npm install --global .`. 10 | 11 | ```sh 12 | cd packages/language-server/ 13 | npm install --global . 14 | ``` 15 | 16 | Editors using Some Sass from `PATH` now use your local build. 17 | 18 | ## Check the logs 19 | 20 | In Helix, run the `hx` command with the `-v` verbose flag. Do your test, and then run the `:log-open` command to see the traffic between server and client. 21 | -------------------------------------------------------------------------------- /docs/src/images/README.md: -------------------------------------------------------------------------------- 1 | # Images 2 | 3 | To make a new highlight reel: 4 | 5 | - record individual GIFs, for example using [CleanShot X](https://cleanshot.com/) 6 | - using [ImageMagick](https://formulae.brew.sh/formula/imagemagick), run `convert first.gif second.gif third.gif highlight-reel.gif` 7 | -------------------------------------------------------------------------------- /docs/src/images/architecture/browser.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/docs/src/images/architecture/browser.png -------------------------------------------------------------------------------- /docs/src/images/architecture/node.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/docs/src/images/architecture/node.png -------------------------------------------------------------------------------- /docs/src/images/architecture/parser-cache.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/docs/src/images/architecture/parser-cache.png -------------------------------------------------------------------------------- /docs/src/images/debugging/attach-to-server.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/docs/src/images/debugging/attach-to-server.png -------------------------------------------------------------------------------- /docs/src/images/debugging/chromium-debugger.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/docs/src/images/debugging/chromium-debugger.png -------------------------------------------------------------------------------- /docs/src/images/debugging/debug-individual-test.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/docs/src/images/debugging/debug-individual-test.gif -------------------------------------------------------------------------------- /docs/src/images/debugging/debug-log-output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/docs/src/images/debugging/debug-log-output.png -------------------------------------------------------------------------------- /docs/src/images/debugging/debugging-e2e-test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/docs/src/images/debugging/debugging-e2e-test.png -------------------------------------------------------------------------------- /docs/src/images/debugging/debugging-profiling-controls.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/docs/src/images/debugging/debugging-profiling-controls.png -------------------------------------------------------------------------------- /docs/src/images/debugging/debugging-unit-test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/docs/src/images/debugging/debugging-unit-test.png -------------------------------------------------------------------------------- /docs/src/images/debugging/debugging.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/docs/src/images/debugging/debugging.png -------------------------------------------------------------------------------- /docs/src/images/debugging/launch-browser-extension.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/docs/src/images/debugging/launch-browser-extension.png -------------------------------------------------------------------------------- /docs/src/images/debugging/launch-extension.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/docs/src/images/debugging/launch-extension.png -------------------------------------------------------------------------------- /docs/src/images/highlight-reel.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/docs/src/images/highlight-reel.gif -------------------------------------------------------------------------------- /docs/src/images/tests/coverage-report.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/docs/src/images/tests/coverage-report.png -------------------------------------------------------------------------------- /docs/src/images/usage/color-decorators.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/docs/src/images/usage/color-decorators.png -------------------------------------------------------------------------------- /docs/src/images/usage/diagnostics-deprecated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/docs/src/images/usage/diagnostics-deprecated.png -------------------------------------------------------------------------------- /docs/src/images/usage/diagnostics-indented.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/docs/src/images/usage/diagnostics-indented.png -------------------------------------------------------------------------------- /docs/src/images/usage/extract.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/docs/src/images/usage/extract.gif -------------------------------------------------------------------------------- /docs/src/images/usage/find-references.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/docs/src/images/usage/find-references.gif -------------------------------------------------------------------------------- /docs/src/images/usage/go-to-definition.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/docs/src/images/usage/go-to-definition.gif -------------------------------------------------------------------------------- /docs/src/images/usage/import-completions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/docs/src/images/usage/import-completions.png -------------------------------------------------------------------------------- /docs/src/images/usage/pkg-imports.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/docs/src/images/usage/pkg-imports.png -------------------------------------------------------------------------------- /docs/src/images/usage/placeholder-declare.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/docs/src/images/usage/placeholder-declare.png -------------------------------------------------------------------------------- /docs/src/images/usage/placeholder-extend.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/docs/src/images/usage/placeholder-extend.png -------------------------------------------------------------------------------- /docs/src/images/usage/rename-symbol.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/docs/src/images/usage/rename-symbol.gif -------------------------------------------------------------------------------- /docs/src/images/usage/sass-built-in-hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/docs/src/images/usage/sass-built-in-hover.png -------------------------------------------------------------------------------- /docs/src/images/usage/sassdoc-annotation-hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/docs/src/images/usage/sassdoc-annotation-hover.png -------------------------------------------------------------------------------- /docs/src/images/usage/sassdoc-block.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/docs/src/images/usage/sassdoc-block.gif -------------------------------------------------------------------------------- /docs/src/images/usage/sassdoc-hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/docs/src/images/usage/sassdoc-hover.png -------------------------------------------------------------------------------- /docs/src/images/usage/settings-built-in.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/docs/src/images/usage/settings-built-in.png -------------------------------------------------------------------------------- /docs/src/images/usage/signature-helper.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/docs/src/images/usage/signature-helper.gif -------------------------------------------------------------------------------- /docs/src/images/usage/string-literal-union-type.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/docs/src/images/usage/string-literal-union-type.png -------------------------------------------------------------------------------- /docs/src/images/usage/suggestions-mixins.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/docs/src/images/usage/suggestions-mixins.gif -------------------------------------------------------------------------------- /docs/src/language-server/existing-clients.md: -------------------------------------------------------------------------------- 1 | # Existing clients 2 | 3 | In addition to the extension for Visual Studio Code and VSCodium, 4 | these are editors with ready-configured clients, maintained by the community. 5 | 6 | 7 | 8 | - [Helix](./helix.md) 9 | - [Neovim](./neovim.md) 10 | - [Sublime Text](./sublime-text.md) 11 | -------------------------------------------------------------------------------- /docs/src/language-server/getting-started.md: -------------------------------------------------------------------------------- 1 | # Use Some Sass outside Visual Studio Code 2 | 3 | Some Sass is a language server using the [Language Server Protocol (LSP)][lsp]. 4 | 5 | The language server is [published independently to npm][npm], and can be used with any editor that has an LSP client. 6 | 7 | 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`. 8 | 9 | ## Getting started 10 | 11 | You can install the language server with `npm`: 12 | 13 | ```sh 14 | npm install --global some-sass-language-server 15 | ``` 16 | 17 | Then start the language server like so: 18 | 19 | ```sh 20 | some-sass-language-server --stdio 21 | ``` 22 | 23 | Tweak the log level by using the `--loglevel` argument, or by using the `somesass.workspace.logLevel` setting. Available loglevels are: 24 | 25 | - silent 26 | - fatal 27 | - error 28 | - warn 29 | - info (default) 30 | - debug 31 | - trace 32 | 33 | ```sh 34 | some-sass-language-server --stdio --loglevel debug 35 | ``` 36 | 37 | ## Configure your editor's client 38 | 39 | The next step is to [configure your editor's language client](./configure-a-client.md). 40 | 41 | [lsp]: https://microsoft.github.io/language-server-protocol/ 42 | [npm]: https://www.npmjs.com/package/some-sass-language-server 43 | -------------------------------------------------------------------------------- /docs/src/language-server/helix.md: -------------------------------------------------------------------------------- 1 | # Helix 2 | 3 | You can configure new language servers in [`.config/helix/languages.toml`](https://docs.helix-editor.com/guides/adding_languages.html). 4 | 5 | [Install the language server if you haven't already](./getting-started.md), then add this config you `languages.toml`. 6 | 7 | ```toml 8 | [language-server.some-sass-language-server] 9 | command = "some-sass-language-server" 10 | args = ["--stdio"] 11 | # see https://wkillerud.github.io/some-sass/language-server/settings.html for all available settings 12 | config = { somesass = { workspace = { loadPaths = [] } } } 13 | 14 | [[language]] 15 | name = "scss" 16 | language-servers = [ 17 | { name = "some-sass-language-server" } 18 | ] 19 | ``` 20 | 21 | The language server will start once you open an SCSS file. 22 | 23 | You can also use it for CSS. 24 | 25 | ```toml 26 | [[language]] 27 | name = "css" 28 | language-servers = [ 29 | { name = "some-sass-language-server" } 30 | ] 31 | ``` 32 | 33 | At time of writing there doesn't seem to be a grammar for Sass indented available in Helix. 34 | -------------------------------------------------------------------------------- /docs/src/language-server/neovim.md: -------------------------------------------------------------------------------- 1 | # Neovim 2 | 3 | Neovim has a ready-to-use client configuration maintained by the community. 4 | 5 | There are two options: 6 | 7 | - [lspconfig](https://github.com/neovim/nvim-lspconfig/blob/master/doc/server_configurations.md#somesass_ls) 8 | - [mason](https://mason-registry.dev/registry/list#some-sass-language-server) 9 | -------------------------------------------------------------------------------- /docs/src/language-server/sublime-text.md: -------------------------------------------------------------------------------- 1 | # Sublime Text 2 | 3 | Sublime Text has a [ready-to-use client implementation](https://github.com/sublimelsp/LSP-some-sass) maintained by the community. 4 | -------------------------------------------------------------------------------- /docs/src/user-guide/color.md: -------------------------------------------------------------------------------- 1 | # Color decorators 2 | 3 | This document describes the color decorators features of Some Sass. 4 | 5 | ## Decorators for Sass variables 6 | 7 | Some Sass adds decorators for color variables where they are used. 8 | 9 | ![](../images/usage/color-decorators.png) 10 | -------------------------------------------------------------------------------- /docs/src/user-guide/diagnostics.md: -------------------------------------------------------------------------------- 1 | # Diagnostics 2 | 3 | This document describes the diagnostics features of Some Sass. 4 | 5 | ## Deprecated symbols 6 | 7 | Symbols documented as [`@deprecated`](http://sassdoc.com/annotations/#deprecated) with SassDoc is shown 8 | with a strikethrough. 9 | 10 | ![](../images/usage/diagnostics-deprecated.png) 11 | 12 | ## Mixing indentation 13 | 14 | In Sass indented it's important to not mix tabs and spaces when indenting. Some Sass highlights errors if you start mixing them. 15 | 16 | ![](../images/usage/diagnostics-indented.png) 17 | -------------------------------------------------------------------------------- /docs/src/user-guide/hover.md: -------------------------------------------------------------------------------- 1 | # Hover info 2 | 3 | This document describes the hover information given by Some Sass. 4 | 5 | ## Symbol information 6 | 7 | When you hover over a symbol Some Sass shows a preview of the declaration and the name of the file where it is declared. Things get more interesting when you add SassDoc though. 8 | 9 | ## SassDoc documentation 10 | 11 | If a symbol is documented with [SassDoc], the documentation is shown in the hover information like how you might see JSDoc. This is especially helpful if you have a core set of utility functions and mixins, or if you use a Sass library provided by a third party. 12 | 13 | ```scss 14 | /// Calculate a responsive size value relative to a given screen size 15 | /// Will return a CSS rule that corresponds to the given pixel size at 16 | /// the given screen size and scales with changes in screen size 17 | /// @param {Number} $px-size - Size to calculate from, in px without unit 18 | /// @param {Number} $screen-width - Screen width to calculate from, in px without unit, default 1400 19 | /// @param {Number} $screen-height - Screen height to calculate from, in px without unit, default 900 20 | /// @return {Number} - Input expressed as a responsive value 21 | @function relative-size($px-size, $screen-width: 1400, $screen-height: 900) { 22 | // ... 23 | } 24 | ``` 25 | 26 | ![Screenshot showing hover info for a function named relative-size. There's a description of what the function does. There's a list of three parameters of type Number, two of them shown with default values and each with a description.](../images/usage/sassdoc-hover.png) 27 | 28 | ## Sass built-ins 29 | 30 | Hover information for Sass built-ins include links to the reference documentation. 31 | 32 | ![Screenshot showing hover info for the floor function. The information reads Rounds down to the nearest number and includes a link titled Sass reference.](../images/usage/sass-built-in-hover.png) 33 | 34 | ## SassDoc annotations 35 | 36 | Hover information for Sassdoc annotations link to the reference documentation. 37 | 38 | ![Screenshot showing hover info for @param in a SassDoc block. @param and a link to SassDoc reference.](../images/usage/sassdoc-annotation-hover.png) 39 | 40 | [SassDoc]: http://sassdoc.com/annotations#description 41 | -------------------------------------------------------------------------------- /docs/src/user-guide/navigation.md: -------------------------------------------------------------------------------- 1 | # Navigation 2 | 3 | This document describes the navigation features of Some Sass. 4 | 5 | ## Go to definition 6 | 7 | To use this feature, either: 8 | 9 | - Hold down `Cmd`/`Ctrl` and click a symbol. 10 | - Right-click a symbol and choose Go to Definition. 11 | - Press `F12` when the cursor is at a symbol. 12 | 13 | [Go to definition reference](https://code.visualstudio.com/docs/editor/editingevolved#_go-to-definition). 14 | 15 | ![](../images/usage/go-to-definition.gif) 16 | 17 | ## Find references 18 | 19 | To use this feature, either: 20 | 21 | - Right-click a symbol and choose Find all references. 22 | - Press `Shift` + `Alt`/`Opt` + `F12` when the cursor is at a symbol. 23 | 24 | [Find all references reference](https://code.visualstudio.com/docs/getstarted/tips-and-tricks#_find-all-references-view). 25 | 26 | ![](../images/usage/find-references.gif) 27 | 28 | ## Go to symbol 29 | 30 | To use this feature, open the Go menu and choos either: 31 | 32 | - Go to symbol in Editor 33 | - Go to symbol in Workspace 34 | 35 | [Go to symbol reference](https://code.visualstudio.com/Docs/editor/editingevolved#_go-to-symbol). 36 | -------------------------------------------------------------------------------- /docs/src/user-guide/refactoring.md: -------------------------------------------------------------------------------- 1 | # Refactoring 2 | 3 | This document describes the refactoring features of Some Sass. 4 | 5 | ## Rename symbol 6 | 7 | With Some Sass installed you can rename a symbol and it is renamed across the whole workspace. 8 | 9 | [Rename symbols reference](https://code.visualstudio.com/docs/editor/refactoring#_rename-symbol) 10 | 11 | ![](../images/usage/rename-symbol.gif) 12 | 13 | ## Extract 14 | 15 | Some Sass adds code actions to extract a selection to a variable, function or mixin. 16 | 17 | [Extract actions reference](https://code.visualstudio.com/docs/editor/refactoring#_refactoring-actions) 18 | 19 | ![](../images/usage/extract.gif) 20 | -------------------------------------------------------------------------------- /eslint.config.mjs: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | import eslint from "@eslint/js"; 3 | import tseslint from "typescript-eslint"; 4 | import eslintConfigPrettier from "eslint-plugin-prettier/recommended"; 5 | import depend from "eslint-plugin-depend"; 6 | 7 | export default tseslint.config( 8 | eslint.configs.recommended, 9 | ...tseslint.configs.recommended, 10 | eslintConfigPrettier, 11 | { 12 | files: ["**/*.ts"], 13 | plugins: { 14 | depend, 15 | }, 16 | rules: { 17 | "depend/ban-dependencies": "error", 18 | }, 19 | }, 20 | { 21 | ignores: [ 22 | "vscode-extension/.vscode-test/", 23 | "vscode-extension/.vscode-test-web/", 24 | "vscode-extension/test/", 25 | "**/dist/**", 26 | "**/lib/**", 27 | ], 28 | }, 29 | { 30 | rules: { 31 | "prefer-const": "off", 32 | "prefer-spread": "off", 33 | "no-empty": "off", 34 | "no-useless-escape": "off", 35 | "no-prototype-builtins": "off", 36 | "no-case-declarations": "off", 37 | "@typescript-eslint/ban-types": "off", 38 | "@typescript-eslint/no-namespace": "off", 39 | "@typescript-eslint/no-explicit-any": "off", 40 | "@typescript-eslint/no-this-alias": "off", 41 | "@typescript-eslint/no-unused-vars": "warn", 42 | }, 43 | }, 44 | ); 45 | -------------------------------------------------------------------------------- /nx.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/nx/schemas/nx-schema.json", 3 | "targetDefaults": { 4 | "build": { 5 | "dependsOn": ["^build"], 6 | "outputs": ["{projectRoot}/dist"], 7 | "cache": true 8 | }, 9 | "build:production": { 10 | "dependsOn": ["^build:production"], 11 | "outputs": ["{projectRoot}/dist"], 12 | "cache": true 13 | }, 14 | "test": { 15 | "dependsOn": ["^test"], 16 | "cache": true 17 | }, 18 | "coverage": { 19 | "dependsOn": ["^coverage"], 20 | "outputs": ["{projectRoot}/coverage"], 21 | "cache": true 22 | }, 23 | "compile": { 24 | "outputs": ["{projectRoot}/lib"], 25 | "cache": true 26 | }, 27 | "compile-esm": { 28 | "outputs": ["{projectRoot}/lib"], 29 | "cache": true 30 | }, 31 | "mocha": { 32 | "cache": true 33 | }, 34 | "lint": { 35 | "cache": true 36 | }, 37 | "test:e2e": { 38 | "cache": true 39 | }, 40 | "pretest:web": { 41 | "cache": true 42 | }, 43 | "test:web": { 44 | "cache": true 45 | } 46 | }, 47 | "defaultBase": "main", 48 | "plugins": [], 49 | "release": { 50 | "version": { 51 | "conventionalCommits": true 52 | }, 53 | "projectsRelationship": "independent", 54 | "projects": ["packages/*", "vscode-extension/*"], 55 | "releaseTagPattern": "{projectName}@{version}", 56 | "changelog": { 57 | "projectChangelogs": { 58 | "renderOptions": { 59 | "authors": false 60 | } 61 | } 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@somesass/project", 3 | "version": "1.0.0", 4 | "private": true, 5 | "description": "Workspace management for the somesass monorepo", 6 | "workspaces": [ 7 | "packages/*", 8 | "vscode-extension" 9 | ], 10 | "scripts": { 11 | "prepare": "husky", 12 | "build": "nx run-many -t build", 13 | "build:production": "nx run-many -t build:production", 14 | "preclean": "nx reset", 15 | "clean": "nx run-many -t clean", 16 | "postclean": "shx rm -rf node_modules", 17 | "coverage": "nx run-many -t coverage", 18 | "dev": "echo Watching workspace for changes... && nx watch --all -- nx run \\$NX_PROJECT_NAME:build", 19 | "lint": "eslint \"**/*.ts\" --cache", 20 | "lint-staged": "lint-staged", 21 | "package": "nx package some-sass", 22 | "release:dryrun": "nx release --dry-run", 23 | "release": "nx release --skip-publish", 24 | "start:web": "nx start:web some-sass", 25 | "test": "cross-env CI=true nx run-many -t test", 26 | "test:all": "npm run test && npm run test:e2e && npm run test:web", 27 | "test:e2e": "nx test:e2e some-sass", 28 | "test:web": "nx test:web some-sass" 29 | }, 30 | "lint-staged": { 31 | "**/*.ts": [ 32 | "prettier --write", 33 | "eslint --fix" 34 | ] 35 | }, 36 | "devDependencies": { 37 | "@commitlint/cli": "19.8.0", 38 | "@commitlint/config-conventional": "19.8.0", 39 | "@eslint/js": "9.26.0", 40 | "@nx/js": "20.8.1", 41 | "@nx/web": "20.8.1", 42 | "@rspack/cli": "1.3.8", 43 | "@rspack/core": "1.3.8", 44 | "@swc-node/register": "1.10.10", 45 | "@swc/core": "1.11.24", 46 | "@swc/helpers": "0.5.17", 47 | "@types/node": "22.15.3", 48 | "@types/vscode": "1.86.0", 49 | "@vscode/vsce": "3.3.2", 50 | "cross-env": "7.0.3", 51 | "eslint": "9.26.0", 52 | "eslint-config-prettier": "10.1.2", 53 | "eslint-plugin-depend": "1.0.0", 54 | "eslint-plugin-prettier": "5.3.1", 55 | "husky": "9.1.7", 56 | "lint-staged": "15.5.1", 57 | "npm-run-all2": "8.0.1", 58 | "nx": "20.8.1", 59 | "ovsx": "0.10.3", 60 | "prettier": "3.5.3", 61 | "shx": "0.4.0", 62 | "ts-loader": "9.5.2", 63 | "typescript": "5.8.3", 64 | "typescript-eslint": "8.31.1", 65 | "vitest": "3.1.2" 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /packages/language-server/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016-2022 Denis Malinochkin, 2022 William Killerud and contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /packages/language-server/bin/some-sass-language-server: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | const path = require("path"); 3 | const fs = require("fs"); 4 | 5 | const args = process.argv; 6 | 7 | if (args.includes("--version") || args.includes("-v") || args.includes("-V")) { 8 | try { 9 | const pkg = fs.readFileSync( 10 | path.join(__dirname, "..", "package.json"), 11 | "utf-8", 12 | ); 13 | const json = JSON.parse(pkg); 14 | if (!json.version) { 15 | throw new Error(); 16 | } 17 | console.info(json.version); 18 | } catch (e) { 19 | console.info("Something went wrong reading the current version number."); 20 | } 21 | return; 22 | } 23 | 24 | if (args.includes("--help") || args.includes("-h")) { 25 | console.info(`some-sass-language-server <--stdio|--node-ipc|--socket={number}> [--loglevel ] 26 | 27 | For documentation, visit https://wkillerud.github.io/some-sass/language-server/getting-started.html`); 28 | return; 29 | } 30 | 31 | require(path.join(__dirname, "..", "dist", "node-main.js")); 32 | -------------------------------------------------------------------------------- /packages/language-server/rspack.browser.config.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | const path = require("path"); 3 | const rspack = require("@rspack/core"); 4 | 5 | /** @type {import('@rspack/core').Configuration} */ 6 | const config = { 7 | context: __dirname, 8 | target: "webworker", 9 | entry: { 10 | "browser-main": "./src/browser-main.ts", 11 | }, 12 | output: { 13 | libraryTarget: "var", 14 | library: "serverExportVar", 15 | filename: "[name].js", 16 | path: path.join(__dirname, "dist"), 17 | }, 18 | module: { 19 | rules: [ 20 | { 21 | test: /\.m?js/, 22 | resolve: { 23 | fullySpecified: false, 24 | }, 25 | }, 26 | { 27 | test: /\.ts$/, 28 | exclude: [/[\\/]node_modules[\\/]/], 29 | loader: "builtin:swc-loader", 30 | options: { 31 | jsc: { 32 | parser: { 33 | syntax: "typescript", 34 | }, 35 | externalHelpers: true, 36 | }, 37 | }, 38 | }, 39 | ], 40 | }, 41 | resolve: { 42 | extensions: [".ts", ".js"], 43 | mainFields: ["browser", "module", "main"], 44 | conditionNames: ["import", "require", "default"], 45 | fallback: { 46 | events: require.resolve("events/"), 47 | path: require.resolve("path-browserify"), 48 | util: require.resolve("util/"), 49 | url: require.resolve("url/"), 50 | "fs/promises": false, 51 | }, 52 | }, 53 | plugins: [ 54 | new rspack.ProvidePlugin({ 55 | process: "process/browser", 56 | }), 57 | new rspack.optimize.LimitChunkCountPlugin({ 58 | maxChunks: 1, 59 | }), 60 | ], 61 | devtool: false, 62 | }; 63 | 64 | module.exports = (env, argv) => { 65 | if (argv.mode === "development") { 66 | config.devtool = "source-map"; 67 | } 68 | return config; 69 | }; 70 | -------------------------------------------------------------------------------- /packages/language-server/rspack.node.config.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | const path = require("path"); 3 | const rspack = require("@rspack/core"); 4 | 5 | /** @type {import('@rspack/core').Configuration} */ 6 | const config = { 7 | target: "node", 8 | entry: { 9 | "node-main": "./src/node-main.ts", 10 | }, 11 | output: { 12 | filename: "[name].js", 13 | path: path.join(__dirname, "dist"), 14 | libraryTarget: "commonjs2", 15 | }, 16 | resolve: { 17 | extensions: [".ts", ".js"], 18 | conditionNames: ["import", "require", "default"], 19 | mainFields: ["module", "main"], 20 | }, 21 | module: { 22 | rules: [ 23 | { 24 | test: /\.ts$/, 25 | exclude: [/[\\/]node_modules[\\/]/], 26 | loader: "builtin:swc-loader", 27 | options: { 28 | jsc: { 29 | parser: { 30 | syntax: "typescript", 31 | }, 32 | externalHelpers: true, 33 | target: "es2022", 34 | }, 35 | }, 36 | }, 37 | ], 38 | }, 39 | devtool: false, 40 | }; 41 | 42 | module.exports = (env, argv) => { 43 | if (argv.mode === "development") { 44 | config.devtool = "source-map"; 45 | } 46 | return config; 47 | }; 48 | -------------------------------------------------------------------------------- /packages/language-server/src/browser-main.ts: -------------------------------------------------------------------------------- 1 | async function setupBrowser() { 2 | await import("./browser-server"); 3 | } 4 | setupBrowser(); 5 | -------------------------------------------------------------------------------- /packages/language-server/src/browser-server.ts: -------------------------------------------------------------------------------- 1 | import { 2 | BrowserMessageReader, 3 | BrowserMessageWriter, 4 | createConnection, 5 | } from "vscode-languageserver/browser"; 6 | import { SomeSassServer } from "./server"; 7 | 8 | const messageReader = new BrowserMessageReader(self); 9 | const messageWriter = new BrowserMessageWriter(self); 10 | const connection = createConnection(messageReader, messageWriter); 11 | 12 | const runtime = {}; 13 | const server = new SomeSassServer(connection, runtime); 14 | 15 | server.listen(); 16 | -------------------------------------------------------------------------------- /packages/language-server/src/constants.ts: -------------------------------------------------------------------------------- 1 | export const EXTENSION_ID = "some-sass"; 2 | export const REQUEST_FS_STAT = `${EXTENSION_ID}/stat`; 3 | export const REQUEST_FS_FIND_FILES = `${EXTENSION_ID}/find-files`; 4 | export const REQUEST_FS_READ_FILE = `${EXTENSION_ID}/read-file`; 5 | export const REQUEST_FS_READ_DIRECTORY = `${EXTENSION_ID}/read-directory`; 6 | -------------------------------------------------------------------------------- /packages/language-server/src/file-system.ts: -------------------------------------------------------------------------------- 1 | import { FileStat, FileType } from "@somesass/language-services"; 2 | import type { CancellationToken } from "vscode-languageserver"; 3 | import type { URI } from "vscode-uri"; 4 | 5 | /** 6 | * API to abstract away whether or not we have direct file system access. 7 | */ 8 | export interface FileSystemProvider { 9 | exists(uri: URI): Promise; 10 | findFiles( 11 | include: string, 12 | exclude?: string | string[] | null, 13 | maxResults?: number, 14 | token?: CancellationToken, 15 | ): Promise; 16 | readFile(uri: URI, encoding?: BufferEncoding): Promise; 17 | readDirectory(uri: URI): Promise<[string, FileType][]>; 18 | stat(uri: URI): Promise; 19 | realPath(uri: URI): Promise; 20 | } 21 | -------------------------------------------------------------------------------- /packages/language-server/src/node-main.ts: -------------------------------------------------------------------------------- 1 | async function setupNode() { 2 | await import("./node-server"); 3 | } 4 | setupNode(); 5 | -------------------------------------------------------------------------------- /packages/language-server/src/node-server.ts: -------------------------------------------------------------------------------- 1 | import { createConnection, ProposedFeatures } from "vscode-languageserver/node"; 2 | import { NodeFileSystem } from "./node-file-system"; 3 | import { SomeSassServer } from "./server"; 4 | 5 | const connection = createConnection(ProposedFeatures.all); 6 | 7 | console.log = connection.console.log.bind(connection.console); 8 | console.error = connection.console.error.bind(connection.console); 9 | 10 | const runtime = { file: new NodeFileSystem() }; 11 | const server = new SomeSassServer(connection, runtime); 12 | 13 | server.listen(); 14 | -------------------------------------------------------------------------------- /packages/language-server/src/runtime.ts: -------------------------------------------------------------------------------- 1 | import type { FileSystemProvider } from "./file-system"; 2 | 3 | export interface RuntimeEnvironment { 4 | file?: FileSystemProvider; 5 | } 6 | -------------------------------------------------------------------------------- /packages/language-server/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2020", 4 | "lib": ["ES2020", "WebWorker"], 5 | "sourceMap": true, 6 | "module": "commonjs", 7 | "moduleResolution": "node", 8 | "outDir": "out", 9 | "strict": true, 10 | "allowSyntheticDefaultImports": true, 11 | "resolveJsonModule": true 12 | }, 13 | "exclude": ["**/*.test.ts", "vitest.config.mts"] 14 | } 15 | -------------------------------------------------------------------------------- /packages/language-server/vitest.config.mts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vitest/config"; 2 | 3 | export default defineConfig({ 4 | test: { 5 | coverage: { 6 | provider: "v8", 7 | reporter: ["text", "json", "html"], 8 | }, 9 | }, 10 | }); 11 | -------------------------------------------------------------------------------- /packages/language-services/README.md: -------------------------------------------------------------------------------- 1 | # @somesass/language-services 2 | 3 | This is where you find the functionality of the language server, organized in classes that inherit from a base `LanguageFeature` class. 4 | 5 | See [Server architecture](https://wkillerud.github.io/some-sass/contributing/architecture.html#server-architecture) for more information. 6 | -------------------------------------------------------------------------------- /packages/language-services/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@somesass/language-services", 3 | "version": "2.2.0", 4 | "private": true, 5 | "description": "The features powering some-sass-language-server", 6 | "keywords": [ 7 | "scss", 8 | "sass" 9 | ], 10 | "engines": { 11 | "node": ">=20" 12 | }, 13 | "homepage": "https://github.com/wkillerud/some-sass/blob/main/packages/language-services#readme", 14 | "repository": { 15 | "type": "git", 16 | "url": "git+ssh://git@github.com/wkillerud/some-sass.git" 17 | }, 18 | "bugs": { 19 | "url": "https://github.com/wkillerud/some-sass/issues" 20 | }, 21 | "files": [ 22 | "dist/", 23 | "!dist/test/", 24 | "!dist/**/*.test.js" 25 | ], 26 | "main": "dist/language-services.js", 27 | "types": "dist/language-services.d.ts", 28 | "exports": { 29 | ".": { 30 | "types": "./dist/language-services.d.ts", 31 | "default": "./dist/language-services.js" 32 | }, 33 | "./*": { 34 | "types": "./dist/*.d.ts", 35 | "default": "./dist/*.js" 36 | }, 37 | "./feature/*": { 38 | "types": "./dist/feature/*.d.ts", 39 | "default": "./dist/feature/*.js" 40 | } 41 | }, 42 | "author": "William Killerud (https://www.williamkillerud.com/)", 43 | "license": "MIT", 44 | "scripts": { 45 | "build": "tsc", 46 | "build:production": "tsc", 47 | "clean": "shx rm -rf dist node_modules", 48 | "test": "vitest", 49 | "coverage": "vitest run --coverage" 50 | }, 51 | "dependencies": { 52 | "@somesass/vscode-css-languageservice": "2.1.0", 53 | "colorjs.io": "0.5.2", 54 | "es-toolkit": "1.37.2", 55 | "sassdoc-parser": "3.4.1" 56 | }, 57 | "devDependencies": { 58 | "@vitest/coverage-v8": "3.1.2", 59 | "shx": "0.4.0", 60 | "typescript": "5.8.3" 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /packages/language-services/src/features/__tests__/do-complete-node-modules.test.ts: -------------------------------------------------------------------------------- 1 | import { test, assert } from "vitest"; 2 | import { getLanguageService } from "../../language-services"; 3 | import { Position } from "../../language-services-types"; 4 | import { getOptions } from "../../utils/test-helpers"; 5 | 6 | const { fileSystemProvider, ...rest } = getOptions(); 7 | const ls = getLanguageService({ fileSystemProvider, ...rest }); 8 | 9 | ls.configure({ 10 | scss: { 11 | completion: { 12 | suggestFromUseOnly: true, 13 | }, 14 | }, 15 | sass: { 16 | completion: { 17 | suggestFromUseOnly: true, 18 | }, 19 | }, 20 | }); 21 | 22 | test("symbols forwarded from node_modules don't get suggested unless used", async () => { 23 | fileSystemProvider.createDocument(['{ "name": "test-module" }'], { 24 | languageId: "json", 25 | uri: "node_modules/sass-true/package.json", 26 | }); 27 | const module = fileSystemProvider.createDocument( 28 | ["$catch-errors: false !default;"], 29 | { 30 | uri: "node_modules/sass-true/_throw.scss", 31 | }, 32 | ); 33 | const forward = fileSystemProvider.createDocument(['@forward "sass-true";'], { 34 | uri: "_test.scss", 35 | }); 36 | const unrelated = fileSystemProvider.createDocument(["@debug $"]); 37 | 38 | ls.parseStylesheet(module); 39 | ls.parseStylesheet(forward); 40 | ls.parseStylesheet(unrelated); 41 | 42 | const { items } = await ls.doComplete(unrelated, Position.create(0, 8)); 43 | assert.notOk( 44 | items.find((item) => item.label === "$catch-errors"), 45 | "Expected not to find $catch-errors in suggestions", 46 | ); 47 | }); 48 | -------------------------------------------------------------------------------- /packages/language-services/src/features/__tests__/do-complete-placeholders.test.ts: -------------------------------------------------------------------------------- 1 | import { test, assert } from "vitest"; 2 | import { getLanguageService } from "../../language-services"; 3 | import { 4 | CompletionItemKind, 5 | InsertTextFormat, 6 | Position, 7 | } from "../../language-services-types"; 8 | import { getOptions } from "../../utils/test-helpers"; 9 | 10 | const { fileSystemProvider, ...rest } = getOptions(); 11 | const ls = getLanguageService({ fileSystemProvider, ...rest }); 12 | 13 | test("when declaring a placeholder selector, suggest placeholders that have an @extend usage", async () => { 14 | // https://github.com/wkillerud/some-sass/issues/49 15 | 16 | const one = fileSystemProvider.createDocument(".main { @extend %main; }", { 17 | uri: "one.scss", 18 | }); 19 | const two = fileSystemProvider.createDocument("%"); 20 | 21 | // emulate scanner of language service which adds workspace documents to the cache 22 | ls.parseStylesheet(one); 23 | ls.parseStylesheet(two); 24 | 25 | const { items } = await ls.doComplete(two, Position.create(0, 1)); 26 | assert.deepStrictEqual(items[0], { 27 | filterText: "main", 28 | insertTextFormat: InsertTextFormat.PlainText, 29 | kind: CompletionItemKind.Class, 30 | label: "%main", 31 | textEdit: { 32 | newText: "%main", 33 | range: { 34 | end: { 35 | character: 1, 36 | line: 0, 37 | }, 38 | start: { 39 | character: 0, 40 | line: 0, 41 | }, 42 | }, 43 | }, 44 | }); 45 | }); 46 | -------------------------------------------------------------------------------- /packages/language-services/src/features/__tests__/find-symbols-document-indented.test.ts: -------------------------------------------------------------------------------- 1 | import { test, assert, beforeEach } from "vitest"; 2 | import { getLanguageService } from "../../language-services"; 3 | import { SymbolKind, Range, Position } from "../../language-services-types"; 4 | import { getOptions } from "../../utils/test-helpers"; 5 | 6 | const { fileSystemProvider, ...rest } = getOptions(); 7 | const ls = getLanguageService({ fileSystemProvider, ...rest }); 8 | 9 | beforeEach(() => { 10 | ls.clearCache(); 11 | }); 12 | 13 | test("should return symbols", async () => { 14 | const document = fileSystemProvider.createDocument( 15 | `$name: "value" 16 | @mixin mixin($a: 1, $b) 17 | line-height: $a 18 | color: $b 19 | @function function($a: 1, $b) 20 | @return $a * $b 21 | %placeholder 22 | color: blue`, 23 | { 24 | languageId: "sass", 25 | }, 26 | ); 27 | 28 | const symbols = ls.findDocumentSymbols(document); 29 | const [variable, mixin, func, placeholder] = symbols; 30 | 31 | assert.deepStrictEqual(variable, { 32 | kind: SymbolKind.Variable, 33 | name: "$name", 34 | range: Range.create(Position.create(0, 0), Position.create(0, 14)), 35 | selectionRange: Range.create(Position.create(0, 0), Position.create(0, 5)), 36 | }); 37 | assert.deepStrictEqual(mixin, { 38 | kind: SymbolKind.Method, 39 | name: "mixin", 40 | detail: "($a: 1, $b)", 41 | range: Range.create(Position.create(1, 0), Position.create(4, 0)), 42 | selectionRange: Range.create(Position.create(1, 7), Position.create(1, 12)), 43 | }); 44 | assert.deepStrictEqual(func, { 45 | kind: SymbolKind.Function, 46 | name: "function", 47 | detail: "($a: 1, $b)", 48 | range: Range.create(Position.create(4, 0), Position.create(6, 0)), 49 | selectionRange: Range.create( 50 | Position.create(4, 10), 51 | Position.create(4, 18), 52 | ), 53 | }); 54 | assert.deepStrictEqual(placeholder, { 55 | kind: SymbolKind.Class, 56 | name: "%placeholder", 57 | range: Range.create(Position.create(6, 0), Position.create(7, 12)), 58 | selectionRange: Range.create(Position.create(6, 0), Position.create(6, 12)), 59 | }); 60 | }); 61 | -------------------------------------------------------------------------------- /packages/language-services/src/features/__tests__/find-symbols-workspace.test.ts: -------------------------------------------------------------------------------- 1 | import { test, assert, beforeEach } from "vitest"; 2 | import { getLanguageService } from "../../language-services"; 3 | import { getOptions } from "../../utils/test-helpers"; 4 | 5 | const { fileSystemProvider, ...rest } = getOptions(); 6 | const ls = getLanguageService({ fileSystemProvider, ...rest }); 7 | 8 | beforeEach(() => { 9 | ls.clearCache(); 10 | }); 11 | 12 | test("empty query returns all workspace symbols", async () => { 13 | const one = fileSystemProvider.createDocument( 14 | [ 15 | "$vone: 1;", 16 | "@mixin mone() { @content; }", 17 | "@function fone() { @return; }", 18 | ], 19 | { uri: "one.scss" }, 20 | ); 21 | const two = fileSystemProvider.createDocument( 22 | [ 23 | "$vone: 1;", 24 | "@mixin mone() { @content; }", 25 | "@function fone() { @return; }", 26 | ], 27 | { 28 | uri: "two.scss", 29 | }, 30 | ); 31 | 32 | // emulate scanner of language service which adds workspace documents to the cache 33 | ls.parseStylesheet(one); 34 | ls.parseStylesheet(two); 35 | 36 | const result = ls.findWorkspaceSymbols(""); 37 | 38 | assert.equal(result.length, 6); 39 | }); 40 | 41 | test("returns workspace symbols matching query", async () => { 42 | const one = fileSystemProvider.createDocument( 43 | [ 44 | "$vone: 1;", 45 | "@mixin mone() { @content; }", 46 | "@function fone() { @return; }", 47 | ], 48 | { uri: "one.scss" }, 49 | ); 50 | const two = fileSystemProvider.createDocument( 51 | [ 52 | "$vtwo: 1;", 53 | "@mixin mtwo() { @content; }", 54 | "@function ftwo() { @return; }", 55 | ], 56 | { 57 | uri: "two.scss", 58 | }, 59 | ); 60 | 61 | // emulate scanner of language service which adds workspace documents to the cache 62 | ls.parseStylesheet(one); 63 | ls.parseStylesheet(two); 64 | 65 | const result = ls.findWorkspaceSymbols("two"); 66 | 67 | assert.equal(result.length, 3); 68 | }); 69 | -------------------------------------------------------------------------------- /packages/language-services/src/features/find-document-highlights.ts: -------------------------------------------------------------------------------- 1 | import { LanguageFeature } from "../language-feature"; 2 | import { 3 | TextDocument, 4 | Position, 5 | DocumentHighlight, 6 | } from "../language-services-types"; 7 | 8 | export class FindDocumentHighlights extends LanguageFeature { 9 | findDocumentHighlights( 10 | document: TextDocument, 11 | position: Position, 12 | ): DocumentHighlight[] { 13 | const stylesheet = this.ls.parseStylesheet(document); 14 | return this.getUpstreamLanguageServer(document).findDocumentHighlights( 15 | document, 16 | position, 17 | stylesheet, 18 | ); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /packages/language-services/src/features/find-document-links.ts: -------------------------------------------------------------------------------- 1 | import { LanguageFeature } from "../language-feature"; 2 | import { 3 | TextDocument, 4 | StylesheetDocumentLink, 5 | URI, 6 | } from "../language-services-types"; 7 | 8 | export class FindDocumentLinks extends LanguageFeature { 9 | async findDocumentLinks( 10 | document: TextDocument, 11 | ): Promise { 12 | const cached = this.cache.getResolvedLinks(document); 13 | if (cached) return cached; 14 | 15 | const stylesheet = this.ls.parseStylesheet(document); 16 | const links = await this.getUpstreamLanguageServer( 17 | document, 18 | ).findDocumentLinks2(document, stylesheet, this.getDocumentContext()); 19 | 20 | for (const link of links) { 21 | if (link.target && !link.target.includes("sass:")) { 22 | // For monorepos, resolve the real path behind a symlink, since multiple links in `node_modules/` can point to the same file. 23 | // Take this initial performance hit to maximise cache hits and provide better results for projects using symlinks. 24 | const realpath = await this.options.fileSystemProvider.realPath( 25 | URI.parse(link.target), 26 | ); 27 | link.target = realpath.toString(); 28 | } 29 | } 30 | 31 | this.cache.putResolvedLinks(document, links); 32 | 33 | return links; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /packages/language-services/src/features/folding-ranges.ts: -------------------------------------------------------------------------------- 1 | import { LanguageFeature } from "../language-feature"; 2 | import { TextDocument, FoldingRange } from "../language-services-types"; 3 | 4 | export type FoldingRangeContext = { 5 | rangeLimit?: number; 6 | }; 7 | 8 | export class FoldingRanges extends LanguageFeature { 9 | async getFoldingRanges( 10 | document: TextDocument, 11 | context?: FoldingRangeContext, 12 | ): Promise { 13 | const result = this.getUpstreamLanguageServer(document).getFoldingRanges( 14 | document, 15 | context, 16 | ); 17 | return result; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /packages/language-services/src/features/selection-ranges.ts: -------------------------------------------------------------------------------- 1 | import { LanguageFeature } from "../language-feature"; 2 | import { 3 | TextDocument, 4 | SelectionRange, 5 | Position, 6 | } from "../language-services-types"; 7 | 8 | export class SelectionRanges extends LanguageFeature { 9 | async getSelectionRanges( 10 | document: TextDocument, 11 | positions: Position[], 12 | ): Promise { 13 | const stylesheet = this.ls.parseStylesheet(document); 14 | const result = this.getUpstreamLanguageServer(document).getSelectionRanges( 15 | document, 16 | positions, 17 | stylesheet, 18 | ); 19 | return result; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /packages/language-services/src/utils/fs-provider.ts: -------------------------------------------------------------------------------- 1 | import type { FileSystemProvider as CSSFileSystemProvider } from "@somesass/vscode-css-languageservice"; 2 | import { FileType, FileSystemProvider, URI } from "../language-services-types"; 3 | 4 | export function mapFsProviders( 5 | ours: FileSystemProvider, 6 | ): CSSFileSystemProvider { 7 | const theirs: CSSFileSystemProvider = { 8 | async stat(uri: string) { 9 | try { 10 | const result = await ours.stat(URI.parse(uri)); 11 | return result; 12 | } catch (error) { 13 | if ((error as NodeJS.ErrnoException).code !== "ENOENT") { 14 | throw error; 15 | } 16 | return { 17 | type: FileType.Unknown, 18 | ctime: -1, 19 | mtime: -1, 20 | size: -1, 21 | }; 22 | } 23 | }, 24 | async readDirectory(uri: string) { 25 | const dir = await ours.readDirectory(URI.parse(uri)); 26 | const result: [string, FileType][] = dir.map(([uri, info]) => [ 27 | uri, 28 | info, 29 | ]); 30 | return result; 31 | }, 32 | getContent(uri, encoding) { 33 | return ours.readFile(URI.parse(uri), encoding); 34 | }, 35 | }; 36 | return theirs; 37 | } 38 | -------------------------------------------------------------------------------- /packages/language-services/src/utils/sass.ts: -------------------------------------------------------------------------------- 1 | /** Strips the dollar prefix off a variable name */ 2 | export function asDollarlessVariable(variable: string): string { 3 | return variable.replace(/^\$/, ""); 4 | } 5 | -------------------------------------------------------------------------------- /packages/language-services/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2020", 4 | "lib": ["ES2020", "WebWorker"], 5 | "sourceMap": true, 6 | "module": "commonjs", 7 | "moduleResolution": "node", 8 | "declaration": true, 9 | "rootDir": "src", 10 | "esModuleInterop": true, 11 | "outDir": "dist", 12 | "strict": true 13 | }, 14 | "include": ["src/**/*.ts"], 15 | "exclude": ["src/**/*.test.ts"] 16 | } 17 | -------------------------------------------------------------------------------- /packages/language-services/vitest.config.mts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vitest/config"; 2 | 3 | export default defineConfig({ 4 | test: { 5 | coverage: { 6 | provider: "v8", 7 | reporter: ["text", "json", "html"], 8 | }, 9 | }, 10 | }); 11 | -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "parser": "@typescript-eslint/parser", 4 | "parserOptions": { 5 | "ecmaVersion": 6, 6 | "sourceType": "module" 7 | }, 8 | "plugins": ["@typescript-eslint"], 9 | "rules": { 10 | "@typescript-eslint/ban-types": "off", 11 | "@typescript-eslint/naming-convention": [ 12 | "warn", 13 | { 14 | "selector": "typeLike", 15 | "format": ["PascalCase"] 16 | } 17 | ], 18 | "@typescript-eslint/semi": "warn", 19 | "curly": "warn", 20 | "eqeqeq": "warn", 21 | "no-throw-literal": "warn", 22 | "semi": "off", 23 | "no-unused-expressions": "warn", 24 | "no-duplicate-imports": "warn", 25 | "new-parens": "warn" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/.gitignore: -------------------------------------------------------------------------------- 1 | lib/ 2 | node_modules/ 3 | coverage/ 4 | .nyc_output/ 5 | npm-debug.log -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "useTabs": true, 3 | "printWidth": 120, 4 | "semi": true 5 | } 6 | -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) Microsoft 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/README.md: -------------------------------------------------------------------------------- 1 | # @somesass/vscode-css-languageservice 2 | 3 | This is a private fork of vscode-css-languageservice with additions to support the language features in [language-services](../language-services/). 4 | 5 | ## Changes from upstream 6 | 7 | These changes should be kept whenever we merge in changes from upstream. Cross off what is sent upstream. 8 | 9 | - [ ] findDocumentLinks extension with use and forward metadata (for most language features). 10 | - [ ] `StylesheetDocumentLink` type. 11 | - [ ] Additions in `_parseUse` in `scssParser.ts` surrouding `this.acceptIdent("as")`. 12 | - [ ] Push `sass:` links as resolved in `findDocumentLinks` and `findDocumentLinks2` in `cssNavigation.ts` (we use them for completions). 13 | - [ ] Additions for `as`, `hide`, `show` and `type` in `findUnresolvedLinks` in `cssNavigation.ts`. 14 | - [x] `pkg:` imports. 15 | - [ ] Placeholder selectors and usages in symbols (for completions, navigation). 16 | - [ ] `_parseExtends` in `scssParser.ts`. 17 | - [ ] `collectDocumentSymbols` in `cssNavigation.ts` surrounding `NodeType.SelectorPlaceholder`. 18 | - [ ] Mixin reference node for namespaced mixins in `_parseMixinReference` in `scssParser.ts` (for completions). 19 | - [ ] Details with parameters for functions and mixins for signature helper in `findDocumentSymbols` in `cssNavigation.ts` (for signature helpers). 20 | -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/build/generateData.js: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | *--------------------------------------------------------------------------------------------*/ 5 | 6 | const fs = require('fs') 7 | const path = require('path') 8 | const os = require('os') 9 | 10 | const customData = require('@vscode/web-custom-data/data/browsers.css-data.json'); 11 | 12 | function toJavaScript(obj) { 13 | return JSON.stringify(obj, null, '\t'); 14 | } 15 | 16 | const DATA_TYPE = 'CSSDataV1'; 17 | const output = [ 18 | '/*---------------------------------------------------------------------------------------------', 19 | ' * Copyright (c) Microsoft Corporation. All rights reserved.', 20 | ' * Licensed under the MIT License. See License.txt in the project root for license information.', 21 | ' *--------------------------------------------------------------------------------------------*/', 22 | '// file generated from @vscode/web-custom-data NPM package', 23 | '', 24 | `import { ${DATA_TYPE} } from '../cssLanguageTypes';`, 25 | '', 26 | `export const cssData : ${DATA_TYPE} = ` + toJavaScript(customData) + ';' 27 | ]; 28 | 29 | var outputPath = path.resolve(__dirname, '../src/data/webCustomData.ts'); 30 | console.log('Writing to: ' + outputPath); 31 | var content = output.join(os.EOL); 32 | fs.writeFileSync(outputPath, content); 33 | console.log('Done'); 34 | -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/build/remove-sourcemap-refs.js: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | *--------------------------------------------------------------------------------------------*/ 5 | 6 | const fs = require('fs'); 7 | const path = require('path'); 8 | 9 | function deleteRefs(dir) { 10 | const files = fs.readdirSync(dir); 11 | for (let file of files) { 12 | const filePath = path.join(dir, file); 13 | const stat = fs.statSync(filePath); 14 | if (stat.isDirectory()) { 15 | deleteRefs(filePath); 16 | } else if (path.extname(file) === '.js') { 17 | const content = fs.readFileSync(filePath, 'utf8'); 18 | const newContent = content.replace(/\/\/\# sourceMappingURL=[^]+.js.map/, '') 19 | if (content.length !== newContent.length) { 20 | console.log('remove sourceMappingURL in ' + filePath); 21 | fs.writeFileSync(filePath, newContent); 22 | } 23 | } else if (path.extname(file) === '.map') { 24 | fs.unlinkSync(filePath) 25 | console.log('remove ' + filePath); 26 | } 27 | } 28 | } 29 | 30 | let location = path.join(__dirname, '..', 'lib'); 31 | console.log('process ' + location); 32 | deleteRefs(location); -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@somesass/vscode-css-languageservice", 3 | "version": "2.1.0", 4 | "private": true, 5 | "description": "Language service for CSS, LESS and SCSS", 6 | "main": "./lib/umd/cssLanguageService.js", 7 | "typings": "./lib/umd/cssLanguageService", 8 | "module": "./lib/esm/cssLanguageService.js", 9 | "author": "Microsoft Corporation", 10 | "repository": { 11 | "type": "git", 12 | "url": "https://github.com/wkillerud/some-sass" 13 | }, 14 | "license": "MIT", 15 | "bugs": { 16 | "url": "https://github.com/wkillerud/some-sass" 17 | }, 18 | "devDependencies": { 19 | "@types/node": "22.15.3", 20 | "@vscode/web-custom-data": "0.5.2", 21 | "rimraf": "6.0.1", 22 | "source-map-support": "0.5.21", 23 | "typescript": "5.8.3" 24 | }, 25 | "dependencies": { 26 | "@vscode/l10n": "0.0.18", 27 | "vscode-languageserver-textdocument": "1.0.12", 28 | "vscode-languageserver-types": "3.17.5", 29 | "vscode-uri": "3.1.0" 30 | }, 31 | "scripts": { 32 | "build": "run-s compile compile-esm", 33 | "build:production": "npm run build", 34 | "compile": "tsc -p ./src/tsconfig.json", 35 | "compile-esm": "tsc -p ./src/tsconfig.esm.json", 36 | "clean": "rimraf lib node_modules", 37 | "watch": "tsc -w -p ./src", 38 | "test": "vitest", 39 | "coverage": "vitest run --coverage", 40 | "lint": "eslint src/**/*.ts", 41 | "preupdate-data": "npm install @vscode/web-custom-data -D", 42 | "update-data": "node ./build/generateData.js" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/src/languageFacts/facts.ts: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | *--------------------------------------------------------------------------------------------*/ 5 | "use strict"; 6 | 7 | export * from "./entry"; 8 | export * from "./colors"; 9 | export * from "./builtinData"; 10 | -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/src/parser/sassErrors.ts: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | *--------------------------------------------------------------------------------------------*/ 5 | "use strict"; 6 | 7 | import * as nodes from "./cssNodes"; 8 | 9 | import * as l10n from "@vscode/l10n"; 10 | 11 | export class SassIssueType implements nodes.IRule { 12 | id: string; 13 | message: string; 14 | 15 | public constructor(id: string, message: string) { 16 | this.id = id; 17 | this.message = message; 18 | } 19 | } 20 | 21 | export const SassParseError = { 22 | FromExpected: new SassIssueType("scss-fromexpected", l10n.t("'from' expected")), 23 | ThroughOrToExpected: new SassIssueType("scss-throughexpected", l10n.t("'through' or 'to' expected")), 24 | InExpected: new SassIssueType("scss-fromexpected", l10n.t("'in' expected")), 25 | }; 26 | -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/src/test/sass/linkFixture/both/_bar.sass: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/packages/vscode-css-languageservice/src/test/sass/linkFixture/both/_bar.sass -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/src/test/sass/linkFixture/both/_foo.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/packages/vscode-css-languageservice/src/test/sass/linkFixture/both/_foo.scss -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/src/test/sass/linkFixture/both/bar.sass: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/packages/vscode-css-languageservice/src/test/sass/linkFixture/both/bar.sass -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/src/test/sass/linkFixture/both/foo.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/packages/vscode-css-languageservice/src/test/sass/linkFixture/both/foo.scss -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/src/test/sass/linkFixture/both/nested/bar.sass: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/packages/vscode-css-languageservice/src/test/sass/linkFixture/both/nested/bar.sass -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/src/test/sass/linkFixture/indented-index/bar/_index.sass: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/packages/vscode-css-languageservice/src/test/sass/linkFixture/indented-index/bar/_index.sass -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/src/test/sass/linkFixture/indented-index/foo/index.sass: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/packages/vscode-css-languageservice/src/test/sass/linkFixture/indented-index/foo/index.sass -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/src/test/sass/linkFixture/index/bar/_index.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/packages/vscode-css-languageservice/src/test/sass/linkFixture/index/bar/_index.scss -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/src/test/sass/linkFixture/index/foo/index.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/packages/vscode-css-languageservice/src/test/sass/linkFixture/index/foo/index.scss -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/src/test/sass/linkFixture/loadPaths/shared/my-lib/variables.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/packages/vscode-css-languageservice/src/test/sass/linkFixture/loadPaths/shared/my-lib/variables.scss -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/src/test/sass/linkFixture/loadPaths/src/styles.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/packages/vscode-css-languageservice/src/test/sass/linkFixture/loadPaths/src/styles.scss -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/src/test/sass/linkFixture/module/bar.sass: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/packages/vscode-css-languageservice/src/test/sass/linkFixture/module/bar.sass -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/src/test/sass/linkFixture/module/foo.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/packages/vscode-css-languageservice/src/test/sass/linkFixture/module/foo.scss -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/src/test/sass/linkFixture/noUnderscore/bar.sass: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/packages/vscode-css-languageservice/src/test/sass/linkFixture/noUnderscore/bar.sass -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/src/test/sass/linkFixture/noUnderscore/foo.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/packages/vscode-css-languageservice/src/test/sass/linkFixture/noUnderscore/foo.scss -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/src/test/sass/linkFixture/underscore/_bar.sass: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/packages/vscode-css-languageservice/src/test/sass/linkFixture/underscore/_bar.sass -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/src/test/sass/linkFixture/underscore/_foo.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/packages/vscode-css-languageservice/src/test/sass/linkFixture/underscore/_foo.scss -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/src/test/sass/parserSmoketest.test.ts: -------------------------------------------------------------------------------- 1 | import fs from "node:fs/promises"; 2 | import path from "node:path"; 3 | import { test } from "vitest"; 4 | import { SassParser } from "../../parser/sassParser"; 5 | import { assertNode } from "../css/parser.test"; 6 | 7 | test("SCSS parser handles example stylesheet", async () => { 8 | const parser = new SassParser({ syntax: "scss" }); 9 | const stylesheet = await fs.readFile(path.join(__dirname, "example.scss"), "utf-8"); 10 | assertNode(stylesheet, parser, parser._parseStylesheet.bind(parser)); 11 | }); 12 | 13 | test("Indented parser handles example stylesheet", async () => { 14 | const parser = new SassParser({ syntax: "indented" }); 15 | const stylesheet = await fs.readFile(path.join(__dirname, "example.sass"), "utf-8"); 16 | assertNode(stylesheet, parser, parser._parseStylesheet.bind(parser)); 17 | }); 18 | -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/src/test/sass/sassCompletionIndented.test.ts: -------------------------------------------------------------------------------- 1 | import { suite, test } from "vitest"; 2 | 3 | import { LanguageSettings } from "../../cssLanguageService"; 4 | import { testCompletionFor as testCSSCompletionFor, ExpectedCompetions } from "../css/completion.test"; 5 | 6 | function testCompletionFor( 7 | value: string, 8 | expected: ExpectedCompetions, 9 | settings: LanguageSettings | undefined = undefined, 10 | testUri: string = "test://test/test.sass", 11 | workspaceFolderUri: string = "test://test", 12 | ) { 13 | return testCSSCompletionFor(value, expected, settings, testUri, workspaceFolderUri); 14 | } 15 | 16 | suite("Sass indented - Completions", () => { 17 | test("declarations suggest properties as expected", async () => { 18 | await testCompletionFor( 19 | `.foo 20 | color: red 21 | |`, 22 | 23 | { 24 | items: [ 25 | { 26 | label: "position", 27 | resultText: `.foo 28 | color: red 29 | position: `, 30 | }, 31 | { 32 | label: "display", 33 | resultText: `.foo 34 | color: red 35 | display: `, 36 | }, 37 | ], 38 | }, 39 | ); 40 | }); 41 | }); 42 | -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/src/test/testUtil/documentContext.ts: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | *--------------------------------------------------------------------------------------------*/ 5 | 6 | import * as url from "url"; 7 | 8 | import { DocumentContext } from "../../cssLanguageTypes"; 9 | import { startsWith } from "../../utils/strings"; 10 | import { joinPath } from "../../utils/resources"; 11 | 12 | export function getDocumentContext(workspaceFolder?: string): DocumentContext { 13 | return { 14 | resolveReference: (ref, base) => { 15 | if (startsWith(ref, "/") && workspaceFolder) { 16 | return joinPath(workspaceFolder, ref); 17 | } 18 | try { 19 | return url.resolve(base, ref); 20 | } catch { 21 | return undefined; 22 | } 23 | }, 24 | }; 25 | } 26 | -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/src/tsconfig.esm.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2020", 4 | "module": "es6", 5 | "moduleResolution": "node", 6 | "sourceMap": true, 7 | "inlineSourceMap": false, 8 | "declaration": true, 9 | "strict": true, 10 | "stripInternal": true, 11 | "outDir": "../lib/esm", 12 | "lib": ["es2020"] 13 | }, 14 | "exclude": ["./test/"] 15 | } 16 | -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/src/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2020", 4 | "module": "umd", 5 | "moduleResolution": "node", 6 | "sourceMap": true, 7 | "inlineSourceMap": false, 8 | "declaration": true, 9 | "strict": true, 10 | "stripInternal": true, 11 | "outDir": "../lib/umd", 12 | "lib": ["es2020"] 13 | }, 14 | "exclude": ["./test/"] 15 | } 16 | -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/src/utils/arrays.ts: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | *--------------------------------------------------------------------------------------------*/ 5 | "use strict"; 6 | 7 | /** 8 | * Takes a sorted array and a function p. The array is sorted in such a way that all elements where p(x) is false 9 | * are located before all elements where p(x) is true. 10 | * @returns the least x for which p(x) is true or array.length if no element fullfills the given function. 11 | */ 12 | export function findFirst(array: T[], p: (x: T) => boolean): number { 13 | let low = 0, 14 | high = array.length; 15 | if (high === 0) { 16 | return 0; // no children 17 | } 18 | while (low < high) { 19 | let mid = Math.floor((low + high) / 2); 20 | if (p(array[mid])) { 21 | high = mid; 22 | } else { 23 | low = mid + 1; 24 | } 25 | } 26 | return low; 27 | } 28 | 29 | export function includes(array: T[], item: T): boolean { 30 | return array.indexOf(item) !== -1; 31 | } 32 | 33 | export function union(...arrays: T[][]): T[] { 34 | const result: T[] = []; 35 | for (const array of arrays) { 36 | for (const item of array) { 37 | if (!includes(result, item)) { 38 | result.push(item); 39 | } 40 | } 41 | } 42 | return result; 43 | } 44 | -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/src/utils/objects.ts: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | *--------------------------------------------------------------------------------------------*/ 5 | "use strict"; 6 | 7 | export function values(obj: { [s: string]: T }): T[] { 8 | return Object.keys(obj).map((key) => obj[key]); 9 | } 10 | 11 | export function isDefined(obj: T | undefined): obj is T { 12 | return typeof obj !== "undefined"; 13 | } 14 | -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/src/utils/resources.ts: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | *--------------------------------------------------------------------------------------------*/ 5 | 6 | import { URI, Utils } from "vscode-uri"; 7 | 8 | export function dirname(uriString: string): string { 9 | return Utils.dirname(URI.parse(uriString)).toString(true); 10 | } 11 | 12 | export function joinPath(uriString: string, ...paths: string[]): string { 13 | return Utils.joinPath(URI.parse(uriString), ...paths).toString(true); 14 | } 15 | -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/test/linksTestFixtures/.gitignore: -------------------------------------------------------------------------------- 1 | !/node_modules -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/test/linksTestFixtures/a.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/packages/vscode-css-languageservice/test/linksTestFixtures/a.css -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/test/linksTestFixtures/green/c.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/packages/vscode-css-languageservice/test/linksTestFixtures/green/c.css -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/test/linksTestFixtures/green/d.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/packages/vscode-css-languageservice/test/linksTestFixtures/green/d.scss -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/test/linksTestFixtures/node_modules/@foo/bar/_baz.scss: -------------------------------------------------------------------------------- 1 | $radius: 3px; -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/test/linksTestFixtures/node_modules/@foo/bar/_index.scss: -------------------------------------------------------------------------------- 1 | $radius: 3px; -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/test/linksTestFixtures/node_modules/@foo/bar/package.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/test/linksTestFixtures/node_modules/@foo/baz/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "exports": { 3 | ".": { 4 | "sass": "./styles/index.scss" 5 | }, 6 | "./colors.scss": { 7 | "sass": "./styles/colors.scss" 8 | }, 9 | "./button": { 10 | "sass": "./styles/button.scss" 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/test/linksTestFixtures/node_modules/@foo/foo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "exports": { 3 | ".": { 4 | "sass": "./styles/index.sass" 5 | }, 6 | "./colors.sass": { 7 | "sass": "./styles/colors.sass" 8 | }, 9 | "./button": { 10 | "sass": "./styles/button.sass" 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/test/linksTestFixtures/node_modules/bar-indented/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "exports": { 3 | ".": { 4 | "sass": "./styles/index.sass" 5 | }, 6 | "./colors.sass": { 7 | "sass": "./styles/colors.sass" 8 | }, 9 | "./button": { 10 | "sass": "./styles/button.sass" 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/test/linksTestFixtures/node_modules/bar-indented/styles/button.sass: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/packages/vscode-css-languageservice/test/linksTestFixtures/node_modules/bar-indented/styles/button.sass -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/test/linksTestFixtures/node_modules/bar-indented/styles/colors.sass: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/packages/vscode-css-languageservice/test/linksTestFixtures/node_modules/bar-indented/styles/colors.sass -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/test/linksTestFixtures/node_modules/bar-indented/styles/index.sass: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/packages/vscode-css-languageservice/test/linksTestFixtures/node_modules/bar-indented/styles/index.sass -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/test/linksTestFixtures/node_modules/bar-pattern-indented/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "exports": { 3 | ".": { 4 | "sass": "./styles/index.sass" 5 | }, 6 | "./*.sass": { 7 | "sass": "./styles/*.sass" 8 | }, 9 | "./theme/*": { 10 | "sass": "./styles/theme/*.sass" 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/test/linksTestFixtures/node_modules/bar-pattern-indented/styles/button.sass: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/packages/vscode-css-languageservice/test/linksTestFixtures/node_modules/bar-pattern-indented/styles/button.sass -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/test/linksTestFixtures/node_modules/bar-pattern-indented/styles/colors.sass: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/packages/vscode-css-languageservice/test/linksTestFixtures/node_modules/bar-pattern-indented/styles/colors.sass -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/test/linksTestFixtures/node_modules/bar-pattern-indented/styles/index.sass: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/packages/vscode-css-languageservice/test/linksTestFixtures/node_modules/bar-pattern-indented/styles/index.sass -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/test/linksTestFixtures/node_modules/bar-pattern-indented/styles/theme/button.sass: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/packages/vscode-css-languageservice/test/linksTestFixtures/node_modules/bar-pattern-indented/styles/theme/button.sass -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/test/linksTestFixtures/node_modules/bar-pattern-indented/styles/theme/colors.sass: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/packages/vscode-css-languageservice/test/linksTestFixtures/node_modules/bar-pattern-indented/styles/theme/colors.sass -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/test/linksTestFixtures/node_modules/bar-pattern-indented/styles/theme/index.sass: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/packages/vscode-css-languageservice/test/linksTestFixtures/node_modules/bar-pattern-indented/styles/theme/index.sass -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/test/linksTestFixtures/node_modules/bar-pattern/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "exports": { 3 | ".": { 4 | "sass": "./styles/index.scss" 5 | }, 6 | "./*.scss": { 7 | "sass": "./styles/*.scss" 8 | }, 9 | "./theme/*": { 10 | "sass": "./styles/theme/*.scss" 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/test/linksTestFixtures/node_modules/bar-pattern/styles/button.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/packages/vscode-css-languageservice/test/linksTestFixtures/node_modules/bar-pattern/styles/button.scss -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/test/linksTestFixtures/node_modules/bar-pattern/styles/colors.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/packages/vscode-css-languageservice/test/linksTestFixtures/node_modules/bar-pattern/styles/colors.scss -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/test/linksTestFixtures/node_modules/bar-pattern/styles/index.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/packages/vscode-css-languageservice/test/linksTestFixtures/node_modules/bar-pattern/styles/index.scss -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/test/linksTestFixtures/node_modules/bar-pattern/styles/theme/button.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/packages/vscode-css-languageservice/test/linksTestFixtures/node_modules/bar-pattern/styles/theme/button.scss -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/test/linksTestFixtures/node_modules/bar-pattern/styles/theme/colors.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/packages/vscode-css-languageservice/test/linksTestFixtures/node_modules/bar-pattern/styles/theme/colors.scss -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/test/linksTestFixtures/node_modules/bar-pattern/styles/theme/index.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/packages/vscode-css-languageservice/test/linksTestFixtures/node_modules/bar-pattern/styles/theme/index.scss -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/test/linksTestFixtures/node_modules/bar/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "exports": { 3 | ".": { 4 | "sass": "./styles/index.scss" 5 | }, 6 | "./colors.scss": { 7 | "sass": "./styles/colors.scss" 8 | }, 9 | "./button": { 10 | "sass": "./styles/button.scss" 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/test/linksTestFixtures/node_modules/bar/styles/button.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/packages/vscode-css-languageservice/test/linksTestFixtures/node_modules/bar/styles/button.scss -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/test/linksTestFixtures/node_modules/bar/styles/colors.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/packages/vscode-css-languageservice/test/linksTestFixtures/node_modules/bar/styles/colors.scss -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/test/linksTestFixtures/node_modules/bar/styles/index.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/packages/vscode-css-languageservice/test/linksTestFixtures/node_modules/bar/styles/index.scss -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/test/linksTestFixtures/node_modules/foo/package.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/test/linksTestFixtures/node_modules/green/_e.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/packages/vscode-css-languageservice/test/linksTestFixtures/node_modules/green/_e.scss -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/test/linksTestFixtures/node_modules/green/c.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/packages/vscode-css-languageservice/test/linksTestFixtures/node_modules/green/c.css -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/test/linksTestFixtures/node_modules/green/d.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/packages/vscode-css-languageservice/test/linksTestFixtures/node_modules/green/d.scss -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/test/linksTestFixtures/node_modules/green/package.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/test/linksTestFixtures/node_modules/root-indented/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "sass": "./styles/index.sass" 3 | } 4 | -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/test/linksTestFixtures/node_modules/root-indented/styles/index.sass: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/packages/vscode-css-languageservice/test/linksTestFixtures/node_modules/root-indented/styles/index.sass -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/test/linksTestFixtures/node_modules/root-sass/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "sass": "./styles/index.scss" 3 | } 4 | -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/test/linksTestFixtures/node_modules/root-sass/styles/index.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/packages/vscode-css-languageservice/test/linksTestFixtures/node_modules/root-sass/styles/index.scss -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/test/linksTestFixtures/node_modules/root-style-indented/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "style": "./styles/index.sass" 3 | } 4 | -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/test/linksTestFixtures/node_modules/root-style-indented/styles/index.sass: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/packages/vscode-css-languageservice/test/linksTestFixtures/node_modules/root-style-indented/styles/index.sass -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/test/linksTestFixtures/node_modules/root-style/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "style": "./styles/index.scss" 3 | } 4 | -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/test/linksTestFixtures/node_modules/root-style/styles/index.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/packages/vscode-css-languageservice/test/linksTestFixtures/node_modules/root-style/styles/index.scss -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/test/linksTestFixtures/node_modules/sass-true/_index.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/packages/vscode-css-languageservice/test/linksTestFixtures/node_modules/sass-true/_index.scss -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/test/linksTestFixtures/node_modules/sass-true/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sass-true", 3 | "title": "True", 4 | "description": "Unit testing for Sass.", 5 | "files": [ 6 | "lib/**/*", 7 | "sass/**/*", 8 | "_index.scss", 9 | "CHANGELOG.md", 10 | "LICENSE.txt", 11 | "README.md" 12 | ], 13 | "main": "./lib/index.js", 14 | "exports": { 15 | "types": "./lib/index.d.ts", 16 | "sass": "./_index.scss", 17 | "default": "./lib/index.js" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/test/linksTestFixtures/node_modules/sass/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "exports": { 3 | ".": { 4 | "sass": "./styles/index.sass" 5 | }, 6 | "./colors.sass": { 7 | "sass": "./styles/colors.sass" 8 | }, 9 | "./button": { 10 | "sass": "./styles/button.sass" 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/test/linksTestFixtures/node_modules/sass/styles/button.sass: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/packages/vscode-css-languageservice/test/linksTestFixtures/node_modules/sass/styles/button.sass -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/test/linksTestFixtures/node_modules/sass/styles/colors.sass: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/packages/vscode-css-languageservice/test/linksTestFixtures/node_modules/sass/styles/colors.sass -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/test/linksTestFixtures/node_modules/sass/styles/index.sass: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/packages/vscode-css-languageservice/test/linksTestFixtures/node_modules/sass/styles/index.sass -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/test/pathCompletionFixtures/.foo.js: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | *--------------------------------------------------------------------------------------------*/ -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/test/pathCompletionFixtures/about/about.css: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | *--------------------------------------------------------------------------------------------*/ -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/test/pathCompletionFixtures/about/about.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/packages/vscode-css-languageservice/test/pathCompletionFixtures/about/about.html -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/test/pathCompletionFixtures/index.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/packages/vscode-css-languageservice/test/pathCompletionFixtures/index.html -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/test/pathCompletionFixtures/sass/_foo.sass: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/packages/vscode-css-languageservice/test/pathCompletionFixtures/sass/_foo.sass -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/test/pathCompletionFixtures/sass/main.sass: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/packages/vscode-css-languageservice/test/pathCompletionFixtures/sass/main.sass -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/test/pathCompletionFixtures/scss/_foo.scss: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | *--------------------------------------------------------------------------------------------*/ -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/test/pathCompletionFixtures/scss/main.scss: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | *--------------------------------------------------------------------------------------------*/ -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/test/pathCompletionFixtures/src/data/foo.asar: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | *--------------------------------------------------------------------------------------------*/ -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/test/pathCompletionFixtures/src/feature.js: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | *--------------------------------------------------------------------------------------------*/ -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/test/pathCompletionFixtures/src/test.js: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | *--------------------------------------------------------------------------------------------*/ -------------------------------------------------------------------------------- /packages/vscode-css-languageservice/vitest.config.mts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vitest/config"; 2 | 3 | export default defineConfig({ 4 | test: { 5 | exclude: ["lib/**"], 6 | isolate: false, 7 | coverage: { 8 | provider: "v8", 9 | reporter: ["text", "json", "html"], 10 | include: ["src/"], 11 | exclude: ["src/test/"], 12 | }, 13 | }, 14 | }); 15 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": ["config:recommended"], 4 | "schedule": ["on the first day of the month"], 5 | "dependencyDashboard": false, 6 | "ignoreDeps": ["@types/vscode"], 7 | "packageRules": [ 8 | { 9 | "groupName": "devDependencies (non-major)", 10 | "matchDepTypes": ["devDependencies"], 11 | "matchUpdateTypes": ["minor", "patch"], 12 | "matchCurrentVersion": "!/^0/", 13 | "automerge": true 14 | }, 15 | { 16 | "groupName": "devDependencies (major)", 17 | "matchDepTypes": ["devDependencies"], 18 | "matchUpdateTypes": ["major"], 19 | "matchCurrentVersion": "!/^0/", 20 | "automerge": true 21 | }, 22 | { 23 | "groupName": "language client and server", 24 | "matchDepTypes": ["dependencies"], 25 | "matchPackagePatterns": ["vscode-language", "vscode-css-languageservice"], 26 | "automerge": false 27 | }, 28 | { 29 | "groupName": "dependencies (non-major)", 30 | "excludePackagePatterns": [ 31 | "vscode-language", 32 | "vscode-css-languageservice" 33 | ], 34 | "matchDepTypes": ["dependencies"], 35 | "matchUpdateTypes": ["minor", "patch"], 36 | "matchCurrentVersion": "!/^0/", 37 | "automerge": true 38 | }, 39 | { 40 | "groupName": "dependencies (major)", 41 | "excludePackagePatterns": [ 42 | "vscode-language", 43 | "vscode-css-languageservice" 44 | ], 45 | "matchDepTypes": ["dependencies"], 46 | "matchUpdateTypes": ["major"], 47 | "matchCurrentVersion": "!/^0/", 48 | "automerge": false 49 | } 50 | ], 51 | "automergeType": "branch" 52 | } 53 | -------------------------------------------------------------------------------- /tsconfig.base.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "rootDir": ".", 5 | "sourceMap": true, 6 | "declaration": false, 7 | "moduleResolution": "node", 8 | "emitDecoratorMetadata": true, 9 | "experimentalDecorators": true, 10 | "importHelpers": true, 11 | "target": "es2015", 12 | "module": "esnext", 13 | "lib": ["es2020", "dom"], 14 | "skipLibCheck": true, 15 | "skipDefaultLibCheck": true, 16 | "baseUrl": ".", 17 | "paths": {} 18 | }, 19 | "exclude": ["node_modules", "tmp"] 20 | } 21 | -------------------------------------------------------------------------------- /vscode-extension/.vscodeignore: -------------------------------------------------------------------------------- 1 | CONTRIBUTING.md 2 | .DS_Store 3 | 4 | # Logs 5 | logs/ 6 | *.log 7 | npm-debug.log* 8 | 9 | # Configuration 10 | .eslintrc.json 11 | tsconfig.json 12 | *.config.js 13 | *.config.cjs 14 | *.config.mjs 15 | 16 | # Dependencies 17 | node_modules/** 18 | # npm workspace links 19 | ../** 20 | 21 | # Source and test files 22 | .vscode-test/ 23 | .vscode-test-web/ 24 | .nyc_output/ 25 | coverage/ 26 | test/ 27 | types/ 28 | **/*.ts 29 | **/*.map 30 | 31 | # Build artifacts 32 | out/ 33 | *.vsix 34 | -------------------------------------------------------------------------------- /vscode-extension/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 3.1.4 (2024-05-01) 2 | 3 | 4 | ### 🩹 Fixes 5 | 6 | - update vscode-css-languageservice to 6.2.14 7 | 8 | Visit the [release section on GitHub](https://github.com/wkillerud/some-sass/releases) to see what has changed between versions. 9 | -------------------------------------------------------------------------------- /vscode-extension/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/vscode-extension/icon.png -------------------------------------------------------------------------------- /vscode-extension/languages/README.md: -------------------------------------------------------------------------------- 1 | # Syntaxes 2 | 3 | See [Syntax highlighting guide](https://code.visualstudio.com/api/language-extensions/syntax-highlight-guide) 4 | for some good background information before you dive into the TextMate grammar. 5 | 6 | The grammar works on one line at a time. 7 | For an indentation based language like Sass this means we need to use 8 | signals other than newline to figure out "where we are". 9 | 10 | You might want the 11 | [documentation for the Regular Expression syntax](https://macromates.com/manual/en/regular_expressions#syntax_oniguruma) 12 | used in the grammars. 13 | 14 | `sass.tmLanguage.json` is an adaptation of the [grammar for SCSS](https://github.com/microsoft/vscode/blob/main/extensions/scss/syntaxes/scss.tmLanguage.json). 15 | The SCSS grammar can be a useful reference when working with the Sass grammar. 16 | 17 | If a matching pattern isn't behaving the way you expect, test it and the code you expect to match in https://rubular.com. 18 | Remember to remove double slashes. For example: 19 | 20 | - This pattern in JSON `(?<=@include)\\s+(?:([\\w-]+)\\s*(\\.))?([\\w-]+)` 21 | - Should be `(?<=@include)\s+(?:([\w-]+)\s*(\.))?([\w-]+)` on Rubular. 22 | 23 | ## Word pattern 24 | 25 | This is one long regular expression composed of multiple separated by `|`. 26 | Together they define [what is considered a word](https://code.visualstudio.com/api/language-extensions/language-configuration-guide#word-pattern) in Sass. 27 | 28 | The first is `(#?-?\\d*\\.?\\d\\w*%?)`. This matches various different ways of declaring numerical values with or without units. 29 | 30 | The second is `(::?[\\w-]*(?=[^,]*[,]))`. This matches various CSS pseudo-selectors. 31 | 32 | The third is `(([@$#.!])?[\\w-?]+%?)`. This matches different at-rules, variables, properties and keywords. 33 | -------------------------------------------------------------------------------- /vscode-extension/languages/sass.configuration.json: -------------------------------------------------------------------------------- 1 | { 2 | "comments": { 3 | "lineComment": "//", 4 | "blockComment": ["/*", "*/"] 5 | }, 6 | "brackets": [ 7 | ["{", "}"], 8 | ["[", "]"], 9 | ["(", ")"] 10 | ], 11 | "autoClosingPairs": [ 12 | ["{", "}"], 13 | ["[", "]"], 14 | ["(", ")"], 15 | ["\"", "\""], 16 | ["'", "'"] 17 | ], 18 | "surroundingPairs": [ 19 | ["{", "}"], 20 | ["[", "]"], 21 | ["(", ")"], 22 | ["\"", "\""], 23 | ["'", "'"] 24 | ], 25 | "folding": { 26 | "offSide": true 27 | }, 28 | "wordPattern": "(#?-?\\d*\\.\\d\\w*%?)|(::?[\\w-]*(?=[^,{;]*[,{]))|(([@$#.!])?[\\w-?]+%?)", 29 | "onEnterRules": [ 30 | { 31 | "beforeText": "^[\\s]*///.*$", 32 | "action": { 33 | "indent": "none", 34 | "appendText": "/// " 35 | } 36 | } 37 | ] 38 | } 39 | -------------------------------------------------------------------------------- /vscode-extension/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "../node_modules/nx/schemas/project-schema.json", 3 | "name": "some-sass", 4 | "sourceRoot": "vscode-extension/src", 5 | "projectType": "application", 6 | "targets": { 7 | "package": { 8 | "executor": "nx:run-commands", 9 | "dependsOn": ["build", "^build"], 10 | "options": { 11 | "commands": [ 12 | "cd vscode-extension && npx vsce package --out some-sass.vsix" 13 | ], 14 | "parallel": false 15 | }, 16 | "outputs": ["{workspaceRoot}/dist/apps"] 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /vscode-extension/rspack.browser.config.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | 3 | const path = require("path"); 4 | const rspack = require("@rspack/core"); 5 | 6 | /** @type {import('@rspack/core').Configuration} **/ 7 | const config = { 8 | context: __dirname, 9 | mode: "none", 10 | target: "webworker", // web extensions run in a webworker context 11 | entry: { 12 | "browser-client": "./src/browser-client.ts", 13 | }, 14 | output: { 15 | filename: "[name].js", 16 | path: path.join(__dirname, "./dist"), 17 | libraryTarget: "commonjs", 18 | }, 19 | externals: { 20 | vscode: "commonjs vscode", 21 | }, 22 | plugins: [], 23 | devtool: false, 24 | resolve: { 25 | extensions: [".ts", ".js"], 26 | mainFields: ["browser", "module", "main"], 27 | conditionNames: ["import", "require", "default"], 28 | fallback: { 29 | events: require.resolve("events/"), 30 | assert: require.resolve("assert"), 31 | path: require.resolve("path-browserify"), 32 | }, 33 | }, 34 | module: { 35 | rules: [ 36 | { 37 | test: /\.m?js/, 38 | resolve: { 39 | fullySpecified: false, 40 | }, 41 | }, 42 | { 43 | test: /\.ts$/, 44 | exclude: [/[\\/]node_modules[\\/]/], 45 | loader: "builtin:swc-loader", 46 | options: { 47 | jsc: { 48 | parser: { 49 | syntax: "typescript", 50 | }, 51 | externalHelpers: true, 52 | }, 53 | }, 54 | }, 55 | ], 56 | }, 57 | plugins: [ 58 | new rspack.ProvidePlugin({ 59 | process: "process/browser", 60 | }), 61 | new rspack.optimize.LimitChunkCountPlugin({ 62 | maxChunks: 1, 63 | }), 64 | new rspack.CopyRspackPlugin({ 65 | patterns: [ 66 | { 67 | from: "../node_modules/some-sass-language-server/dist/**/*.js", 68 | to: "[name][ext]", 69 | }, 70 | ], 71 | }), 72 | ], 73 | }; 74 | 75 | module.exports = (env, argv) => { 76 | if (argv.mode === "development") { 77 | config.devtool = "source-map"; 78 | } 79 | 80 | return config; 81 | }; 82 | -------------------------------------------------------------------------------- /vscode-extension/rspack.node.config.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | 3 | const path = require("path"); 4 | const rspack = require("@rspack/core"); 5 | 6 | /** @type {import('@rspack/core').Configuration} **/ 7 | const config = { 8 | target: "node", 9 | entry: { 10 | "node-client": "./src/node-client.ts", 11 | }, 12 | output: { 13 | libraryTarget: "commonjs2", 14 | devtoolModuleFilenameTemplate: "../[resource-path]", 15 | path: path.join(__dirname, "./dist"), 16 | filename: "[name].js", 17 | }, 18 | externals: { 19 | fsevents: 'require("fsevents")', 20 | vscode: "commonjs vscode", 21 | }, 22 | resolve: { 23 | extensions: [".ts", ".js"], 24 | conditionNames: ["import", "require", "default"], 25 | mainFields: ["module", "main"], 26 | }, 27 | plugins: [ 28 | new rspack.CopyRspackPlugin({ 29 | patterns: [ 30 | { 31 | from: "../node_modules/some-sass-language-server/dist/**/*.js", 32 | to: "[name][ext]", 33 | }, 34 | ], 35 | }), 36 | ], 37 | devtool: false, 38 | module: { 39 | rules: [ 40 | { 41 | test: /\.ts$/, 42 | exclude: [/[\\/]node_modules[\\/]/], 43 | loader: "builtin:swc-loader", 44 | options: { 45 | jsc: { 46 | parser: { 47 | syntax: "typescript", 48 | }, 49 | externalHelpers: true, 50 | }, 51 | }, 52 | }, 53 | ], 54 | }, 55 | }; 56 | 57 | module.exports = (env, argv) => { 58 | if (argv.mode === "development") { 59 | config.devtool = "source-map"; 60 | } 61 | 62 | return config; 63 | }; 64 | -------------------------------------------------------------------------------- /vscode-extension/rspack.test-web.config.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | 3 | const path = require("path"); 4 | const rspack = require("@rspack/core"); 5 | 6 | /** @typedef {import('@rspack/core').Configuration} RspackConfig **/ 7 | /** @type RspackConfig */ 8 | const browserTestsConfig = { 9 | context: __dirname, 10 | mode: "none", 11 | target: "webworker", 12 | entry: { 13 | "suite/index": "./test/web/suite/index.js", 14 | }, 15 | output: { 16 | filename: "web-tests.js", 17 | path: path.join(__dirname, "out", "test"), 18 | libraryTarget: "commonjs", 19 | }, 20 | resolve: { 21 | mainFields: ["module", "main"], 22 | extensions: [".js"], 23 | alias: {}, 24 | fallback: { 25 | assert: require.resolve("assert"), 26 | events: require.resolve("events/"), 27 | path: require.resolve("path-browserify"), 28 | util: require.resolve("util/"), 29 | "fs/promises": false, 30 | }, 31 | }, 32 | module: { 33 | rules: [ 34 | { 35 | test: /\.m?js/, 36 | resolve: { 37 | fullySpecified: false, 38 | }, 39 | }, 40 | ], 41 | }, 42 | performance: { 43 | hints: false, 44 | }, 45 | plugins: [ 46 | new rspack.ProvidePlugin({ 47 | process: "process/browser", 48 | }), 49 | ], 50 | externals: { 51 | vscode: "commonjs vscode", 52 | }, 53 | performance: { 54 | hints: false, 55 | }, 56 | devtool: "nosources-source-map", 57 | }; 58 | 59 | module.exports = browserTestsConfig; 60 | -------------------------------------------------------------------------------- /vscode-extension/schemas/package.schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "type": "object", 4 | "properties": { 5 | "contributes": { 6 | "type": "object", 7 | "properties": { 8 | "css.customData": { 9 | "type": "array", 10 | "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.", 11 | "items": { 12 | "type": "string", 13 | "description": "Relative path to a CSS custom data file" 14 | } 15 | } 16 | } 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /vscode-extension/src/constants.ts: -------------------------------------------------------------------------------- 1 | export const EXTENSION_ID = "some-sass"; 2 | export const EXTENSION_NAME = "Some Sass"; 3 | 4 | export const REQUEST_FS_STAT = `${EXTENSION_ID}/stat`; 5 | export const REQUEST_FS_FIND_FILES = `${EXTENSION_ID}/find-files`; 6 | export const REQUEST_FS_READ_FILE = `${EXTENSION_ID}/read-file`; 7 | export const REQUEST_FS_READ_DIRECTORY = `${EXTENSION_ID}/read-directory`; 8 | -------------------------------------------------------------------------------- /vscode-extension/src/node/file-system.ts: -------------------------------------------------------------------------------- 1 | import type { FileStat } from "vscode"; 2 | import { FileType } from "vscode-css-languageservice"; 3 | import type { CancellationToken } from "vscode-languageclient/node"; 4 | import type { URI } from "vscode-uri"; 5 | 6 | /** 7 | * API to abstract away whether or not we have direct file system access. 8 | */ 9 | export interface FileSystemProvider { 10 | exists(uri: URI): Promise; 11 | findFiles( 12 | include: string, 13 | exclude?: string | string[] | null, 14 | maxResults?: number, 15 | token?: CancellationToken, 16 | ): Promise; 17 | readFile(uri: URI, encoding?: BufferEncoding): Promise; 18 | readDirectory(uri: string): Promise<[string, FileType][]>; 19 | stat(uri: URI): Promise; 20 | realPath(uri: URI): Promise; 21 | } 22 | -------------------------------------------------------------------------------- /vscode-extension/src/runtime.ts: -------------------------------------------------------------------------------- 1 | import { FileSystemProvider } from "./node/file-system"; 2 | 3 | export interface Runtime { 4 | TextDecoder: { 5 | new (encoding?: string): { decode(buffer: ArrayBuffer): string }; 6 | }; 7 | fs?: FileSystemProvider; 8 | } 9 | -------------------------------------------------------------------------------- /vscode-extension/src/utils/string.ts: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * MIT License 4 | * 5 | * Copyright (c) 2015 - present Microsoft Corporation 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | *--------------------------------------------------------------------------------------------*/ 25 | export function getEOL(text: string): string { 26 | for (let i = 0; i < text.length; i++) { 27 | const ch = text.charAt(i); 28 | if (ch === "\r") { 29 | if (i + 1 < text.length && text.charAt(i + 1) === "\n") { 30 | return "\r\n"; 31 | } 32 | return "\r"; 33 | } else if (ch === "\n") { 34 | return "\n"; 35 | } 36 | } 37 | return "\n"; 38 | } 39 | -------------------------------------------------------------------------------- /vscode-extension/test/README.md: -------------------------------------------------------------------------------- 1 | # About these tests 2 | 3 | These tests automate Visual Studio Code using the [VS Code JavaScript API](https://code.visualstudio.com/api/references/vscode-api). 4 | Check the API docs to see how you can automate the interactions you need for testing. 5 | 6 | There are two different test runners: 7 | 8 | - [@vscode/test-electron](https://github.com/microsoft/vscode-test) 9 | - [@vscode/test-web](https://github.com/microsoft/vscode-test-web) 10 | 11 | The web runner test suite is a minimal "smoketest" to ensure the browser build runs as expected. 12 | 13 | The Electron runner is configured so it can run multiple instances of VS Code (in sequence) using 14 | different configurations and workspaces. Each subdirectory in `e2e/` will run in a separate instance 15 | of VS Code. 16 | 17 | By convention subdirectories in `e2e/` must have: 18 | 19 | - `index.js` as the entrypoint that finds test files and passes them to Mocha 20 | - at least one `*.test.js` file with some tests 21 | - a `workspace/` subdirectory with: 22 | - `.vscode/settings.json` 23 | - `styles.scss` or `styles.sass` 24 | 25 | Starting and stopping VS Code takes a few seconds, so try to use the same workspaces as much as possible. 26 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-sass/completions.test.js: -------------------------------------------------------------------------------- 1 | const assert = require("assert"); 2 | const vscode = require("vscode"); 3 | const { getDocUri, showFile, sleepCI, type, sleep } = require("./util"); 4 | 5 | const completionsUri = getDocUri("completions.sass"); 6 | 7 | before(async () => { 8 | await showFile(completionsUri); 9 | await sleepCI(); 10 | }); 11 | 12 | test("shows completions for a module after typing the module name and .", async () => { 13 | const completions = await showFile(completionsUri); 14 | await sleepCI(); 15 | 16 | // give syntax highlighting time to tell Emmet to GTFO 17 | await sleep(300); 18 | 19 | const cursor = new vscode.Position(2, 0); 20 | completions.selection = new vscode.Selection(cursor, cursor); 21 | 22 | // should show suggestions for dark- and light-mode-variables 23 | await type(completions, "@include theme."); 24 | 25 | // give suggestions time to appear 26 | await sleep(300); 27 | 28 | // accept the first 29 | await vscode.commands.executeCommand("acceptSelectedSuggestion"); 30 | 31 | // confirm the suggestion was applied 32 | assert.match(completions.document.getText(), /dark-mode-variables/); 33 | }); 34 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-sass/index.js: -------------------------------------------------------------------------------- 1 | const vscode = require("vscode"); 2 | const { resolve } = require("path"); 3 | const { glob } = require("tinyglobby"); 4 | const { runMocha } = require("../mocha"); 5 | 6 | /** 7 | * @returns {Promise} 8 | */ 9 | async function run() { 10 | const files = await glob("*.test.js", { 11 | cwd: resolve(__dirname), 12 | absolute: true, 13 | }); 14 | 15 | await runMocha( 16 | files, 17 | vscode.Uri.file(resolve(__dirname, "workspace", "styles.sass")), 18 | ); 19 | } 20 | 21 | module.exports = { run }; 22 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-sass/navigation.test.js: -------------------------------------------------------------------------------- 1 | const assert = require("assert"); 2 | const vscode = require("vscode"); 3 | const { getDocUri, showFile, sleepCI } = require("./util"); 4 | 5 | const mainUri = getDocUri("navigation/main.sass"); 6 | const circularUri = getDocUri("navigation/_circular.sass"); 7 | 8 | before(async () => { 9 | await showFile(mainUri); 10 | await sleepCI(); 11 | }); 12 | 13 | after(async () => { 14 | await vscode.commands.executeCommand("workbench.action.closeAllEditors"); 15 | }); 16 | 17 | test("navigating to a circular dependency does not cause a loop (#206)", async () => { 18 | await showFile(mainUri); 19 | let links = await findDocumentLinks(mainUri); 20 | 21 | const circular = links.find( 22 | (v) => v.target && v.target.path.endsWith("circular.sass"), 23 | ); 24 | if (!circular || !circular.target) { 25 | return assert.fail("Didn't find a working link to circular.sass"); 26 | } 27 | 28 | await goToTarget(circular.target); 29 | 30 | assert.equal( 31 | vscode.window.activeTextEditor?.document.uri.fsPath, 32 | circularUri.fsPath, 33 | "Should be viewing circular.sass right now", 34 | ); 35 | 36 | links = await findDocumentLinks(circular.target); 37 | const main = links.find( 38 | (v) => v.target && v.target.path.endsWith("main.sass"), 39 | ); 40 | if (!main || !main.target) { 41 | return assert.fail("Didn't find a working link to main.sass"); 42 | } 43 | 44 | await goToTarget(main.target); 45 | 46 | assert.equal( 47 | vscode.window.activeTextEditor?.document.uri.fsPath, 48 | mainUri.fsPath, 49 | "Should be viewing main.sass right now", 50 | ); 51 | }); 52 | 53 | /** 54 | * @param {import('vscode').Uri} documentUri 55 | * @returns {Promise} 56 | */ 57 | async function findDocumentLinks(documentUri) { 58 | /** @type {import('vscode').DocumentLink[]} */ 59 | const links = await vscode.commands.executeCommand( 60 | "vscode.executeLinkProvider", 61 | documentUri, 62 | /*linkResolveCount*/ 100, 63 | ); 64 | return links; 65 | } 66 | 67 | /** 68 | * @param {import('vscode').Uri} uri 69 | * @returns {Promise} 70 | */ 71 | async function goToTarget(uri) { 72 | await vscode.commands.executeCommand("vscode.open", uri); 73 | } 74 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-sass/syntax-mixing.test.js: -------------------------------------------------------------------------------- 1 | const assert = require("assert"); 2 | const vscode = require("vscode"); 3 | const { getDocUri, showFile, sleepCI } = require("./util"); 4 | 5 | const indentedStyles = getDocUri("syntax-mixing/styles.sass"); 6 | const scssStyles = getDocUri("syntax-mixing/styles.scss"); 7 | const indentedTokens = getDocUri("syntax-mixing/_indented.sass"); 8 | const scssTokens = getDocUri("syntax-mixing/_scss.scss"); 9 | 10 | before(async () => { 11 | await showFile(indentedStyles); 12 | await showFile(scssStyles); 13 | await sleepCI(); 14 | }); 15 | 16 | test("finds definition of a variable declared in indented from scss", async () => { 17 | const expected = new vscode.Location( 18 | indentedTokens, 19 | new vscode.Range(new vscode.Position(0, 0), new vscode.Position(0, 10)), 20 | ); 21 | 22 | await testDefinition(scssStyles, new vscode.Position(4, 24), expected); 23 | }); 24 | 25 | test("finds definition of a variable declared in scss from indented", async () => { 26 | const expected = new vscode.Location( 27 | scssTokens, 28 | new vscode.Range(new vscode.Position(0, 0), new vscode.Position(0, 10)), 29 | ); 30 | 31 | await testDefinition(indentedStyles, new vscode.Position(5, 18), expected); 32 | }); 33 | 34 | 35 | /** 36 | * @param {import('vscode').Uri} docUri 37 | * @param {import('vscode').Position} position 38 | * @param {import('vscode').Location} expectedLocation 39 | * @returns {Promise} 40 | */ 41 | async function testDefinition(docUri, position, expectedLocation) { 42 | await showFile(docUri); 43 | 44 | const result = 45 | /** @type {import('vscode').Location[]} */ 46 | ( 47 | await vscode.commands.executeCommand( 48 | "vscode.executeDefinitionProvider", 49 | docUri, 50 | position, 51 | ) 52 | ); 53 | 54 | if (result[0] === undefined) { 55 | assert.fail("The 'result[0]' is undefined."); 56 | } 57 | 58 | assert.ok( 59 | result[0].range.isEqual(expectedLocation.range), 60 | `Expected ${JSON.stringify(result[0].range)} to equal ${JSON.stringify( 61 | expectedLocation.range, 62 | )} in ${docUri.fsPath}`, 63 | ); 64 | assert.strictEqual(result[0].uri.fsPath, expectedLocation.uri.fsPath); 65 | } 66 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-sass/util.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | const vscode = require("vscode"); 3 | const { 4 | showFile, 5 | sleep, 6 | sleepCI, 7 | type, 8 | } = require("../util"); 9 | 10 | /** 11 | * @param {string} p 12 | * @returns {string} 13 | */ 14 | function getDocPath(p) { 15 | return path.resolve(__dirname, "workspace", p); 16 | } 17 | 18 | /** 19 | * @param {string} p 20 | * @returns {import('vscode').Uri} 21 | */ 22 | function getDocUri(p) { 23 | return vscode.Uri.file(getDocPath(p)); 24 | } 25 | 26 | module.exports = { 27 | sleep, 28 | sleepCI, 29 | showFile, 30 | getDocPath, 31 | getDocUri, 32 | type, 33 | }; 34 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-sass/workspace/.editorconfig: -------------------------------------------------------------------------------- 1 | [*] 2 | charset = utf-8 3 | indent_style = space 4 | indent_size = 2 5 | insert_final_newline = true 6 | trim_trailing_whitespace = true 7 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-sass/workspace/completions.sass: -------------------------------------------------------------------------------- 1 | @use "core/theme" 2 | 3 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-sass/workspace/core/_theme.sass: -------------------------------------------------------------------------------- 1 | @mixin light-mode-variables 2 | @media screen and (prefers-color-scheme: light) 3 | :root 4 | @content 5 | 6 | @mixin dark-mode-variables 7 | @media screen and (prefers-color-scheme: dark) 8 | :root 9 | @content 10 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-sass/workspace/core/_tokens.sass: -------------------------------------------------------------------------------- 1 | $_font-size-12: 12px 2 | $_font-size-16: 16px 3 | $_font-size-20: 20px 4 | $_font-size-28: 28px 5 | $_font-size-36: 36px 6 | $_font-size-56: 56px 7 | 8 | $font-size-micro: $_font-size-12 9 | $font-size-small: $_font-size-16 10 | $font-size-body: $_font-size-20 11 | $font-size-heading-3: $_font-size-28 12 | $font-size-heading-2: $_font-size-36 13 | $font-size-heading-1: $_font-size-56 14 | 15 | $_color-black: #000 16 | $_color-white: #fff 17 | 18 | $color-text-on-light: $_color-black 19 | $color-text-on-dark: $_color-white 20 | 21 | $color-background-light: $_color-white 22 | $color-background-dark: $_color-black 23 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-sass/workspace/navigation/_circular.sass: -------------------------------------------------------------------------------- 1 | @use "main" 2 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-sass/workspace/navigation/main.sass: -------------------------------------------------------------------------------- 1 | @use "circular" 2 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-sass/workspace/styles.sass: -------------------------------------------------------------------------------- 1 | @use "core/tokens" 2 | @use "core/theme" 3 | 4 | +theme.light-mode-variables 5 | --color-body-background: #{tokens.$color-background-light} 6 | --color-body-text: #{tokens.$color-text-on-light} 7 | 8 | @include theme.dark-mode-variables 9 | --color-body-background: #{tokens.$color-background-dark} 10 | --color-body-text: #{tokens.$color-text-on-dark} 11 | 12 | body 13 | background-color: var(--color-body-background) 14 | color: var(--color-body-text) 15 | font-size: tokens.$font-size-body 16 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-sass/workspace/syntax-mixing/_indented.sass: -------------------------------------------------------------------------------- 1 | $spacing-2: 2px 2 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-sass/workspace/syntax-mixing/_scss.scss: -------------------------------------------------------------------------------- 1 | $spacing-4: 4px; 2 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-sass/workspace/syntax-mixing/styles.sass: -------------------------------------------------------------------------------- 1 | @use "indented" 2 | @use "scss" 3 | 4 | a 5 | padding: indented.$spacing-2 6 | margin: scss.$spacing-4 7 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-sass/workspace/syntax-mixing/styles.scss: -------------------------------------------------------------------------------- 1 | @use "indented"; 2 | @use "scss"; 3 | 4 | a { 5 | padding: indented.$spacing-2; 6 | margin: scss.$spacing-4; 7 | } 8 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-scss/completion-placeholders.test.js: -------------------------------------------------------------------------------- 1 | const { getDocUri, showFile, position, sleepCI } = require("./util"); 2 | const { testCompletion } = require("./completion-helper"); 3 | 4 | const docUri = getDocUri("completion/reverse-placeholders/_theme.scss"); 5 | 6 | before(async () => { 7 | await showFile(docUri); 8 | await sleepCI(); 9 | }); 10 | 11 | test("Offers completions for placeholder usages when implementing a placeholder selector", async () => { 12 | await testCompletion(docUri, position(1, 2), [ 13 | { 14 | label: "%app", 15 | insertText: "app", 16 | }, 17 | { 18 | label: "%app", 19 | labelDetails: { detail: " { }" }, 20 | }, 21 | { 22 | label: "%chat", 23 | insertText: "chat", 24 | }, 25 | { 26 | label: "%chat", 27 | labelDetails: { detail: " { }" }, 28 | }, 29 | ]); 30 | 31 | await testCompletion(docUri, position(3, 4), [ 32 | { 33 | label: "%chat", 34 | insertText: "chat", 35 | }, 36 | { 37 | label: "%chat", 38 | labelDetails: { detail: " { }" }, 39 | }, 40 | ]); 41 | }); 42 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-scss/definition-helper.js: -------------------------------------------------------------------------------- 1 | const assert = require("assert"); 2 | const vscode = require("vscode"); 3 | const { showFile } = require("./util"); 4 | 5 | /** 6 | * @param {import('vscode').Uri} docUri 7 | * @param {import('vscode').Position} position 8 | * @param {import('vscode').Location} expectedLocation 9 | * @returns {Promise} 10 | */ 11 | async function testDefinition(docUri, position, expectedLocation) { 12 | await showFile(docUri); 13 | 14 | const result = 15 | /** @type {import('vscode').Location[]} */ 16 | ( 17 | await vscode.commands.executeCommand( 18 | "vscode.executeDefinitionProvider", 19 | docUri, 20 | position, 21 | ) 22 | ); 23 | 24 | if (result[0] === undefined) { 25 | assert.fail("The 'result[0]' is undefined."); 26 | } 27 | 28 | assert.ok( 29 | result[0].range.isEqual(expectedLocation.range), 30 | `Expected ${JSON.stringify(result[0].range)} to equal ${JSON.stringify( 31 | expectedLocation.range, 32 | )} in ${docUri.fsPath}`, 33 | ); 34 | assert.strictEqual(result[0].uri.fsPath, expectedLocation.uri.fsPath); 35 | } 36 | 37 | module.exports = { 38 | testDefinition, 39 | }; 40 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-scss/hover-helper.js: -------------------------------------------------------------------------------- 1 | const assert = require("assert"); 2 | const vscode = require("vscode"); 3 | const { showFile } = require("./util"); 4 | 5 | /** 6 | * @param {import('vscode').Uri} docUri 7 | * @param {import('vscode').Position} position 8 | * @param {import('vscode').Hover} expectedHover 9 | * @returns {Promise} 10 | */ 11 | async function testHover(docUri, position, expectedHover) { 12 | await showFile(docUri); 13 | 14 | const result = /** @type {import('vscode').Hover[]} */ ( 15 | await vscode.commands.executeCommand( 16 | "vscode.executeHoverProvider", 17 | docUri, 18 | position, 19 | ) 20 | ); 21 | 22 | if (!result[0]) { 23 | throw new Error(`Hover failed at position ${JSON.stringify(position)}`); 24 | } 25 | 26 | const contents = result 27 | .map((item) => { 28 | return item.contents.map((content) => { 29 | return /** @type {import('vscode').MarkdownString} */ (content).value; 30 | }); 31 | }) 32 | .join("\n"); 33 | 34 | // We use `.includes` here because the hover can contain content from other plugins. 35 | assert.ok( 36 | contents.includes(expectedHover.contents.join("")), 37 | `Hover does not include expected output. Actual: '${contents}'.`, 38 | ); 39 | 40 | if (expectedHover.range && result[0] && result[0].range) { 41 | assert.ok( 42 | result[0].range.isEqual(expectedHover.range), 43 | `Expected output does not match expected range. Actual: '${result[0].range?.toString()}'.`, 44 | ); 45 | } 46 | } 47 | 48 | module.exports = { 49 | testHover, 50 | }; 51 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-scss/index.js: -------------------------------------------------------------------------------- 1 | const vscode = require("vscode"); 2 | const { resolve } = require("path"); 3 | const { glob } = require("tinyglobby"); 4 | const { runMocha } = require("../mocha"); 5 | 6 | /** 7 | * @returns {Promise} 8 | */ 9 | async function run() { 10 | const files = await glob("*.test.js", { 11 | cwd: resolve(__dirname), 12 | absolute: true, 13 | }); 14 | 15 | await runMocha( 16 | files, 17 | vscode.Uri.file(resolve(__dirname, "workspace", "styles.scss")), 18 | ); 19 | } 20 | 21 | module.exports = { run }; 22 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-scss/navigation.test.js: -------------------------------------------------------------------------------- 1 | const vscode = require("vscode"); 2 | const { getDocUri, showFile, sleepCI } = require("./util"); 3 | const assert = require("assert"); 4 | 5 | const mainUri = getDocUri("completion/main.scss"); 6 | const circularUri = getDocUri("completion/circular.scss"); 7 | 8 | before(async () => { 9 | await showFile(mainUri); 10 | await sleepCI(); 11 | }); 12 | 13 | after(async () => { 14 | await vscode.commands.executeCommand("workbench.action.closeAllEditors"); 15 | }); 16 | 17 | test("navigating to a circular dependency does not cause a loop (#206)", async () => { 18 | await showFile(mainUri); 19 | let links = await findDocumentLinks(mainUri); 20 | 21 | const circular = links.find( 22 | (v) => v.target && v.target.path.endsWith("circular.scss"), 23 | ); 24 | if (!circular || !circular.target) { 25 | return assert.fail("Didn't find a working link to circular.scss"); 26 | } 27 | 28 | await goToTarget(circular.target); 29 | 30 | assert.equal( 31 | vscode.window.activeTextEditor?.document.uri.fsPath, 32 | circularUri.fsPath, 33 | "Should be viewing circular.scss right now", 34 | ); 35 | 36 | links = await findDocumentLinks(circular.target); 37 | const main = links.find( 38 | (v) => v.target && v.target.path.endsWith("main.scss"), 39 | ); 40 | if (!main || !main.target) { 41 | return assert.fail("Didn't find a working link to main.scss"); 42 | } 43 | 44 | await goToTarget(main.target); 45 | 46 | assert.equal( 47 | vscode.window.activeTextEditor?.document.uri.fsPath, 48 | mainUri.fsPath, 49 | "Should be viewing main.scss right now", 50 | ); 51 | }); 52 | 53 | /** 54 | * @param {import('vscode').Uri} documentUri 55 | * @returns {Promise} 56 | */ 57 | async function findDocumentLinks(documentUri) { 58 | /** @type {import('vscode').DocumentLink[]} */ 59 | const links = await vscode.commands.executeCommand( 60 | "vscode.executeLinkProvider", 61 | documentUri, 62 | /*linkResolveCount*/ 100, 63 | ); 64 | return links; 65 | } 66 | 67 | /** 68 | * @param {import('vscode').Uri} uri 69 | * @returns {Promise} 70 | */ 71 | async function goToTarget(uri) { 72 | await vscode.commands.executeCommand("vscode.open", uri); 73 | } 74 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-scss/signature-helper.js: -------------------------------------------------------------------------------- 1 | const assert = require("assert"); 2 | const vscode = require("vscode"); 3 | const { showFile } = require("./util"); 4 | 5 | /** 6 | * @param {import('vscode').Uri} docUri 7 | * @param {import('vscode').Position} position 8 | * @param {import('vscode').SignatureHelp} signature 9 | * @returns {Promise} 10 | */ 11 | async function testSignature(docUri, position, signature) { 12 | await showFile(docUri); 13 | 14 | const result = /** @type {import('vscode').SignatureHelp} */ ( 15 | await vscode.commands.executeCommand( 16 | "vscode.executeSignatureHelpProvider", 17 | docUri, 18 | position, 19 | ) 20 | ); 21 | 22 | if (result === undefined) { 23 | assert.fail("The 'result' is undefined."); 24 | } 25 | 26 | assert.strictEqual( 27 | result.activeParameter, 28 | signature.activeParameter, 29 | `activeParameter in ${docUri.fsPath}`, 30 | ); 31 | assert.strictEqual( 32 | result.activeSignature, 33 | signature.activeSignature, 34 | "activeSignature", 35 | ); 36 | 37 | assert.strictEqual( 38 | result.signatures.length, 39 | signature.signatures.length, 40 | `Count of signatures: ${signature.signatures.length} expected; ${result.signatures.length} actual`, 41 | ); 42 | 43 | signature.signatures.forEach((expectedSignature, i) => { 44 | const actualSignature = result.signatures[i]; 45 | 46 | if (actualSignature === undefined) { 47 | assert.fail("The 'actualSignature' is undefined."); 48 | } 49 | 50 | assert.strictEqual(actualSignature.label, expectedSignature.label); 51 | 52 | assert.strictEqual( 53 | actualSignature.parameters.length, 54 | expectedSignature.parameters.length, 55 | `Count of parameters for {expectedSignature.label}: ${expectedSignature.parameters.length} expected; ${actualSignature.parameters.length} actual`, 56 | ); 57 | }); 58 | } 59 | 60 | module.exports = { 61 | testSignature, 62 | }; 63 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-scss/util.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | const vscode = require("vscode"); 3 | const { 4 | position, 5 | sameLineLocation, 6 | sameLineRange, 7 | showFile, 8 | sleep, 9 | sleepCI, 10 | type, 11 | } = require("../util"); 12 | 13 | /** 14 | * @param {string} p 15 | * @returns {string} 16 | */ 17 | function getDocPath(p) { 18 | return path.resolve(__dirname, "workspace", p); 19 | } 20 | 21 | /** 22 | * @param {string} p 23 | * @returns {import('vscode').Uri} 24 | */ 25 | function getDocUri(p) { 26 | return vscode.Uri.file(getDocPath(p)); 27 | } 28 | 29 | module.exports = { 30 | sleep, 31 | sleepCI, 32 | showFile, 33 | getDocPath, 34 | getDocUri, 35 | position, 36 | sameLineLocation, 37 | sameLineRange, 38 | type, 39 | }; 40 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-scss/workspace/.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-scss/workspace/_functions.scss: -------------------------------------------------------------------------------- 1 | @function function() { 2 | @return 1; 3 | } 4 | 5 | @function pow($base, $exponent) { 6 | $result: 1; 7 | @for $_ from 1 through $exponent { 8 | $result: $result * $base; 9 | } 10 | @return $result; 11 | } 12 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-scss/workspace/_mixins.scss: -------------------------------------------------------------------------------- 1 | @mixin mixin { 2 | content: 'mixin'; 3 | } 4 | 5 | @mixin square($size, $radius: 0) { 6 | width: $size; 7 | height: $size; 8 | 9 | @if $radius != 0 { 10 | border-radius: $radius; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-scss/workspace/_placeholders.scss: -------------------------------------------------------------------------------- 1 | %alert { 2 | color: blue; 3 | } 4 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-scss/workspace/_variables.scss: -------------------------------------------------------------------------------- 1 | $variable: 'value'; 2 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-scss/workspace/completion/AppButton.astro: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | 4 |

5 | 6 | 40 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-scss/workspace/completion/AppButton.svelte: -------------------------------------------------------------------------------- 1 |

2 | 3 | 37 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-scss/workspace/completion/AppButton.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 10 | 11 | 45 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-scss/workspace/completion/_partial.scss: -------------------------------------------------------------------------------- 1 | $partial: blue; 2 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-scss/workspace/completion/circular.scss: -------------------------------------------------------------------------------- 1 | @use "./main"; 2 | 3 | $cicular: reference; 4 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-scss/workspace/completion/main.scss: -------------------------------------------------------------------------------- 1 | $color: blue; 2 | $fonts: -apple-system; 3 | 4 | .foo { 5 | color: $; 6 | } 7 | 8 | @import '~foo/bar.scss'; 9 | 10 | .foo { 11 | color: $; 12 | } 13 | 14 | @import './partial'; 15 | 16 | .foo { 17 | color: $; 18 | } 19 | 20 | @use '../namespace' as ns; 21 | 22 | .foo { 23 | color: ns. 24 | @include ns. 25 | --runtime-var: var(--other-var, #{ns.}) 26 | font-size: -#{ns.} 27 | } 28 | 29 | @function _multiply($value) { 30 | @return $value * ns.; 31 | } 32 | 33 | @use "sass:math"; 34 | 35 | .foo { 36 | padding: math.fl 37 | } 38 | 39 | @use "./circular"; 40 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-scss/workspace/completion/modules.scss: -------------------------------------------------------------------------------- 1 | @use "bootstrap/"; 2 | @use "bootstrap/scss/"; 3 | @use "foo/"; 4 | @use "~bootstrap/"; 5 | @use "~bootstrap/scss/"; 6 | @use "~foo/"; 7 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-scss/workspace/completion/node_modules/foo/bar.scss: -------------------------------------------------------------------------------- 1 | $tilde: blue; 2 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-scss/workspace/completion/node_modules/foo/package.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-scss/workspace/completion/node_modules/placeholders/package.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-scss/workspace/completion/node_modules/placeholders/placeholders-module.scss: -------------------------------------------------------------------------------- 1 | %strongAlert { 2 | color: red; 3 | } 4 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-scss/workspace/completion/placeholders.scss: -------------------------------------------------------------------------------- 1 | @use "placeholders/placeholders-module" as pl; 2 | 3 | %mediumAlert { 4 | color: orange; 5 | } 6 | 7 | .alert { 8 | &--medium { 9 | @extend %; 10 | } 11 | 12 | &--strong { 13 | @extend %s; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-scss/workspace/completion/reverse-placeholders/_theme.scss: -------------------------------------------------------------------------------- 1 | % 2 | 3 | %ch 4 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-scss/workspace/completion/reverse-placeholders/main.scss: -------------------------------------------------------------------------------- 1 | @use "./theme"; 2 | 3 | .app-asdfqwer1234 { 4 | @extend %app !optional; 5 | } 6 | 7 | .chat-qwerasdf1234 { 8 | @extend %chat !optional; 9 | } 10 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-scss/workspace/completion/sassdoc.scss: -------------------------------------------------------------------------------- 1 | @use "sass:math"; 2 | 3 | /// 4 | @mixin contentless { 5 | color: limegreen; 6 | } 7 | 8 | /// 9 | @mixin has-content { 10 | @content; 11 | } 12 | 13 | /// 14 | @mixin has-parameters($a: 1px, $b: 2px) { 15 | font-size: math.calc($a + $b); 16 | } 17 | 18 | /// 19 | @mixin has-parameters-and-content($a, $b) { 20 | @media screen and (min-width: $a) and (max-width: #{$b - 1px}) { 21 | @content; 22 | } 23 | } 24 | 25 | /// 26 | @function parameterless() { 27 | @return 1px; 28 | } 29 | 30 | /// 31 | @function parameterfull($a: 1px, $b: 2px) { 32 | @return math.calc($a + $b); 33 | } 34 | 35 | /// 36 | $doc-variable: 1px; 37 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-scss/workspace/completion/use-use/_first.scss: -------------------------------------------------------------------------------- 1 | @use "./second"; 2 | 3 | $first: second.$second; 4 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-scss/workspace/completion/use-use/_second.scss: -------------------------------------------------------------------------------- 1 | $second: red; 2 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-scss/workspace/completion/use-use/main.scss: -------------------------------------------------------------------------------- 1 | @use "./first"; 2 | 3 | $_hello: first.$; 4 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-scss/workspace/definition/AppButton.astro: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | 4 |

5 | 6 | 24 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-scss/workspace/definition/AppButton.svelte: -------------------------------------------------------------------------------- 1 |

2 | 3 | 22 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-scss/workspace/definition/AppButton.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 8 | 9 | 28 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-scss/workspace/definition/circular.scss: -------------------------------------------------------------------------------- 1 | @use "./main"; 2 | 3 | $cicular: reference; 4 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-scss/workspace/definition/main.scss: -------------------------------------------------------------------------------- 1 | @use "../functions" as *; 2 | @use "../mixins" as *; 3 | @use "../variables" as *; 4 | @use "../placeholders"; 5 | 6 | .test { 7 | content: $variable + function(); 8 | 9 | @include mixin(); 10 | } 11 | 12 | @use "../namespace" as ns; 13 | 14 | .foo { 15 | color: ns.$var-var-variable; 16 | @include ns.mix-mix-mixin; 17 | } 18 | 19 | .alert { 20 | @extend %alert; 21 | } 22 | 23 | @use "./circular"; 24 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-scss/workspace/diagnostics/AppButton.astro: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | 4 |

5 | 6 | 20 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-scss/workspace/diagnostics/AppButton.svelte: -------------------------------------------------------------------------------- 1 |

2 | 3 | 17 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-scss/workspace/diagnostics/AppButton.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 8 | 9 | 23 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-scss/workspace/diagnostics/_helpers.scss: -------------------------------------------------------------------------------- 1 | /// @deprecated Use something else. 2 | @function old-function() { 3 | @return 1; 4 | } 5 | 6 | /// @deprecated Use something else. 7 | $old-variable: 'value'; 8 | 9 | /// @deprecated Use something else. 10 | @mixin old-mixin { 11 | content: 'mixin'; 12 | } 13 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-scss/workspace/diagnostics/circular.scss: -------------------------------------------------------------------------------- 1 | @use "./main"; 2 | 3 | $cicular: reference; 4 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-scss/workspace/diagnostics/main.scss: -------------------------------------------------------------------------------- 1 | @use "./helpers" as *; 2 | 3 | /// @deprecated 4 | $_old-private-variable: 1px; 5 | 6 | .test { 7 | content: $old-variable + old-function(); 8 | 9 | @include old-mixin(); 10 | 11 | content: $_old-private-variable; 12 | } 13 | 14 | @use "../namespace" as ns; 15 | 16 | .foo { 17 | color: ns.$deprecated; 18 | @include ns.mix-mix-ohno; 19 | } 20 | 21 | @use "./circular"; 22 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-scss/workspace/hover/AppButton.astro: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | 4 |

5 | 6 | 24 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-scss/workspace/hover/AppButton.svelte: -------------------------------------------------------------------------------- 1 |

2 | 3 | 22 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-scss/workspace/hover/AppButton.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 8 | 9 | 28 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-scss/workspace/hover/_config.scss: -------------------------------------------------------------------------------- 1 | /// Deliberate name collision with sass:map 2 | @function get() { 3 | @return 1; 4 | } 5 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-scss/workspace/hover/circular.scss: -------------------------------------------------------------------------------- 1 | @use "./main"; 2 | 3 | $cicular: reference; 4 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-scss/workspace/hover/collision.scss: -------------------------------------------------------------------------------- 1 | @use "./config"; 2 | @use "sass:map"; 3 | 4 | .bar { 5 | $_color: config.get("bar"); 6 | } 7 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-scss/workspace/hover/main.scss: -------------------------------------------------------------------------------- 1 | @use "../functions" as *; 2 | @use "../mixins" as *; 3 | @use "../variables" as *; 4 | @use "../placeholders"; 5 | 6 | .test { 7 | content: $variable + function(); 8 | 9 | @include mixin(); 10 | } 11 | 12 | @use "../namespace" as ns; 13 | 14 | .foo { 15 | color: ns.$var-var-variable; 16 | @include ns.mix-mix-mixin; 17 | } 18 | 19 | /// Some wise words 20 | /// @type String 21 | $documented-variable: "value"; 22 | 23 | @use "sass:math" as magic; 24 | 25 | .foo { 26 | font-size: magic.floor(19.5px); 27 | } 28 | 29 | .alert { 30 | @extend %alert; 31 | } 32 | 33 | @use "./circular"; 34 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-scss/workspace/namespace/_functions.scss: -------------------------------------------------------------------------------- 1 | @function fun-function() { 2 | @return 1; 3 | } 4 | 5 | @function fun-pow($base, $exponent) { 6 | $result: 1; 7 | @for $_ from 1 through $exponent { 8 | $result: $result * $base; 9 | } 10 | @return $result; 11 | } 12 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-scss/workspace/namespace/_index.scss: -------------------------------------------------------------------------------- 1 | @forward "./functions" as fun-*; 2 | @forward "./mixins" as mix-* hide secret, other-secret; 3 | @forward "./variables" hide $secret; 4 | @forward "./show" show $one; 5 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-scss/workspace/namespace/_mixins.scss: -------------------------------------------------------------------------------- 1 | @mixin mix-mixin { 2 | content: 'mixin'; 3 | } 4 | 5 | /// Just here for the test 6 | /// @deprecated 7 | @mixin mix-ohno { 8 | content: 'mixin'; 9 | } 10 | 11 | @mixin mix-square($size, $radius: 0) { 12 | width: $size; 13 | height: $size; 14 | 15 | @if $radius != 0 { 16 | border-radius: $radius; 17 | } 18 | } 19 | 20 | 21 | @mixin secret { 22 | content: 'safe'; 23 | } 24 | 25 | @mixin other-secret { 26 | content: 'also-safe'; 27 | } 28 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-scss/workspace/namespace/_show.scss: -------------------------------------------------------------------------------- 1 | $one: blue; 2 | $two: red; 3 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-scss/workspace/namespace/_variables.scss: -------------------------------------------------------------------------------- 1 | $var-var-variable: 'value'; 2 | 3 | $secret: 'value'; 4 | 5 | /// Just here for the test 6 | /// @deprecated 7 | $deprecated: 'value'; 8 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-scss/workspace/node_modules/bootstrap/package.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkillerud/some-sass/cbfbfa96699020e32087c7a9ce76563e2be50981/vscode-extension/test/e2e/defaults-scss/workspace/node_modules/bootstrap/package.json -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-scss/workspace/node_modules/bootstrap/scss/bootstrap.scss: -------------------------------------------------------------------------------- 1 | $color: blue; 2 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-scss/workspace/pkg-import/node_modules/@my-scope/my-components/index.js: -------------------------------------------------------------------------------- 1 | console.log("Hello, World!"); 2 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-scss/workspace/pkg-import/node_modules/@my-scope/my-components/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@my-scope/my-components", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "exports": { 7 | ".": { 8 | "sass": "./styles/index.scss", 9 | "default": "./index.js" 10 | }, 11 | "./*.scss": { 12 | "sass": "./styles/*.scss" 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-scss/workspace/pkg-import/node_modules/@my-scope/my-components/styles/colors.scss: -------------------------------------------------------------------------------- 1 | /// Primary brand color 2 | /// @type {Color} 3 | $color-primary: green; 4 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-scss/workspace/pkg-import/node_modules/@my-scope/my-components/styles/index.scss: -------------------------------------------------------------------------------- 1 | @forward "./colors.scss"; 2 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-scss/workspace/pkg-import/node_modules/my-components/index.js: -------------------------------------------------------------------------------- 1 | console.log("Hello, World!"); 2 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-scss/workspace/pkg-import/node_modules/my-components/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "my-components", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "exports": { 7 | ".": { 8 | "sass": "./styles/index.scss", 9 | "default": "./index.js" 10 | }, 11 | "./*.scss": { 12 | "sass": "./styles/*.scss" 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-scss/workspace/pkg-import/node_modules/my-components/styles/colors.scss: -------------------------------------------------------------------------------- 1 | /// Primary brand color 2 | /// @type {Color} 3 | $color-primary: green; 4 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-scss/workspace/pkg-import/node_modules/my-components/styles/index.scss: -------------------------------------------------------------------------------- 1 | @forward "./colors.scss"; 2 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-scss/workspace/pkg-import/src/scoped.scss: -------------------------------------------------------------------------------- 1 | @use "pkg:@my-scope/my-components/colors"; 2 | 3 | button { 4 | color: colors.$color-primary; 5 | } 6 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-scss/workspace/pkg-import/src/styles.scss: -------------------------------------------------------------------------------- 1 | @use "pkg:my-components/colors"; 2 | 3 | button { 4 | color: colors.$color-primary; 5 | } 6 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-scss/workspace/references/_dev.scss: -------------------------------------------------------------------------------- 1 | @forward "fun" as fun-*; 2 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-scss/workspace/references/_fun.scss: -------------------------------------------------------------------------------- 1 | @function hello($var) { 2 | @return $var; 3 | } 4 | 5 | $name: "there"; 6 | $reply: "general"; 7 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-scss/workspace/references/circular.scss: -------------------------------------------------------------------------------- 1 | @use "./one"; 2 | 3 | $cicular: reference; 4 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-scss/workspace/references/one.scss: -------------------------------------------------------------------------------- 1 | @use "dev"; 2 | 3 | .a { 4 | // Here it comes! 5 | content: dev.fun-hello(dev.$fun-name); 6 | } 7 | 8 | @use "./circular"; 9 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-scss/workspace/signature/AppButton.astro: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | 4 |

5 | 6 | 26 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-scss/workspace/signature/AppButton.svelte: -------------------------------------------------------------------------------- 1 |

2 | 3 | 24 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-scss/workspace/signature/AppButton.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 8 | 9 | 30 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-scss/workspace/signature/main.scss: -------------------------------------------------------------------------------- 1 | @use '../functions' as *; 2 | @use '../mixins' as *; 3 | 4 | .test { 5 | @include square(); 6 | @include square(1,); 7 | 8 | content: pow() + pow(1,); 9 | } 10 | 11 | @use '../namespace' as ns; 12 | 13 | .foo { 14 | @include ns.mix-mix-square(); 15 | @include ns.mix-mix-square(1,); 16 | 17 | content: ns.fun-fun-pow() + ns.fun-fun-pow(1,); 18 | } 19 | 20 | @use 'sass:math' as magic; 21 | 22 | .foo { 23 | font-size: magic.clamp(); 24 | font-size: magic.clamp(1,); 25 | font-size: magic.clamp(1,2,); 26 | } 27 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/defaults-scss/workspace/styles.scss: -------------------------------------------------------------------------------- 1 | @use "./functions"; 2 | @use "./mixins"; 3 | @use "./variables"; 4 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/mocha.js: -------------------------------------------------------------------------------- 1 | const Mocha = require("mocha"); 2 | const { showFile, sleep } = require("./util"); 3 | 4 | const ONE_SECOND_IN_MS = 1 * 1000; 5 | 6 | /** 7 | * @param {string[]} files 8 | * @param {import('vscode').Uri} openFile File to open that activates the extension 9 | * @returns {Promise} 10 | */ 11 | async function runMocha(files, openFile) { 12 | const mocha = new Mocha({ 13 | ui: "qunit", 14 | timeout: ONE_SECOND_IN_MS * 30, 15 | }); 16 | 17 | // Add files to the test suite 18 | files.forEach((file) => mocha.addFile(file)); 19 | 20 | // Open a file to start initializing the extension and give it some time. 21 | await showFile(openFile); 22 | if (process.env["CI"]) { 23 | await sleep(ONE_SECOND_IN_MS * 10); 24 | } else { 25 | await sleep(ONE_SECOND_IN_MS * 3); 26 | } 27 | 28 | return new Promise((resolve, reject) => { 29 | mocha.run((failures) => { 30 | if (failures === 0) { 31 | resolve(); 32 | return; 33 | } 34 | 35 | const error = new Error(`${failures} tests failed.`); 36 | 37 | reject(error); 38 | }); 39 | }); 40 | } 41 | 42 | module.exports = { runMocha }; 43 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/runTest.js: -------------------------------------------------------------------------------- 1 | const childProcess = require("child_process"); 2 | const path = require("path"); 3 | const fs = require("fs/promises"); 4 | const { 5 | runTests, 6 | downloadAndUnzipVSCode, 7 | resolveCliArgsFromVSCodeExecutablePath, 8 | } = require("@vscode/test-electron"); 9 | 10 | async function main() { 11 | try { 12 | // The folder containing the Extension Manifest package.json 13 | // Passed to `--extensionDevelopmentPath` 14 | const extensionDevelopmentPath = path.resolve(__dirname, "..", ".."); 15 | 16 | const version = "insiders"; 17 | 18 | // Download VS Code, unzip it and run the integration test 19 | const vscodeExecutablePath = await downloadAndUnzipVSCode(version); 20 | 21 | const [cli, ...args] = 22 | resolveCliArgsFromVSCodeExecutablePath(vscodeExecutablePath); 23 | 24 | if (!cli) { 25 | throw new Error( 26 | "Something went wrong resolving the CLI path to the download of VS Code", 27 | ); 28 | } 29 | 30 | // For each folder, run the tests in index.js with that folder's workspace/ 31 | // as the workspace directory. 32 | const dir = await fs.readdir(__dirname, { withFileTypes: true }); 33 | for (let entry of dir) { 34 | if (entry.isDirectory()) { 35 | // The path to the extension test script 36 | // Passed to --extensionTestsPath 37 | const extensionTestsPath = path.resolve( 38 | entry.parentPath, 39 | entry.name, 40 | "index.js", 41 | ); 42 | 43 | const workspaceDir = path.resolve( 44 | entry.parentPath, 45 | entry.name, 46 | "workspace", 47 | ); 48 | 49 | await runTests({ 50 | vscodeExecutablePath, 51 | version, 52 | extensionDevelopmentPath, 53 | extensionTestsPath, 54 | launchArgs: [workspaceDir], 55 | }); 56 | } 57 | } 58 | } catch (error) { 59 | console.error("Failed to run tests"); 60 | console.error(error.name); 61 | console.error(error.message); 62 | console.error(error.stack); 63 | process.exit(1); 64 | } 65 | } 66 | 67 | main(); 68 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/suggest-from-use-only/index.js: -------------------------------------------------------------------------------- 1 | const vscode = require("vscode"); 2 | const { resolve } = require("path"); 3 | const { glob } = require("tinyglobby"); 4 | const { runMocha } = require("../mocha"); 5 | 6 | /** 7 | * @returns {Promise} 8 | */ 9 | async function run() { 10 | const files = await glob("*.test.js", { 11 | cwd: resolve(__dirname), 12 | absolute: true, 13 | }); 14 | 15 | await runMocha( 16 | files, 17 | vscode.Uri.file(resolve(__dirname, "workspace", "styles.scss")), 18 | ); 19 | } 20 | 21 | module.exports = { run }; 22 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/suggest-from-use-only/suggest-from-use-only.test.js: -------------------------------------------------------------------------------- 1 | const { showFile, position, sleepCI } = require("../util"); 2 | const { testCompletion, getDocPath } = require("./helper"); 3 | 4 | const styles = getDocPath("styles.scss"); 5 | 6 | before(async () => { 7 | await showFile(styles); 8 | await sleepCI(); 9 | }); 10 | 11 | test("setting gets applied", async () => { 12 | await testCompletion(styles, position(3, 6), [ 13 | { 14 | label: "$a", 15 | }, 16 | ]); 17 | 18 | // Does not suggest from b or c 19 | await testCompletion( 20 | styles, 21 | position(3, 6), 22 | [ 23 | { 24 | label: "$b", 25 | }, 26 | ], 27 | { 28 | expectNoMatch: true, 29 | }, 30 | ); 31 | await testCompletion( 32 | styles, 33 | position(3, 6), 34 | [ 35 | { 36 | label: "$c", 37 | }, 38 | ], 39 | { 40 | expectNoMatch: true, 41 | }, 42 | ); 43 | }); 44 | 45 | test("offers no hidden items in namespace completions", async () => { 46 | let expectedCompletions = ["$secret"]; 47 | 48 | await testCompletion(styles, position(23, 13), expectedCompletions, { 49 | expectNoMatch: true, 50 | }); 51 | }); 52 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/suggest-from-use-only/workspace/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "somesass.scss.completion.suggestFromUseOnly": true, 3 | "somesass.sass.completion.suggestFromUseOnly": true 4 | } 5 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/suggest-from-use-only/workspace/_a.scss: -------------------------------------------------------------------------------- 1 | @forward "d" hide $secret; 2 | 3 | $a: 1; 4 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/suggest-from-use-only/workspace/_b.scss: -------------------------------------------------------------------------------- 1 | $b: 1; 2 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/suggest-from-use-only/workspace/_c.scss: -------------------------------------------------------------------------------- 1 | $c: 1; 2 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/suggest-from-use-only/workspace/_d.scss: -------------------------------------------------------------------------------- 1 | $secret: 1; 2 | -------------------------------------------------------------------------------- /vscode-extension/test/e2e/suggest-from-use-only/workspace/styles.scss: -------------------------------------------------------------------------------- 1 | @use "./a" as *; 2 | 3 | $v: $ 4 | -------------------------------------------------------------------------------- /vscode-extension/test/web/runTest.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | const { runTests } = require("@vscode/test-web"); 3 | 4 | process.on("uncaughtException", (e) => { 5 | console.error(e); 6 | }); 7 | 8 | async function main() { 9 | try { 10 | // The folder containing the Extension Manifest package.json 11 | const extensionDevelopmentPath = path.resolve(__dirname, "..", ".."); 12 | 13 | // The path to module with the bundled test runner and tests 14 | const extensionTestsPath = path.resolve( 15 | __dirname, 16 | "..", 17 | "..", 18 | "out", 19 | "test", 20 | "web-tests.js", 21 | ); 22 | 23 | const folderPath = path.resolve( 24 | __dirname, 25 | "..", 26 | "..", 27 | "test", 28 | "e2e", 29 | "defaults-scss", 30 | "workspace", 31 | ); 32 | 33 | const attachArgName = "--waitForDebugger="; 34 | const waitForDebugger = process.argv.find((arg) => 35 | arg.startsWith(attachArgName), 36 | ); 37 | 38 | // Start a web server that serves VSCode in a browser, run the tests 39 | await runTests({ 40 | headless: true, 41 | browserType: "chromium", 42 | extensionDevelopmentPath, 43 | extensionTestsPath, 44 | folderPath, 45 | waitForDebugger: waitForDebugger 46 | ? Number(waitForDebugger.slice(attachArgName.length)) 47 | : undefined, 48 | }); 49 | } catch (err) { 50 | console.error("Failed to run tests"); 51 | process.exit(1); 52 | } 53 | } 54 | 55 | main(); 56 | -------------------------------------------------------------------------------- /vscode-extension/test/web/suite/completion-placeholders.test.js: -------------------------------------------------------------------------------- 1 | const { testCompletion } = require("./completion-helper"); 2 | const { getDocUri, showFile, position, sleep } = require("./util"); 3 | 4 | 5 | const placeholders = getDocUri("completion/placeholders.scss"); 6 | const theme = getDocUri("completion/reverse-placeholders/_theme.scss"); 7 | 8 | before(async () => { 9 | await showFile(placeholders); 10 | await showFile(theme); 11 | // TODO: figure out why we need to open main.scss and sleep here in the test. It works as expected in the browser. 12 | await showFile(getDocUri("completion/reverse-placeholders/main.scss")); 13 | await sleep(); 14 | }); 15 | 16 | 17 | test("get completions", async () => { 18 | const expectedCompletions = [ 19 | { 20 | label: "%mediumAlert", 21 | insertText: "mediumAlert", 22 | }, 23 | ]; 24 | 25 | await testCompletion(placeholders, position(9, 14), expectedCompletions); 26 | }); 27 | 28 | test("when implementing a placeholder selector", async () => { 29 | await testCompletion(theme, position(1, 2), [ 30 | { 31 | label: "%app", 32 | insertText: "app", 33 | }, 34 | { 35 | label: "%chat", 36 | insertText: "chat", 37 | }, 38 | ]); 39 | 40 | await testCompletion(theme, position(3, 4), [ 41 | { 42 | label: "%chat", 43 | insertText: "chat", 44 | }, 45 | ]); 46 | }); 47 | -------------------------------------------------------------------------------- /vscode-extension/test/web/suite/definitions-helper.js: -------------------------------------------------------------------------------- 1 | const assert = require("assert"); 2 | const vscode = require("vscode"); 3 | const { showFile } = require("./util"); 4 | 5 | /** 6 | * @param {import('vscode').Uri} docUri 7 | * @param {import('vscode').Position} position 8 | * @param {import('vscode').Location} expectedLocation 9 | * @returns {Promise} 10 | */ 11 | async function testDefinition(docUri, position, expectedLocation) { 12 | await showFile(docUri); 13 | 14 | const result = 15 | /** @type {import('vscode').Location[]} */ 16 | ( 17 | await vscode.commands.executeCommand( 18 | "vscode.executeDefinitionProvider", 19 | docUri, 20 | position, 21 | ) 22 | ); 23 | 24 | if (result[0] === undefined) { 25 | assert.fail("The 'result[0]' is undefined."); 26 | } 27 | 28 | assert.ok( 29 | result[0].range.isEqual(expectedLocation.range), 30 | `Expected ${JSON.stringify(result[0].range)} to equal ${JSON.stringify( 31 | expectedLocation.range, 32 | )} in ${docUri.fsPath}`, 33 | ); 34 | assert.strictEqual(result[0].uri.fsPath, expectedLocation.uri.fsPath); 35 | } 36 | 37 | module.exports = { testDefinition }; 38 | -------------------------------------------------------------------------------- /vscode-extension/test/web/suite/definitions.test.js: -------------------------------------------------------------------------------- 1 | const { testDefinition } = require("./definitions-helper"); 2 | const { 3 | getDocUri, 4 | showFile, 5 | position, 6 | sameLineLocation, 7 | sleep, 8 | } = require("./util"); 9 | 10 | 11 | const docUri = getDocUri("definition/main.scss"); 12 | 13 | before(async () => { 14 | await showFile(docUri); 15 | await sleep(1000); 16 | }); 17 | 18 | test("should find definition for variables", async () => { 19 | const expectedDocumentUri = getDocUri("_variables.scss"); 20 | const expectedLocation = sameLineLocation(expectedDocumentUri, 1, 1, 10); 21 | await testDefinition(docUri, position(7, 13), expectedLocation); 22 | }); 23 | 24 | test("should find definition for functions", async () => { 25 | const expectedDocumentUri = getDocUri("_functions.scss"); 26 | const expectedLocation = sameLineLocation(expectedDocumentUri, 1, 11, 19); 27 | await testDefinition(docUri, position(7, 24), expectedLocation); 28 | }); 29 | 30 | test("should find definition for mixins", async () => { 31 | const expectedDocumentUri = getDocUri("_mixins.scss"); 32 | const expectedLocation = sameLineLocation(expectedDocumentUri, 1, 8, 13); 33 | await testDefinition(docUri, position(9, 12), expectedLocation); 34 | }); 35 | 36 | test("should find definition for placeholder", async () => { 37 | const expectedDocumentUri = getDocUri("_placeholders.scss"); 38 | const expectedLocation = sameLineLocation(expectedDocumentUri, 1, 1, 7); 39 | await testDefinition(docUri, position(20, 14), expectedLocation); 40 | }); 41 | 42 | test("should find symbol definition behind namespace", async () => { 43 | const expectedDocumentUri = getDocUri("namespace/_variables.scss"); 44 | const expectedLocation = sameLineLocation(expectedDocumentUri, 1, 1, 18); 45 | await testDefinition(docUri, position(15, 15), expectedLocation); 46 | }); 47 | 48 | test("should find symbol definition behind namespace and prefix", async () => { 49 | const expectedDocumentUri = getDocUri("namespace/_mixins.scss"); 50 | const expectedLocation = sameLineLocation(expectedDocumentUri, 1, 8, 17); 51 | await testDefinition(docUri, position(16, 18), expectedLocation); 52 | }); 53 | -------------------------------------------------------------------------------- /vscode-extension/test/web/suite/hover-helper.js: -------------------------------------------------------------------------------- 1 | const assert = require("assert"); 2 | const vscode = require("vscode"); 3 | const { getDocUri, showFile, position, sleep } = require("./util"); 4 | 5 | /** 6 | * @param {import('vscode').Uri} docUri 7 | * @param {import('vscode').Position} position 8 | * @param {import('vscode').Hover} expectedHover 9 | * @returns {Promise} 10 | */ 11 | async function testHover(docUri, position, expectedHover) { 12 | await showFile(docUri); 13 | 14 | const result = /** @type {import('vscode').Hover[]} */ ( 15 | await vscode.commands.executeCommand( 16 | "vscode.executeHoverProvider", 17 | docUri, 18 | position, 19 | ) 20 | ); 21 | 22 | if (!result[0]) { 23 | throw new Error(`Hover failed at position ${JSON.stringify(position)}`); 24 | } 25 | 26 | const contents = result 27 | .map((item) => { 28 | return item.contents.map((content) => { 29 | return /** @type {import('vscode').MarkdownString} */ (content).value; 30 | }); 31 | }) 32 | .join("\n"); 33 | 34 | // We use `.includes` here because the hover can contain content from other plugins. 35 | assert.ok( 36 | contents.includes(expectedHover.contents.join("")), 37 | `Hover does not include expected output. Actual: '${contents}'.`, 38 | ); 39 | 40 | if (expectedHover.range && result[0] && result[0].range) { 41 | assert.ok( 42 | result[0].range.isEqual(expectedHover.range), 43 | `Expected output does not match expected range. Actual: '${result[0].range?.toString()}'.`, 44 | ); 45 | } 46 | } 47 | 48 | module.exports = { testHover }; 49 | -------------------------------------------------------------------------------- /vscode-extension/test/web/suite/index.js: -------------------------------------------------------------------------------- 1 | // imports mocha for the browser, defining the `mocha` global. 2 | require("mocha/mocha"); 3 | 4 | /** 5 | * @returns {Promise} 6 | */ 7 | function run() { 8 | return new Promise((c, e) => { 9 | mocha.setup({ 10 | ui: "qunit", 11 | reporter: undefined, 12 | timeout: 20000, 13 | }); 14 | 15 | // bundles all files in the current directory matching `*.test` 16 | const importAll = (r) => r.keys().forEach(r); 17 | importAll(require.context(".", true, /\.test$/)); 18 | 19 | try { 20 | // Run the mocha test 21 | mocha.run((failures) => { 22 | if (failures > 0) { 23 | e(new Error(`${failures} tests failed.`)); 24 | } else { 25 | c(); 26 | } 27 | }); 28 | } catch (err) { 29 | console.error(err); 30 | e(err); 31 | } 32 | }); 33 | } 34 | 35 | module.exports = { run }; 36 | -------------------------------------------------------------------------------- /vscode-extension/test/web/suite/signature-helper.js: -------------------------------------------------------------------------------- 1 | const assert = require("assert"); 2 | const vscode = require("vscode"); 3 | const { showFile } = require("./util"); 4 | 5 | /** 6 | * @param {import('vscode').Uri} docUri 7 | * @param {import('vscode').Position} position 8 | * @param {import('vscode').SignatureHelp} signature 9 | * @returns {Promise} 10 | */ 11 | async function testSignature(docUri, position, signature) { 12 | await showFile(docUri); 13 | 14 | const result = /** @type {import('vscode').SignatureHelp} */ ( 15 | await vscode.commands.executeCommand( 16 | "vscode.executeSignatureHelpProvider", 17 | docUri, 18 | position, 19 | ) 20 | ); 21 | if (result === undefined) { 22 | assert.fail("The 'result' is undefined."); 23 | } 24 | 25 | assert.strictEqual( 26 | result.activeParameter, 27 | signature.activeParameter, 28 | `activeParameter in ${docUri.fsPath}`, 29 | ); 30 | assert.strictEqual( 31 | result.activeSignature, 32 | signature.activeSignature, 33 | "activeSignature", 34 | ); 35 | 36 | assert.strictEqual( 37 | result.signatures.length, 38 | signature.signatures.length, 39 | `Count of signatures: ${signature.signatures.length} expected; ${result.signatures.length} actual`, 40 | ); 41 | 42 | signature.signatures.forEach((expectedSignature, i) => { 43 | const actualSignature = result.signatures[i]; 44 | 45 | if (actualSignature === undefined) { 46 | assert.fail("The 'actualSignature' is undefined."); 47 | } 48 | 49 | assert.strictEqual(actualSignature.label, expectedSignature.label); 50 | 51 | assert.strictEqual( 52 | actualSignature.parameters.length, 53 | expectedSignature.parameters.length, 54 | `Count of parameters for {expectedSignature.label}: ${expectedSignature.parameters.length} expected; ${actualSignature.parameters.length} actual`, 55 | ); 56 | }); 57 | } 58 | 59 | module.exports = { testSignature }; 60 | -------------------------------------------------------------------------------- /vscode-extension/test/web/suite/util.js: -------------------------------------------------------------------------------- 1 | const vscode = require("vscode"); 2 | 3 | /** 4 | * @param {number} ms 5 | * @returns {Promise} 6 | */ 7 | function sleep(ms = 1000) { 8 | if (process.env["CI"]) { 9 | return new Promise((resolve) => setTimeout(resolve, ms * 2)); 10 | } 11 | return new Promise((resolve) => setTimeout(resolve, ms)); 12 | } 13 | 14 | /** 15 | * @param {string} path 16 | * @returns {import('vscode').Uri} 17 | */ 18 | function getDocUri(path) { 19 | return vscode.Uri.from({ 20 | scheme: "vscode-test-web", 21 | authority: "mount", 22 | path: `/${path}`, 23 | }); 24 | } 25 | 26 | /** 27 | * @param {import('vscode').Uri} docUri 28 | * @returns {Promise} 29 | */ 30 | async function showFile(docUri) { 31 | const doc = await vscode.workspace.openTextDocument(docUri); 32 | return vscode.window.showTextDocument(doc); 33 | } 34 | 35 | /** 36 | * Line and Char as shown in lowerright of VS Code 37 | * 38 | * @param {number} char 39 | * @param {number} line 40 | * @returns {import('vscode').Position} 41 | */ 42 | function position(line, char) { 43 | return new vscode.Position(line - 1, char - 1); 44 | } 45 | 46 | /** 47 | * @param {number} line 48 | * @param {number} startChar 49 | * @param {number} endChar 50 | * @returns {import('vscode').Range} 51 | */ 52 | function sameLineRange(line, startChar, endChar) { 53 | return new vscode.Range(position(line, startChar), position(line, endChar)); 54 | } 55 | 56 | /** 57 | * @param {import('vscode').Uri} uri 58 | * @param {number} line 59 | * @param {number} startChar 60 | * @param {number} endChar 61 | * @returns {import('vscode').Location} 62 | */ 63 | function sameLineLocation(uri, line, startChar, endChar) { 64 | return new vscode.Location(uri, sameLineRange(line, startChar, endChar)); 65 | } 66 | 67 | module.exports = { 68 | sleep, 69 | showFile, 70 | getDocUri, 71 | position, 72 | sameLineLocation, 73 | sameLineRange, 74 | }; 75 | -------------------------------------------------------------------------------- /vscode-extension/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2020", 4 | "lib": ["ES2020", "WebWorker"], 5 | "sourceMap": true, 6 | "module": "commonjs", 7 | "moduleResolution": "node", 8 | "rootDir": ".", 9 | "outDir": "out", 10 | "strict": true, 11 | "resolveJsonModule": true 12 | } 13 | } 14 | --------------------------------------------------------------------------------