Skip to content

Commit 3710653

Browse files
refactor: adding typescript jsdocs types (#710)
* refactor: adding typescript jsdocs types * lint: fix * test: fix
1 parent 77599a4 commit 3710653

28 files changed

+1122
-149
lines changed

client/components/ContextMenu.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ export default class ContextMenu extends PureComponent {
107107
/**
108108
* Handle document-wide `mousedown` events to detect clicks
109109
* outside the context menu.
110-
* @param {MouseEvent} event - DOM mouse event object
110+
* @param {MouseEvent} event DOM mouse event object
111111
* @returns {void}
112112
*/
113113
handleDocumentMousedown = (event) => {

client/components/ContextMenuItem.jsx

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,24 @@ import PropTypes from "prop-types";
33

44
import * as styles from "./ContextMenuItem.css";
55

6+
/**
7+
* @returns {boolean} nothing
8+
*/
69
function noop() {
710
return false;
811
}
912

13+
/**
14+
* @typedef {object} ContextMenuItemProps
15+
* @property {React.ReactNode} children children
16+
* @property {boolean=} disabled - true when disabled, otherwise false
17+
* @property {React.MouseEventHandler<HTMLLIElement>=} onClick on click handler
18+
*/
19+
20+
/**
21+
* @param {ContextMenuItemProps} props props
22+
* @returns {JSX.Element} context menu item
23+
*/
1024
export default function ContextMenuItem({ children, disabled, onClick }) {
1125
const className = cls({
1226
[styles.item]: true,

client/components/ModulesTreemap.jsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@ import Switcher from "./Switcher.jsx";
1818
import Tooltip from "./Tooltip.jsx";
1919
import Treemap from "./Treemap.jsx";
2020

21+
/** @typedef {"statSize" | "parsedSize" | "gzipSize" | "brotliSize" | "zstdSize"} PropSize */
22+
23+
/**
24+
* @returns {{ label: string, prop: PropSize }[]} sizes
25+
*/
2126
function getSizeSwitchItems() {
2227
const items = [
2328
{ label: "Stat", prop: "statSize" },

client/components/Treemap.jsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,17 @@ import { Component } from "preact";
33
import PropTypes from "prop-types";
44
import { SizeType, ViewerDataType } from "./types.js";
55

6+
/**
7+
* @param {Event} event event
8+
*/
69
function preventDefault(event) {
710
event.preventDefault();
811
}
912

13+
/**
14+
* @param {string} str string
15+
* @returns {number} hash
16+
*/
1017
function hashCode(str) {
1118
let hash = 0;
1219
for (let i = 0; i < str.length; i++) {
@@ -133,8 +140,7 @@ export default class Treemap extends Component {
133140
},
134141
/**
135142
* Handle Foamtree's "group clicked" event
136-
* @param {FoamtreeEvent} event - Foamtree event object
137-
* (see https://get.carrotsearch.com/foamtree/demo/api/index.html#event-details)
143+
* @param {FoamtreeEvent} event foamtree event object (see https://get.carrotsearch.com/foamtree/demo/api/index.html#event-details)
138144
* @returns {void}
139145
*/
140146
onGroupClick(event) {

client/lib/PureComponent.jsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
import { Component } from "preact";
22

3+
/**
4+
* @param {object} obj1 obj1
5+
* @param {object} obj2 obj2
6+
* @returns {boolean} true when the same, otherwise false
7+
*/
38
function isEqual(obj1, obj2) {
49
if (obj1 === obj2) return true;
510
const keys = Object.keys(obj1);

client/utils.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,16 @@
1+
/**
2+
* @param {Chunk} chunk chunk
3+
* @returns {boolean} true when chunk is parser, otherwise false
4+
*/
15
export function isChunkParsed(chunk) {
26
return typeof chunk.parsedSize === "number";
37
}
48

9+
/**
10+
* @param {Module[]} modules modules
11+
* @param {(module: Module) => boolean} cb callback
12+
* @returns {boolean} state
13+
*/
514
export function walkModules(modules, cb) {
615
for (const module of modules) {
716
if (cb(module) === false) return false;
@@ -12,6 +21,12 @@ export function walkModules(modules, cb) {
1221
}
1322
}
1423

24+
/**
25+
* @template T
26+
* @param {T} elem element
27+
* @param {T[]} container container
28+
* @returns {boolean} true when element is outside, otherwise false
29+
*/
1530
export function elementIsOutside(elem, container) {
1631
return !(elem === container || container.contains(elem));
1732
}

package-lock.json

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

package.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,9 @@
4040
"watch:analyzer": "npm run build:analyzer -- --watch",
4141
"watch:viewer": "npm run build:viewer -- --node-env=development --watch",
4242
"npm-publish": "npm run lint && npm run build && npm test && npm publish",
43-
"lint": "npm run lint:code && npm run fmt:check",
43+
"lint": "npm run lint:code && npm run lint:types && npm run fmt:check",
4444
"lint:code": "eslint --cache .",
45+
"lint:types": "tsc --pretty --noEmit",
4546
"fmt": "npm run fmt:base -- --log-level warn --write",
4647
"fmt:check": "npm run fmt:base -- --check",
4748
"fmt:base": "prettier --cache --ignore-unknown .",
@@ -71,6 +72,8 @@
7172
"@babel/preset-react": "^7.26.3",
7273
"@babel/runtime": "^7.26.9",
7374
"@carrotsearch/foamtree": "^3.5.0",
75+
"@types/html-escaper": "^3.0.4",
76+
"@types/opener": "^1.4.3",
7477
"autoprefixer": "^10.2.5",
7578
"babel-eslint": "^10.1.0",
7679
"babel-loader": "^10.0.0",
@@ -95,6 +98,7 @@
9598
"style-loader": "^4.0.0",
9699
"terser-webpack-plugin": "^5.1.2",
97100
"tinyglobby": "^0.2.15",
101+
"typescript": "^5.9.3",
98102
"webpack": "^5.105.2",
99103
"webpack-4": "npm:webpack@^4",
100104
"webpack-cli": "^6.0.1",

src/BundleAnalyzerPlugin.js

Lines changed: 92 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,54 @@ const { writeStats } = require("./statsUtils");
77
const utils = require("./utils");
88
const viewer = require("./viewer");
99

10+
/** @typedef {import("net").AddressInfo} AddressInfo */
11+
/** @typedef {import("webpack").Compiler} Compiler */
12+
/** @typedef {import("webpack").OutputFileSystem} OutputFileSystem */
13+
/** @typedef {import("webpack").Stats} Stats */
14+
/** @typedef {import("webpack").StatsOptions} StatsOptions */
15+
/** @typedef {import("webpack").StatsAsset} StatsAsset */
16+
/** @typedef {import("webpack").StatsCompilation} StatsCompilation */
17+
/** @typedef {import("./sizeUtils").Algorithm} CompressionAlgorithm */
18+
/** @typedef {import("./Logger").Level} LogLever */
19+
/** @typedef {import("./viewer").ViewerServerObj} ViewerServerObj */
20+
21+
/** @typedef {string | boolean | StatsOptions} PluginStatsOptions */
22+
23+
// eslint-disable-next-line jsdoc/reject-any-type
24+
/** @typedef {any} EXPECTED_ANY */
25+
26+
/** @typedef {"static" | "json" | "server" | "disabled"} Mode */
27+
/** @typedef {string | RegExp | ((asset: string) => void)} Pattern */
28+
/** @typedef {null | Pattern | Pattern[]} ExcludeAssets */
29+
/** @typedef {"stat" | "parsed" | "gzip" | "brotli" | "zstd"} Sizes */
30+
/** @typedef {string | (() => string)} ReportTitle */
31+
/** @typedef {(options: { listenHost: string, listenPort: number, boundAddress: string | AddressInfo | null }) => string} AnalyzerUrl */
32+
33+
/**
34+
* @typedef {object} Options
35+
* @property {Mode=} analyzerMode analyzer mode
36+
* @property {string=} analyzerHost analyzer host
37+
* @property {"auto" | number=} analyzerPort analyzer port
38+
* @property {CompressionAlgorithm=} compressionAlgorithm compression algorithm
39+
* @property {string | null=} reportFilename report filename
40+
* @property {ReportTitle=} reportTitle report title
41+
* @property {Sizes=} defaultSizes default sizes
42+
* @property {boolean=} openAnalyzer open analyzer
43+
* @property {boolean=} generateStatsFile generate stats file
44+
* @property {string=} statsFilename stats filename
45+
* @property {PluginStatsOptions=} statsOptions stats options
46+
* @property {ExcludeAssets=} excludeAssets exclude assets
47+
* @property {LogLever=} logLevel exclude assets
48+
* @property {boolean=} startAnalyzer start analyzer
49+
* @property {AnalyzerUrl=} analyzerUrl start analyzer
50+
*/
51+
1052
class BundleAnalyzerPlugin {
53+
/**
54+
* @param {Options=} opts options
55+
*/
1156
constructor(opts = {}) {
57+
/** @type {Required<Omit<Options, "analyzerPort" | "statsOptions">> & { analyzerPort: number, statsOptions: undefined | PluginStatsOptions }} */
1258
this.opts = {
1359
analyzerMode: "server",
1460
analyzerHost: "127.0.0.1",
@@ -19,31 +65,38 @@ class BundleAnalyzerPlugin {
1965
openAnalyzer: true,
2066
generateStatsFile: false,
2167
statsFilename: "stats.json",
22-
statsOptions: null,
68+
statsOptions: undefined,
2369
excludeAssets: null,
2470
logLevel: "info",
25-
// deprecated
71+
// TODO deprecated
2672
startAnalyzer: true,
2773
analyzerUrl: utils.defaultAnalyzerUrl,
2874
...opts,
2975
analyzerPort:
30-
"analyzerPort" in opts
31-
? opts.analyzerPort === "auto"
32-
? 0
33-
: opts.analyzerPort
34-
: 8888,
76+
opts.analyzerPort === "auto" ? 0 : (opts.analyzerPort ?? 8888),
3577
};
3678

79+
/** @type {Compiler | null} */
80+
this.compiler = null;
81+
/** @type {Promise<ViewerServerObj> | null} */
3782
this.server = null;
3883
this.logger = new Logger(this.opts.logLevel);
3984
}
4085

86+
/**
87+
* @param {Compiler} compiler compiler
88+
*/
4189
apply(compiler) {
4290
this.compiler = compiler;
4391

92+
/**
93+
* @param {Stats} stats stats
94+
* @param {(err?: Error) => void} callback callback
95+
*/
4496
const done = (stats, callback) => {
4597
callback ||= () => {};
4698

99+
/** @type {(() => Promise<void>)[]} */
47100
const actions = [];
48101

49102
if (this.opts.generateStatsFile) {
@@ -72,7 +125,7 @@ class BundleAnalyzerPlugin {
72125
await Promise.all(actions.map((action) => action()));
73126
callback();
74127
} catch (err) {
75-
callback(err);
128+
callback(/** @type {Error} */ (err));
76129
}
77130
});
78131
} else {
@@ -83,13 +136,19 @@ class BundleAnalyzerPlugin {
83136
if (compiler.hooks) {
84137
compiler.hooks.done.tapAsync("webpack-bundle-analyzer", done);
85138
} else {
139+
// @ts-expect-error old webpack@4 API
86140
compiler.plugin("done", done);
87141
}
88142
}
89143

144+
/**
145+
* @param {StatsCompilation} stats stats
146+
* @returns {Promise<void>}
147+
*/
90148
async generateStatsFile(stats) {
91149
const statsFilepath = path.resolve(
92-
this.compiler.outputPath,
150+
/** @type {Compiler} */
151+
(this.compiler).outputPath,
93152
this.opts.statsFilename,
94153
);
95154
await fs.promises.mkdir(path.dirname(statsFilepath), { recursive: true });
@@ -107,6 +166,10 @@ class BundleAnalyzerPlugin {
107166
}
108167
}
109168

169+
/**
170+
* @param {StatsCompilation} stats stats
171+
* @returns {Promise<void>}
172+
*/
110173
async startAnalyzerServer(stats) {
111174
if (this.server) {
112175
(await this.server).updateChartData(stats);
@@ -126,10 +189,15 @@ class BundleAnalyzerPlugin {
126189
}
127190
}
128191

192+
/**
193+
* @param {StatsCompilation} stats stats
194+
* @returns {Promise<void>}
195+
*/
129196
async generateJSONReport(stats) {
130197
await viewer.generateJSONReport(stats, {
131198
reportFilename: path.resolve(
132-
this.compiler.outputPath,
199+
/** @type {Compiler} */
200+
(this.compiler).outputPath,
133201
this.opts.reportFilename || "report.json",
134202
),
135203
compressionAlgorithm: this.opts.compressionAlgorithm,
@@ -139,11 +207,16 @@ class BundleAnalyzerPlugin {
139207
});
140208
}
141209

210+
/**
211+
* @param {StatsCompilation} stats stats
212+
* @returns {Promise<void>}
213+
*/
142214
async generateStaticReport(stats) {
143215
await viewer.generateReport(stats, {
144216
openBrowser: this.opts.openAnalyzer,
145217
reportFilename: path.resolve(
146-
this.compiler.outputPath,
218+
/** @type {Compiler} */
219+
(this.compiler).outputPath,
147220
this.opts.reportFilename || "report.html",
148221
),
149222
reportTitle: this.opts.reportTitle,
@@ -156,18 +229,22 @@ class BundleAnalyzerPlugin {
156229
}
157230

158231
getBundleDirFromCompiler() {
159-
if (typeof this.compiler.outputFileSystem.constructor === "undefined") {
160-
return this.compiler.outputPath;
232+
const outputFileSystemConstructor =
233+
/** @type {OutputFileSystem} */
234+
(/** @type {Compiler} */ (this.compiler).outputFileSystem).constructor;
235+
236+
if (typeof outputFileSystemConstructor === "undefined") {
237+
return /** @type {Compiler} */ (this.compiler).outputPath;
161238
}
162-
switch (this.compiler.outputFileSystem.constructor.name) {
239+
switch (outputFileSystemConstructor.name) {
163240
case "MemoryFileSystem":
164241
return null;
165242
// Detect AsyncMFS used by Nuxt 2.5 that replaces webpack's MFS during development
166243
// Related: #274
167244
case "AsyncMFS":
168245
return null;
169246
default:
170-
return this.compiler.outputPath;
247+
return /** @type {Compiler} */ (this.compiler).outputPath;
171248
}
172249
}
173250
}

0 commit comments

Comments
 (0)