Skip to content

Commit a4e28f3

Browse files
feat: add JSDoc type-checking and declaration emission (#1312)
1 parent a3db95b commit a4e28f3

11 files changed

Lines changed: 1668 additions & 798 deletions

File tree

.changeset/curvy-schools-cover.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"sass-loader": minor
3+
---
4+
5+
Added types.

package-lock.json

Lines changed: 115 additions & 86 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
"type": "module",
2121
"exports": {
2222
".": {
23+
"types": "./types/index.d.ts",
2324
"import": "./dist/esm/index.js",
2425
"require": "./dist/cjs/index.js",
2526
"default": "./dist/esm/index.js"
@@ -28,19 +29,23 @@
2829
},
2930
"main": "./dist/cjs/index.js",
3031
"module": "./dist/esm/index.js",
32+
"types": "./types/index.d.ts",
3133
"files": [
32-
"dist"
34+
"dist",
35+
"types"
3336
],
3437
"scripts": {
35-
"clean": "del-cli dist",
38+
"clean": "del-cli dist types",
3639
"prebuild": "npm run clean",
3740
"build:esm": "babel src -d dist/esm --env-name esm --copy-files --no-copy-ignored",
3841
"build:cjs": "babel src -d dist/cjs --env-name cjs --copy-files --no-copy-ignored && node -e \"const fs=require('fs');fs.writeFileSync('dist/cjs/package.json','{\\\"type\\\":\\\"commonjs\\\"}\\n');fs.appendFileSync('dist/cjs/index.js','module.exports = exports.default;\\nmodule.exports.default = exports.default;\\n')\"",
42+
"build:types": "tsc && prettier \"types/**/*.ts\" --write",
3943
"build": "npm-run-all -p \"build:*\"",
4044
"security": "npm audit --production",
4145
"lint": "npm-run-all -l -p \"lint:**\" && npm run fmt:check",
4246
"lint:code": "eslint --cache .",
4347
"lint:spelling": "cspell --cache --no-must-find-files --quiet \"**/*.*\"",
48+
"lint:types": "tsc --pretty --noEmit",
4449
"fmt": "npm run fmt:check -- --write",
4550
"fmt:check": "prettier --list-different --cache --ignore-unknown .",
4651
"fix": "npm run fix:code && npm run fmt",
@@ -60,6 +65,7 @@
6065
"@babel/preset-env": "^7.28.6",
6166
"@changesets/cli": "^2.30.0",
6267
"@changesets/get-github-info": "^0.8.0",
68+
"@types/node": "^22.3.0",
6369
"bootstrap-sass": "^3.4.1",
6470
"bootstrap-v4": "npm:bootstrap@^4.5.3",
6571
"bootstrap-v5": "npm:bootstrap@^5.3.7",
@@ -78,10 +84,10 @@
7884
"memfs": "^4.57.2",
7985
"npm-run-all": "^4.1.5",
8086
"prettier": "^3.8.3",
81-
"sass": "^1.89.2",
82-
"sass-embedded": "^1.89.2",
87+
"sass": "^1.99.0",
88+
"sass-embedded": "^1.99.0",
8389
"style-loader": "^3.3.4",
84-
"typescript": "^5.9.2",
90+
"typescript": "^6.0.3",
8591
"webpack": "^5.106.2"
8692
},
8793
"peerDependencies": {

src/index.js

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -11,35 +11,39 @@ import {
1111
normalizeSourceMap,
1212
} from "./utils.js";
1313

14-
// eslint-disable-next-line jsdoc/reject-any-type
15-
/** @typedef {any} EXPECTED_ANY */
14+
/** @typedef {import("webpack").LoaderContext<LoaderOptions>} LoaderContext */
15+
/** @typedef {import("schema-utils/declarations/validate").Schema} Schema */
16+
/** @typedef {import("./utils.js").LoaderOptions} LoaderOptions */
17+
/** @typedef {import("./utils.js").SassError} SassError */
1618

1719
/**
1820
* The sass-loader makes dart-sass and sass-embedded available to webpack modules.
19-
* @this {LoaderContext<{ string: EXPECTED_ANY }>}
21+
* @this {LoaderContext}
2022
* @param {string} content content
23+
* @returns {Promise<void>} loader result
2124
*/
2225
async function loader(content) {
23-
const options = this.getOptions(schema);
26+
const options = this.getOptions(/** @type {Schema} */ (schema));
2427
const callback = this.async();
2528

2629
let implementation;
2730

2831
try {
29-
implementation = await getSassImplementation(this, options.implementation);
32+
implementation = await getSassImplementation(options.implementation);
3033
} catch (error) {
31-
callback(error);
34+
callback(/** @type {Error} */ (error));
3235

3336
return;
3437
}
3538

3639
const useSourceMap =
37-
typeof options.sourceMap === "boolean" ? options.sourceMap : this.sourceMap;
40+
typeof options.sourceMap === "boolean"
41+
? options.sourceMap
42+
: this.sourceMap === true;
3843
const sassOptions = await getSassOptions(
3944
this,
4045
options,
4146
content,
42-
implementation,
4347
useSourceMap,
4448
);
4549

@@ -49,18 +53,15 @@ async function loader(content) {
4953
: true;
5054

5155
if (shouldUseWebpackImporter) {
52-
sassOptions.importers.push(
53-
// No need to pass `loadPaths`, because modern API handle them itself
54-
getModernWebpackImporter(this, implementation, []),
55-
);
56+
sassOptions.importers.push(getModernWebpackImporter(this));
5657
}
5758

5859
let compile;
5960

6061
try {
6162
compile = getCompileFn(this, implementation, options.api);
6263
} catch (error) {
63-
callback(error);
64+
callback(/** @type {Error} */ (error));
6465
return;
6566
}
6667

@@ -69,17 +70,19 @@ async function loader(content) {
6970
try {
7071
result = await compile(sassOptions);
7172
} catch (error) {
73+
const sassError = /** @type {SassError} */ (error);
74+
7275
// There are situations when the `span.url` property does not exist
73-
if (error.span && typeof error.span.url !== "undefined") {
74-
this.addDependency(url.fileURLToPath(error.span.url));
76+
if (sassError.span && typeof sassError.span.url !== "undefined") {
77+
this.addDependency(url.fileURLToPath(sassError.span.url));
7578
}
7679

77-
callback(errorFactory(error));
80+
callback(errorFactory(sassError));
7881

7982
return;
8083
}
8184

82-
let map = result.sourceMap || null;
85+
let map = result.sourceMap || undefined;
8386

8487
// Modify source paths only for webpack, otherwise we do nothing
8588
if (map && useSourceMap) {
@@ -99,7 +102,7 @@ async function loader(content) {
99102
}
100103
}
101104

102-
callback(null, result.css.toString(), map);
105+
callback(null, result.css.toString(), map || undefined);
103106
}
104107

105108
export default loader;

0 commit comments

Comments
 (0)