From 7037bb8ec258a8c79b7fb991e01ecd55a5099b40 Mon Sep 17 00:00:00 2001 From: Jonny Gerig Meyer Date: Thu, 22 Feb 2024 14:53:22 -0500 Subject: [PATCH] Add option to specify sass implementation to use --- CHANGELOG.md | 3 + package.json | 4 +- src/index.ts | 35 +++++-- test/main.test.js | 66 ++++++++++++- test/sass.test.js | 2 +- yarn.lock | 241 +++++++++++++++++++++++++++++++++++++++++++++- 6 files changed, 334 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c3b6379..a376081 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,10 @@ ## 8.0.0-beta.0 (unreleased) +- FEATURE: Add True `sass` option (`string` or Sass implementation instance, + defaults to `'sass'`) to allow using either `sass` or `embedded-sass`. - BREAKING: Drop support for node < 18 +- INTERNAL: Remove `sass` as a peer-dependency. - INTERNAL: Update dependencies ## 7.0.1 (01/04/24) diff --git a/package.json b/package.json index 59803b8..6d22062 100644 --- a/package.json +++ b/package.json @@ -63,9 +63,6 @@ "release": "run-s commit docs", "prepack": "yarn run release" }, - "peerDependencies": { - "sass": ">=1.45.0" - }, "dependencies": { "@adobe/css-tools": "^4.3.3", "jest-diff": "^29.7.0", @@ -92,6 +89,7 @@ "postcss": "^8.4.35", "prettier": "^3.2.5", "sass": "^1.71.1", + "sass-embedded": "^1.71.1", "sassdoc": "^2.7.4", "sassdoc-theme-herman": "^5.0.1", "stylelint": "^16.2.1", diff --git a/src/index.ts b/src/index.ts index a40da60..cf75bfa 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,8 @@ -/* eslint-disable @typescript-eslint/no-use-before-define */ /* eslint-disable no-use-before-define */ +/* eslint-disable @typescript-eslint/no-use-before-define */ + +import assert from 'node:assert'; +import path from 'node:path'; import { CssAtRuleAST, @@ -9,12 +12,8 @@ import { parse as cssParse, stringify as cssStringify, } from '@adobe/css-tools'; -import * as assert from 'assert'; import { diffStringsUnified } from 'jest-diff'; import { find, forEach, last, startsWith } from 'lodash'; -import * as path from 'path'; -import type { Options, StringOptions } from 'sass'; -import { compile, compileString } from 'sass'; import * as constants from './constants'; import { @@ -28,6 +27,7 @@ import { export interface TrueOptions { describe: (description: string, fn: () => void) => void; it: (description: string, fn: () => void) => void; + sass?: any; sourceType?: 'path' | 'string'; contextLines?: number; } @@ -69,7 +69,7 @@ export type Parser = (rule: Rule, ctx: Context) => Parser; export const runSass = function ( trueOptions: TrueOptions, src: string, - sassOptions?: Options<'sync'> | StringOptions<'sync'>, + sassOptions?: any, ) { const trueOpts = Object.assign({}, trueOptions); const sassOpts = Object.assign({}, sassOptions); @@ -83,12 +83,29 @@ export const runSass = function ( // Warn if arguments match v6 API if (typeof src !== 'string' || !trueOptions.describe || !trueOptions.it) { throw new Error( - 'The arguments provided to `runSass` do not match the new API introduced in True v7. Refer to the v7 release notes for migration documentation: https://github.com/oddbird/true/releases/tag/v7.0.0', + 'The arguments provided to `runSass` do not match the new API ' + + 'introduced in True v7. Refer to the v7 release notes ' + + 'for migration documentation: ' + + 'https://github.com/oddbird/true/releases/tag/v7.0.0', ); } - const compiler = trueOpts.sourceType === 'string' ? compileString : compile; - const parsedCss = compiler(src, sassOpts).css; + let compiler; + if (trueOpts.sass && typeof trueOpts.sass !== 'string') { + compiler = trueOpts.sass; + } else { + const sassPkg = trueOpts.sass ?? 'sass'; + try { + // eslint-disable-next-line global-require + compiler = require(sassPkg); + } catch (err) { + throw new Error(`Cannot find Dart Sass (\`${sassPkg}\`) dependency.`); + } + } + + const compilerFn = + trueOpts.sourceType === 'string' ? 'compileString' : 'compile'; + const parsedCss = compiler[compilerFn](src, sassOpts).css; const modules = parse(parsedCss, trueOpts.contextLines); forEach(modules, (module) => { diff --git a/test/main.test.js b/test/main.test.js index d6cd184..5003a57 100644 --- a/test/main.test.js +++ b/test/main.test.js @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/no-var-requires */ /* eslint-disable global-require */ -const path = require('path'); +const path = require('node:path'); const { expect } = require('chai'); const { diffStringsUnified } = require('jest-diff'); @@ -114,6 +114,70 @@ describe('#runSass', () => { }; expect(attempt).not.to.throw(); }); + + it('can specify sass implementation to use [string]', () => { + const sass = [ + '@use "true" as *;', + '@include test-module("Module") {', + ' @include test("Test") {', + ' @include assert("Assertion") {', + ' @include output() {', + ' -property: value;', + ' }', + ' @include expect() {', + ' -property: value;', + ' }', + ' }', + ' }', + '}', + ].join('\n'); + const mock = function (name, cb) { + cb(); + }; + const attempt = function () { + sassTrue.runSass( + { + describe: mock, + it: mock, + sourceType: 'string', + sass: 'sass-embedded', + }, + sass, + ); + }; + expect(attempt).not.to.throw(); + }); + + it('can specify sass implementation to use [object]', () => { + const mock = function (name, cb) { + cb(); + }; + const attempt = function () { + sassTrue.runSass( + { + describe: mock, + it: mock, + sass: { + compile() { + throw new Error('Custom sass implementation called'); + }, + }, + }, + '', + ); + }; + expect(attempt).to.throw('Custom sass implementation called'); + }); + + it('throws if sass implementation is not found', () => { + const mock = function (name, cb) { + cb(); + }; + const attempt = function () { + sassTrue.runSass({ describe: mock, it: mock, sass: 'foobar' }, ''); + }; + expect(attempt).to.throw('Cannot find Dart Sass (`foobar`) dependency.'); + }); }); describe('#parse', () => { diff --git a/test/sass.test.js b/test/sass.test.js index 11e4d4e..695a365 100644 --- a/test/sass.test.js +++ b/test/sass.test.js @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/no-var-requires */ /* eslint-disable global-require */ -const path = require('path'); +const path = require('node:path'); const sassFile = path.join(__dirname, 'scss', 'test.scss'); let runSass; diff --git a/yarn.lock b/yarn.lock index 9e31010..0486027 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1485,6 +1485,13 @@ __metadata: languageName: node linkType: hard +"@bufbuild/protobuf@npm:^1.0.0": + version: 1.7.2 + resolution: "@bufbuild/protobuf@npm:1.7.2" + checksum: 10/f23ccc77066100157043cf36bd2506acdcb235f0a902f7662fbbb992e78df4202780aeb55bd2e3fd1945bd9e52a4fca759351f333f2ff779e32996e13eb56d34 + languageName: node + linkType: hard + "@csstools/css-parser-algorithms@npm:^2.5.0": version: 2.6.0 resolution: "@csstools/css-parser-algorithms@npm:2.6.0" @@ -2896,6 +2903,13 @@ __metadata: languageName: node linkType: hard +"buffer-builder@npm:^0.2.0": + version: 0.2.0 + resolution: "buffer-builder@npm:0.2.0" + checksum: 10/16bd9eb8ac6630a05441bcb56522e956ae6a0724371ecc49b9a6bc10d35690489140df73573d0577e1e85c875737e560a4e2e67521fddd14714ddf4e0097d0ec + languageName: node + linkType: hard + "buffer-equal@npm:^1.0.0": version: 1.0.1 resolution: "buffer-equal@npm:1.0.1" @@ -8292,6 +8306,15 @@ __metadata: languageName: node linkType: hard +"rxjs@npm:^7.4.0": + version: 7.8.1 + resolution: "rxjs@npm:7.8.1" + dependencies: + tslib: "npm:^2.1.0" + checksum: 10/b10cac1a5258f885e9dd1b70d23c34daeb21b61222ee735d2ec40a8685bdca40429000703a44f0e638c27a684ac139e1c37e835d2a0dc16f6fc061a138ae3abb + languageName: node + linkType: hard + "safe-array-concat@npm:^1.0.1": version: 1.0.1 resolution: "safe-array-concat@npm:1.0.1" @@ -8366,6 +8389,205 @@ __metadata: languageName: node linkType: hard +"sass-embedded-android-arm64@npm:1.71.1": + version: 1.71.1 + resolution: "sass-embedded-android-arm64@npm:1.71.1" + bin: + sass: dart-sass/sass + conditions: os=android & cpu=arm64 + languageName: node + linkType: hard + +"sass-embedded-android-arm@npm:1.71.1": + version: 1.71.1 + resolution: "sass-embedded-android-arm@npm:1.71.1" + bin: + sass: dart-sass/sass + conditions: os=android & cpu=arm + languageName: node + linkType: hard + +"sass-embedded-android-ia32@npm:1.71.1": + version: 1.71.1 + resolution: "sass-embedded-android-ia32@npm:1.71.1" + bin: + sass: dart-sass/sass + conditions: os=android & cpu=ia32 + languageName: node + linkType: hard + +"sass-embedded-android-x64@npm:1.71.1": + version: 1.71.1 + resolution: "sass-embedded-android-x64@npm:1.71.1" + bin: + sass: dart-sass/sass + conditions: os=android & cpu=x64 + languageName: node + linkType: hard + +"sass-embedded-darwin-arm64@npm:1.71.1": + version: 1.71.1 + resolution: "sass-embedded-darwin-arm64@npm:1.71.1" + bin: + sass: dart-sass/sass + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"sass-embedded-darwin-x64@npm:1.71.1": + version: 1.71.1 + resolution: "sass-embedded-darwin-x64@npm:1.71.1" + bin: + sass: dart-sass/sass + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"sass-embedded-linux-arm64@npm:1.71.1": + version: 1.71.1 + resolution: "sass-embedded-linux-arm64@npm:1.71.1" + bin: + sass: dart-sass/sass + conditions: os=linux & cpu=arm64 + languageName: node + linkType: hard + +"sass-embedded-linux-arm@npm:1.71.1": + version: 1.71.1 + resolution: "sass-embedded-linux-arm@npm:1.71.1" + bin: + sass: dart-sass/sass + conditions: os=linux & cpu=arm + languageName: node + linkType: hard + +"sass-embedded-linux-ia32@npm:1.71.1": + version: 1.71.1 + resolution: "sass-embedded-linux-ia32@npm:1.71.1" + bin: + sass: dart-sass/sass + conditions: os=linux & cpu=ia32 + languageName: node + linkType: hard + +"sass-embedded-linux-musl-arm64@npm:1.71.1": + version: 1.71.1 + resolution: "sass-embedded-linux-musl-arm64@npm:1.71.1" + conditions: os=linux & cpu=arm64 + languageName: node + linkType: hard + +"sass-embedded-linux-musl-arm@npm:1.71.1": + version: 1.71.1 + resolution: "sass-embedded-linux-musl-arm@npm:1.71.1" + conditions: os=linux & cpu=arm + languageName: node + linkType: hard + +"sass-embedded-linux-musl-ia32@npm:1.71.1": + version: 1.71.1 + resolution: "sass-embedded-linux-musl-ia32@npm:1.71.1" + conditions: os=linux & cpu=ia32 + languageName: node + linkType: hard + +"sass-embedded-linux-musl-x64@npm:1.71.1": + version: 1.71.1 + resolution: "sass-embedded-linux-musl-x64@npm:1.71.1" + conditions: os=linux & cpu=x64 + languageName: node + linkType: hard + +"sass-embedded-linux-x64@npm:1.71.1": + version: 1.71.1 + resolution: "sass-embedded-linux-x64@npm:1.71.1" + bin: + sass: dart-sass/sass + conditions: os=linux & cpu=x64 + languageName: node + linkType: hard + +"sass-embedded-win32-ia32@npm:1.71.1": + version: 1.71.1 + resolution: "sass-embedded-win32-ia32@npm:1.71.1" + bin: + sass: dart-sass/sass.bat + conditions: os=win32 & cpu=ia32 + languageName: node + linkType: hard + +"sass-embedded-win32-x64@npm:1.71.1": + version: 1.71.1 + resolution: "sass-embedded-win32-x64@npm:1.71.1" + bin: + sass: dart-sass/sass.bat + conditions: os=win32 & (cpu=arm64 | cpu=x64) + languageName: node + linkType: hard + +"sass-embedded@npm:^1.71.1": + version: 1.71.1 + resolution: "sass-embedded@npm:1.71.1" + dependencies: + "@bufbuild/protobuf": "npm:^1.0.0" + buffer-builder: "npm:^0.2.0" + immutable: "npm:^4.0.0" + rxjs: "npm:^7.4.0" + sass-embedded-android-arm: "npm:1.71.1" + sass-embedded-android-arm64: "npm:1.71.1" + sass-embedded-android-ia32: "npm:1.71.1" + sass-embedded-android-x64: "npm:1.71.1" + sass-embedded-darwin-arm64: "npm:1.71.1" + sass-embedded-darwin-x64: "npm:1.71.1" + sass-embedded-linux-arm: "npm:1.71.1" + sass-embedded-linux-arm64: "npm:1.71.1" + sass-embedded-linux-ia32: "npm:1.71.1" + sass-embedded-linux-musl-arm: "npm:1.71.1" + sass-embedded-linux-musl-arm64: "npm:1.71.1" + sass-embedded-linux-musl-ia32: "npm:1.71.1" + sass-embedded-linux-musl-x64: "npm:1.71.1" + sass-embedded-linux-x64: "npm:1.71.1" + sass-embedded-win32-ia32: "npm:1.71.1" + sass-embedded-win32-x64: "npm:1.71.1" + supports-color: "npm:^8.1.1" + varint: "npm:^6.0.0" + dependenciesMeta: + sass-embedded-android-arm: + optional: true + sass-embedded-android-arm64: + optional: true + sass-embedded-android-ia32: + optional: true + sass-embedded-android-x64: + optional: true + sass-embedded-darwin-arm64: + optional: true + sass-embedded-darwin-x64: + optional: true + sass-embedded-linux-arm: + optional: true + sass-embedded-linux-arm64: + optional: true + sass-embedded-linux-ia32: + optional: true + sass-embedded-linux-musl-arm: + optional: true + sass-embedded-linux-musl-arm64: + optional: true + sass-embedded-linux-musl-ia32: + optional: true + sass-embedded-linux-musl-x64: + optional: true + sass-embedded-linux-x64: + optional: true + sass-embedded-win32-ia32: + optional: true + sass-embedded-win32-x64: + optional: true + checksum: 10/bf4da1bf905b7de845822c915169e35c6fb9f4e9055b4042f5869b3ed7c803b13017c408b0a068279a9240b2bd464609e77744f4bd163580c23997cd67d82b91 + languageName: node + linkType: hard + "sass-true@workspace:.": version: 0.0.0-use.local resolution: "sass-true@workspace:." @@ -8393,13 +8615,12 @@ __metadata: postcss: "npm:^8.4.35" prettier: "npm:^3.2.5" sass: "npm:^1.71.1" + sass-embedded: "npm:^1.71.1" sassdoc: "npm:^2.7.4" sassdoc-theme-herman: "npm:^5.0.1" stylelint: "npm:^16.2.1" stylelint-config-standard-scss: "npm:^13.0.0" typescript: "npm:^5.3.3" - peerDependencies: - sass: ">=1.45.0" languageName: unknown linkType: soft @@ -9101,7 +9322,7 @@ __metadata: languageName: node linkType: hard -"supports-color@npm:8.1.1, supports-color@npm:^8.0.0": +"supports-color@npm:8.1.1, supports-color@npm:^8.0.0, supports-color@npm:^8.1.1": version: 8.1.1 resolution: "supports-color@npm:8.1.1" dependencies: @@ -9328,6 +9549,13 @@ __metadata: languageName: node linkType: hard +"tslib@npm:^2.1.0": + version: 2.6.2 + resolution: "tslib@npm:2.6.2" + checksum: 10/bd26c22d36736513980091a1e356378e8b662ded04204453d353a7f34a4c21ed0afc59b5f90719d4ba756e581a162ecbf93118dc9c6be5acf70aa309188166ca + languageName: node + linkType: hard + "type-check@npm:^0.4.0, type-check@npm:~0.4.0": version: 0.4.0 resolution: "type-check@npm:0.4.0" @@ -9679,6 +9907,13 @@ __metadata: languageName: node linkType: hard +"varint@npm:^6.0.0": + version: 6.0.0 + resolution: "varint@npm:6.0.0" + checksum: 10/7684113c9d497c01e40396e50169c502eb2176203219b96e1c5ac965a3e15b4892bd22b7e48d87148e10fffe638130516b6dbeedd0efde2b2d0395aa1772eea7 + languageName: node + linkType: hard + "vinyl-fs@npm:^3.0.3": version: 3.0.3 resolution: "vinyl-fs@npm:3.0.3"