@storm-software/eslint-plugin-bun 0.0.6 → 0.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/README.md +1 -1
  2. package/dist/configs/index.d.mts +5 -0
  3. package/dist/configs/index.mjs +4 -943
  4. package/dist/configs/recommended.d.mts +5 -0
  5. package/dist/configs/recommended.mjs +33 -939
  6. package/dist/helpers/bun-workspace.d.mts +49 -0
  7. package/dist/helpers/bun-workspace.mjs +197 -244
  8. package/dist/helpers/{create-rule.d.ts → create-rule.d.mts} +6 -6
  9. package/dist/helpers/create-rule.mjs +37 -38
  10. package/dist/helpers/{iterate-dependencies.d.ts → iterate-dependencies.d.mts} +7 -7
  11. package/dist/helpers/iterate-dependencies.mjs +36 -56
  12. package/dist/index.d.mts +52 -0
  13. package/dist/index.mjs +29 -951
  14. package/dist/plugin-DfH7W_YX.mjs +20 -0
  15. package/dist/plugin.d.mts +31 -0
  16. package/dist/plugin.mjs +1 -807
  17. package/dist/rules/json-enforce-catalog.d.mts +14 -0
  18. package/dist/rules/json-enforce-catalog.mjs +102 -444
  19. package/dist/rules/json-no-duplicate-catalog-item.d.mts +8 -0
  20. package/dist/rules/json-no-duplicate-catalog-item.mjs +72 -386
  21. package/dist/rules/json-no-unused-catalog-item.d.mts +5 -0
  22. package/dist/rules/json-no-unused-catalog-item.mjs +70 -423
  23. package/dist/rules/json-valid-catalog.d.mts +11 -0
  24. package/dist/rules/json-valid-catalog.mjs +80 -422
  25. package/package.json +17 -23
  26. package/dist/configs/index.d.ts +0 -5
  27. package/dist/configs/recommended.d.ts +0 -5
  28. package/dist/helpers/bun-workspace.d.ts +0 -48
  29. package/dist/index.d.ts +0 -58
  30. package/dist/plugin.d.ts +0 -33
  31. package/dist/rules/json-enforce-catalog.d.ts +0 -18
  32. package/dist/rules/json-no-duplicate-catalog-item.d.ts +0 -12
  33. package/dist/rules/json-no-unused-catalog-item.d.ts +0 -7
  34. package/dist/rules/json-valid-catalog.d.ts +0 -15
@@ -1,939 +1,33 @@
1
- import parserJsonc from 'jsonc-eslint-parser';
2
- import defu from 'defu';
3
- import fs from 'node:fs';
4
- import process from 'node:process';
5
- import { findUpSync } from 'find-up-simple';
6
- import { normalize, resolve, dirname } from 'pathe';
7
- import { globSync } from 'tinyglobby';
8
-
9
- // ../package-constants/src/globs.ts
10
- var GLOB_EXCLUDE = [
11
- "**/.git",
12
- "**/node_modules",
13
- "**/dist",
14
- "**/tmp",
15
- "**/coverage",
16
- "**/bench",
17
- "**/__snapshots__",
18
- "**/__test__",
19
- "**/__mocks__",
20
- "**/__generated__",
21
- "**/.wrangler",
22
- "**/.rolldown",
23
- "**/.docusaurus",
24
- "**/.tamagui",
25
- "**/tamagui.css",
26
- "**/.nx",
27
- "**/.next",
28
- "**/.storm",
29
- "**/.powerlines",
30
- "**/.shell-shock",
31
- "**/.earthquake",
32
- "**/.aftershock",
33
- "**/workbox*.js",
34
- "**/sw*.js",
35
- "**/service-worker.js",
36
- "**/fallback*.js",
37
- "**/ios",
38
- "**/.android",
39
- "**/.DS_Store",
40
- "**/Thumbs.db",
41
- "**/.cspellcache",
42
- "**/package-lock.*",
43
- "**/npm-lock.*",
44
- "**/pnpm-lock.*",
45
- "**/bun.lockb",
46
- "**/cargo.lock",
47
- "**/next-env.d.ts",
48
- "**/CODEOWNERS",
49
- "**/yarn.lock",
50
- "**/jest.preset.{js,ts,cjs,cts,mjs,mts,json}",
51
- "**/vitest.preset.{js,ts,cjs,cts,mjs,mts,json}",
52
- "**/jest.config.{js,ts,cjs,cts,mjs,mts,json}",
53
- "**/vitest.config.{js,ts,cjs,cts,mjs,mts,json}",
54
- "**/vitest.workspace.{js,ts,cjs,cts,mjs,mts,json}",
55
- "**/*.spec.{ts,tsx}",
56
- "**/*.test.{ts,tsx}",
57
- "**/temp",
58
- "**/.temp",
59
- "**/.output",
60
- "**/.history",
61
- "**/.vitepress/cache",
62
- "**/.nuxt",
63
- "**/.svelte-kit",
64
- "**/.vercel",
65
- "**/.changeset",
66
- "**/.idea",
67
- "**/.cache",
68
- "**/.vite-inspect",
69
- "**/.yarn",
70
- "**/*.min.*",
71
- "**/CHANGELOG*.md",
72
- "**/CONTRIBUTING.md",
73
- "**/SECURITY.md",
74
- "**/CODE_OF_CONDUCT.md",
75
- "**/PULL_REQUEST_TEMPLATE.md",
76
- "**/LICENSE*",
77
- "**/auto-import?(s).d.ts",
78
- "**/components.d.ts",
79
- "**/vite.config.*.timestamp-*",
80
- "**/webpack.config.*.timestamp-*",
81
- "**/rollup.config.*.timestamp-*",
82
- "**/nx/**/schema.d.ts",
83
- "**/nx/**/schema.json",
84
- "**/nx/**/schema.md",
85
- "**/nx/**/*.schema.d.ts",
86
- "**/nx/**/*.schema.json",
87
- "**/nx/**/*.schema.md",
88
- "**/nx/**/generators/**/files",
89
- ".agents/**/*",
90
- "**/.agents/**/*",
91
- ".claude/**/*",
92
- "**/.claude/**/*",
93
- ".codex/**/*",
94
- "**/.codex/**/*",
95
- ".cursor/**/*",
96
- "**/.cursor/**/*",
97
- ".opencode/**/*",
98
- "**/.opencode/**/*",
99
- ".nx/**/*",
100
- "**/.nx/**/*"
101
- ];
102
-
103
- // package.json
104
- var package_default = {
105
- version: "0.0.5"};
106
- function RuleCreator(urlCreator) {
107
- return function createNamedRule({
108
- name,
109
- meta,
110
- ...rule
111
- }) {
112
- return createRuleInfo({
113
- meta: {
114
- ...meta,
115
- docs: {
116
- ...meta.docs,
117
- url: urlCreator(name)
118
- }
119
- },
120
- ...rule
121
- });
122
- };
123
- }
124
- function createRuleInfo({
125
- create,
126
- defaultOptions,
127
- meta
128
- }) {
129
- return {
130
- create: ((context) => {
131
- const optionsWithDefault = context.options.map((options, index) => {
132
- return defu(defaultOptions?.[index] ?? {}, options);
133
- });
134
- return create(context, optionsWithDefault);
135
- }),
136
- defaultOptions: defaultOptions ?? {},
137
- meta
138
- };
139
- }
140
- var createRule = RuleCreator(
141
- (ruleName) => `https://docs.stormsoftware.com/projects/storm-ops/eslint-plugin-bun/rules/${ruleName}.md`
142
- );
143
- function isWorkspaceObject(workspaces) {
144
- return Boolean(workspaces) && typeof workspaces === "object" && !Array.isArray(workspaces);
145
- }
146
- function detectCatalogRoot(data) {
147
- if (data.catalog || data.catalogs) {
148
- return "top";
149
- }
150
- if (isWorkspaceObject(data.workspaces) && (data.workspaces.catalog || data.workspaces.catalogs)) {
151
- return "workspaces";
152
- }
153
- return isWorkspaceObject(data.workspaces) ? "workspaces" : "top";
154
- }
155
- function normalizeCatalogName(name) {
156
- return name.replace(/\^/g, "h").replace(/~/g, "t").replace(/\./g, "_").replace(/</g, "l").replace(/>/g, "g").replace(/=/g, "e").replace(/\*/g, "s").replace(/@/g, "a").replace(/\|/g, "p").replace(/&/g, "n").replace(/-/g, "m").replace(/\+/g, "u").replace(/\s/g, "_");
157
- }
158
- function sortObjectKeys(input) {
159
- return Object.fromEntries(
160
- Object.entries(input).sort(([left], [right]) => left.localeCompare(right))
161
- );
162
- }
163
- function isWorkspaceRootPackageJson(data) {
164
- return Boolean(
165
- data.workspaces || data.catalog || data.catalogs
166
- );
167
- }
168
- function readBunWorkspace(cwd = process.cwd()) {
169
- const filepath = findUpSync("package.json", {
170
- cwd,
171
- type: "file"
172
- });
173
- if (!filepath) {
174
- throw new Error("package.json not found");
175
- }
176
- let current = filepath;
177
- let content = fs.readFileSync(current, "utf8");
178
- let data = JSON.parse(content);
179
- while (!isWorkspaceRootPackageJson(data)) {
180
- const searchFrom = dirname(dirname(current));
181
- const next = findUpSync("package.json", {
182
- cwd: searchFrom,
183
- type: "file"
184
- });
185
- if (!next || normalize(next) === normalize(current)) {
186
- break;
187
- }
188
- current = next;
189
- content = fs.readFileSync(current, "utf8");
190
- data = JSON.parse(content);
191
- }
192
- if (!isWorkspaceRootPackageJson(data)) {
193
- throw new Error(
194
- "Bun workspace root package.json with workspaces/catalog not found"
195
- );
196
- }
197
- let hasChanged = false;
198
- let queueTimer;
199
- const queue = [];
200
- let catalogRoot = detectCatalogRoot(data);
201
- const write = () => {
202
- if (!fs.existsSync(current)) {
203
- return;
204
- }
205
- fs.writeFileSync(current, `${JSON.stringify(data, null, 2)}
206
- `);
207
- };
208
- const clearQueue = () => {
209
- if (queueTimer != null) {
210
- clearTimeout(queueTimer);
211
- queueTimer = void 0;
212
- }
213
- queue.length = 0;
214
- };
215
- const getCatalogContainer = () => {
216
- if (catalogRoot === "workspaces") {
217
- if (!isWorkspaceObject(data.workspaces)) {
218
- data.workspaces = {
219
- packages: Array.isArray(data.workspaces) ? data.workspaces : [],
220
- catalog: {},
221
- catalogs: {}
222
- };
223
- }
224
- return data.workspaces;
225
- }
226
- return data;
227
- };
228
- const getCatalogData = () => {
229
- const container = getCatalogContainer();
230
- return {
231
- catalog: container.catalog,
232
- catalogs: container.catalogs
233
- };
234
- };
235
- const setPackage = (catalogName, packageName, specifier) => {
236
- const container = getCatalogContainer();
237
- if (catalogName === "default") {
238
- container.catalog ??= {};
239
- if (container.catalog[packageName] !== specifier) {
240
- container.catalog[packageName] = specifier;
241
- container.catalog = sortObjectKeys(container.catalog);
242
- hasChanged = true;
243
- }
244
- return;
245
- }
246
- container.catalogs ??= {};
247
- container.catalogs[catalogName] ??= {};
248
- if (container.catalogs[catalogName][packageName] !== specifier) {
249
- container.catalogs[catalogName][packageName] = specifier;
250
- container.catalogs[catalogName] = sortObjectKeys(
251
- container.catalogs[catalogName]
252
- );
253
- container.catalogs = sortObjectKeys(container.catalogs);
254
- hasChanged = true;
255
- }
256
- };
257
- const hasSpecifierConflicts = (catalogName, packageName, specifier) => {
258
- const { catalog, catalogs } = getCatalogData();
259
- const existingSpecifier = catalogName === "default" ? catalog?.[packageName] : catalogs?.[catalogName]?.[packageName];
260
- if (existingSpecifier === specifier) {
261
- return {
262
- conflicts: false,
263
- newCatalogName: catalogName,
264
- existingSpecifier
265
- };
266
- }
267
- if (existingSpecifier) {
268
- const versionSuffix = normalizeCatalogName(specifier);
269
- const newCatalogName = catalogName === "default" ? `conflicts_${packageName}_${versionSuffix}` : `conflicts_${catalogName}_${versionSuffix}`;
270
- return {
271
- conflicts: true,
272
- existingSpecifier,
273
- newCatalogName
274
- };
275
- }
276
- return {
277
- conflicts: false,
278
- newCatalogName: catalogName
279
- };
280
- };
281
- const getPackageCatalogs = (packageName) => {
282
- const found = [];
283
- const { catalog, catalogs } = getCatalogData();
284
- if (catalogs) {
285
- for (const name of Object.keys(catalogs)) {
286
- if (catalogs[name]?.[packageName]) {
287
- found.push(name);
288
- }
289
- }
290
- }
291
- if (catalog?.[packageName]) {
292
- found.push("default");
293
- }
294
- return found;
295
- };
296
- const workspace2 = {
297
- filepath: current,
298
- setContent(newContent) {
299
- content = newContent;
300
- data = JSON.parse(newContent);
301
- catalogRoot = detectCatalogRoot(data);
302
- hasChanged = false;
303
- },
304
- hasChanged: () => hasChanged,
305
- hasQueue: () => queueTimer != null,
306
- clearQueue,
307
- queueChange(fn, order) {
308
- if (order === "pre") {
309
- queue.unshift(fn);
310
- } else {
311
- queue.push(fn);
312
- }
313
- if (queueTimer != null) {
314
- clearTimeout(queueTimer);
315
- }
316
- queueTimer = setTimeout(() => {
317
- queueTimer = void 0;
318
- const clone = [...queue];
319
- queue.length = 0;
320
- for (const queued of clone) {
321
- queued(workspace2);
322
- }
323
- if (hasChanged) {
324
- write();
325
- }
326
- }, 1e3);
327
- },
328
- toJSON: () => data,
329
- toString: () => `${JSON.stringify(data, null, 2)}
330
- `,
331
- setPackage,
332
- setPackageNoConflicts(catalogName, packageName, specifier) {
333
- const { newCatalogName } = hasSpecifierConflicts(
334
- catalogName,
335
- packageName,
336
- specifier
337
- );
338
- setPackage(newCatalogName, packageName, specifier);
339
- },
340
- getPackageCatalogs,
341
- hasSpecifierConflicts,
342
- getCatalogData,
343
- getWorkspacePackagePatterns() {
344
- if (Array.isArray(data.workspaces)) {
345
- return data.workspaces;
346
- }
347
- if (isWorkspaceObject(data.workspaces) && data.workspaces.packages) {
348
- return data.workspaces.packages;
349
- }
350
- return [];
351
- }
352
- };
353
- return workspace2;
354
- }
355
- var WORKSPACE_CACHE_TIME = 1e4;
356
- var workspaceLastRead;
357
- var workspace;
358
- function getBunWorkspace(cwd = process.cwd()) {
359
- if (workspaceLastRead && workspace && !workspace.hasQueue() && Date.now() - workspaceLastRead > WORKSPACE_CACHE_TIME) {
360
- workspace = void 0;
361
- }
362
- if (!workspace) {
363
- workspace = readBunWorkspace(cwd);
364
- workspaceLastRead = Date.now();
365
- }
366
- return workspace;
367
- }
368
- function isRootWorkspacePackageJson(filename, cwd = process.cwd()) {
369
- try {
370
- const root = getBunWorkspace(cwd);
371
- return normalize(root.filepath) === normalize(filename);
372
- } catch {
373
- return false;
374
- }
375
- }
376
- function collectWorkspacePackageJsonPaths(workspaceRoot) {
377
- const root = resolve(dirname(workspaceRoot.filepath));
378
- const patterns = workspaceRoot.getWorkspacePackagePatterns();
379
- const dirs = patterns.length ? globSync(patterns, {
380
- cwd: root,
381
- dot: false,
382
- ignore: [
383
- "**/node_modules/**",
384
- "**/dist/**",
385
- "**/build/**"
386
- ],
387
- absolute: true,
388
- expandDirectories: false,
389
- onlyDirectories: true
390
- }) : [];
391
- dirs.push(root);
392
- return dirs.map((dir) => resolve(dir, "package.json")).filter((path) => fs.existsSync(path)).sort();
393
- }
394
-
395
- // src/helpers/iterate-dependencies.ts
396
- function getPackageJsonRootNode(context) {
397
- if (!context.filename.endsWith("package.json")) {
398
- return void 0;
399
- }
400
- const ast = context.sourceCode.ast;
401
- const root = ast.body[0];
402
- if (root?.expression?.type === "JSONObjectExpression") {
403
- return root.expression;
404
- }
405
- return void 0;
406
- }
407
- function* iterateDependencies(context, fields) {
408
- const root = getPackageJsonRootNode(context);
409
- if (!root) {
410
- return;
411
- }
412
- for (const fieldName of fields) {
413
- const path = fieldName.split(".");
414
- let node = root;
415
- for (const segment of path) {
416
- const item = node.properties?.find(
417
- (property) => property.key.type === "JSONLiteral" && property.key.value === segment
418
- );
419
- if (!item?.value || item.value.type !== "JSONObjectExpression") {
420
- node = void 0;
421
- break;
422
- }
423
- node = item.value;
424
- }
425
- if (!node || node === root || !node.properties) {
426
- continue;
427
- }
428
- for (const property of node.properties) {
429
- if (property.value.type !== "JSONLiteral" || property.key.type !== "JSONLiteral") {
430
- continue;
431
- }
432
- if (typeof property.value.value !== "string") {
433
- continue;
434
- }
435
- yield {
436
- packageName: String(property.key.value),
437
- specifier: String(property.value.value),
438
- property
439
- };
440
- }
441
- }
442
- }
443
- function getObjectPath(obj, path) {
444
- let current = obj;
445
- for (const key of path) {
446
- if (!current || typeof current !== "object") {
447
- return void 0;
448
- }
449
- current = current[key];
450
- if (!current) {
451
- return void 0;
452
- }
453
- }
454
- return current;
455
- }
456
-
457
- // src/rules/json-enforce-catalog.ts
458
- var RULE_NAME = "json-enforce-catalog";
459
- var DEFAULT_FIELDS = ["dependencies", "devDependencies"];
460
- var IGNORED_DEPENDENCIES = ["typescript"];
461
- var json_enforce_catalog_default = createRule({
462
- name: RULE_NAME,
463
- meta: {
464
- type: "layout",
465
- docs: {
466
- description: 'Enforce using "catalog:" in `package.json` and write versions to the Bun workspace root catalog'
467
- },
468
- fixable: "code",
469
- schema: [
470
- {
471
- type: "object",
472
- properties: {
473
- allowedProtocols: {
474
- type: "array",
475
- description: "Allowed protocols in specifier to not be converted to catalog",
476
- items: { type: "string" }
477
- },
478
- autofix: {
479
- type: "boolean",
480
- description: "Whether to autofix the linting error",
481
- default: true
482
- },
483
- defaultCatalog: {
484
- type: "string",
485
- description: "Default catalog to use when moving version to catalog with autofix"
486
- },
487
- reuseExistingCatalog: {
488
- type: "boolean",
489
- description: "Whether to reuse existing catalog when moving version to catalog with autofix",
490
- default: true
491
- },
492
- conflicts: {
493
- type: "string",
494
- description: "Strategy to handle conflicts when adding packages to catalogs",
495
- enum: ["new-catalog", "overrides", "error"],
496
- default: "new-catalog"
497
- },
498
- fields: {
499
- type: "array",
500
- description: "Fields to check for catalog",
501
- items: { type: "string" },
502
- default: DEFAULT_FIELDS
503
- },
504
- ignore: {
505
- type: "array",
506
- description: "A list of dependencies to ignore",
507
- items: { type: "string" },
508
- default: IGNORED_DEPENDENCIES
509
- }
510
- },
511
- additionalProperties: false
512
- }
513
- ],
514
- messages: {
515
- expectCatalog: 'Expect to use catalog instead of plain specifier, got "{{specifier}}" for package "{{packageName}}".'
516
- }
517
- },
518
- defaultOptions: [{}],
519
- create(context, [options]) {
520
- const {
521
- allowedProtocols = ["workspace", "link", "file"],
522
- defaultCatalog = "default",
523
- autofix = true,
524
- reuseExistingCatalog = true,
525
- conflicts = "new-catalog",
526
- fields = DEFAULT_FIELDS,
527
- ignore = IGNORED_DEPENDENCIES
528
- } = options || {};
529
- for (const { packageName, specifier, property } of iterateDependencies(
530
- context,
531
- fields
532
- )) {
533
- if (ignore?.some((name) => name === packageName)) {
534
- continue;
535
- }
536
- if (specifier.startsWith("catalog:")) {
537
- continue;
538
- }
539
- if (allowedProtocols?.some((protocol) => specifier.startsWith(protocol))) {
540
- continue;
541
- }
542
- let workspace2;
543
- try {
544
- workspace2 = getBunWorkspace();
545
- } catch {
546
- return {};
547
- }
548
- let targetCatalog = reuseExistingCatalog ? workspace2.getPackageCatalogs(packageName)[0] || defaultCatalog : defaultCatalog;
549
- const resolvedConflicts = workspace2.hasSpecifierConflicts(
550
- targetCatalog,
551
- packageName,
552
- specifier
553
- );
554
- let shouldFix = autofix;
555
- if (conflicts === "error" && resolvedConflicts.conflicts) {
556
- shouldFix = false;
557
- }
558
- if (conflicts === "new-catalog" && resolvedConflicts.conflicts) {
559
- targetCatalog = resolvedConflicts.newCatalogName;
560
- }
561
- context.report({
562
- node: property.value,
563
- messageId: "expectCatalog",
564
- data: {
565
- specifier,
566
- packageName
567
- },
568
- fix: shouldFix ? (fixer) => {
569
- workspace2.queueChange(() => {
570
- workspace2.setPackage(targetCatalog, packageName, specifier);
571
- });
572
- return fixer.replaceText(
573
- property.value,
574
- targetCatalog === "default" ? JSON.stringify("catalog:") : JSON.stringify(`catalog:${targetCatalog}`)
575
- );
576
- } : void 0
577
- });
578
- }
579
- return {};
580
- }
581
- });
582
-
583
- // src/rules/json-no-duplicate-catalog-item.ts
584
- var RULE_NAME2 = "json-no-duplicate-catalog-item";
585
- function getProperty(node, key) {
586
- return node?.properties?.find(
587
- (property) => property.key.type === "JSONLiteral" && property.key.value === key
588
- );
589
- }
590
- var json_no_duplicate_catalog_item_default = createRule({
591
- name: RULE_NAME2,
592
- meta: {
593
- type: "problem",
594
- docs: {
595
- description: "Disallow duplicate catalog items in the Bun workspace root `package.json`"
596
- },
597
- schema: [
598
- {
599
- type: "object",
600
- properties: {
601
- allow: {
602
- type: "array",
603
- items: { type: "string" }
604
- }
605
- },
606
- additionalProperties: false
607
- }
608
- ],
609
- messages: {
610
- duplicateCatalogItem: 'Catalog item "{{name}}" is already defined in the "{{existingCatalog}}" catalog. You may want to remove one of them.'
611
- }
612
- },
613
- defaultOptions: [{}],
614
- create(context, [options = {}]) {
615
- if (!isRootWorkspacePackageJson(context.filename)) {
616
- return {};
617
- }
618
- let workspace2;
619
- try {
620
- workspace2 = getBunWorkspace();
621
- } catch {
622
- return {};
623
- }
624
- if (workspace2.hasChanged() || workspace2.hasQueue()) {
625
- return {};
626
- }
627
- workspace2.setContent(context.sourceCode.text);
628
- const root = getPackageJsonRootNode(context);
629
- if (!root) {
630
- return {};
631
- }
632
- const { allow = [] } = options;
633
- const topCatalog = getProperty(root, "catalog");
634
- const topCatalogs = getProperty(root, "catalogs");
635
- const workspaces = getProperty(root, "workspaces");
636
- const workspacesCatalog = workspaces?.value?.type === "JSONObjectExpression" ? getProperty(workspaces.value, "catalog") : void 0;
637
- const workspacesCatalogs = workspaces?.value?.type === "JSONObjectExpression" ? getProperty(workspaces.value, "catalogs") : void 0;
638
- const catalogNode = topCatalog ?? workspacesCatalog;
639
- const catalogsNode = topCatalogs ?? workspacesCatalogs;
640
- const exists = /* @__PURE__ */ new Map();
641
- const catalogEntries = [];
642
- if (catalogNode?.value?.type === "JSONObjectExpression") {
643
- for (const property of catalogNode.value.properties || []) {
644
- catalogEntries.push({ catalogName: "default", property });
645
- }
646
- }
647
- if (catalogsNode?.value?.type === "JSONObjectExpression") {
648
- for (const named of catalogsNode.value.properties || []) {
649
- if (named.value.type !== "JSONObjectExpression") {
650
- continue;
651
- }
652
- const catalogName = String(named.key.value);
653
- for (const property of named.value.properties || []) {
654
- catalogEntries.push({ catalogName, property });
655
- }
656
- }
657
- }
658
- for (const { catalogName, property } of catalogEntries) {
659
- const key = String(property.key.value);
660
- if (allow.includes(key)) {
661
- continue;
662
- }
663
- if (exists.has(key)) {
664
- context.report({
665
- node: property.value,
666
- messageId: "duplicateCatalogItem",
667
- data: {
668
- name: key,
669
- currentCatalog: catalogName,
670
- existingCatalog: exists.get(key)
671
- }
672
- });
673
- } else {
674
- exists.set(key, catalogName);
675
- }
676
- }
677
- return {};
678
- }
679
- });
680
- var RULE_NAME3 = "json-no-unused-catalog-item";
681
- var FIELDS = [
682
- "dependencies",
683
- "devDependencies",
684
- "peerDependencies",
685
- "optionalDependencies",
686
- "overrides",
687
- "resolutions"
688
- ];
689
- function getProperty2(node, key) {
690
- return node?.properties?.find(
691
- (property) => property.key.type === "JSONLiteral" && property.key.value === key
692
- );
693
- }
694
- var json_no_unused_catalog_item_default = createRule({
695
- name: RULE_NAME3,
696
- meta: {
697
- type: "problem",
698
- docs: {
699
- description: "Disallow unused catalog items in the Bun workspace root `package.json`"
700
- },
701
- schema: [],
702
- messages: {
703
- unusedCatalogItem: 'Catalog item "{{catalogItem}}" is not used in any package.json.'
704
- }
705
- },
706
- defaultOptions: [],
707
- create(context) {
708
- if (!isRootWorkspacePackageJson(context.filename)) {
709
- return {};
710
- }
711
- let workspace2;
712
- try {
713
- workspace2 = getBunWorkspace();
714
- } catch {
715
- return {};
716
- }
717
- if (workspace2.hasChanged() || workspace2.hasQueue()) {
718
- return {};
719
- }
720
- workspace2.setContent(context.sourceCode.text);
721
- const root = getPackageJsonRootNode(context);
722
- if (!root) {
723
- return {};
724
- }
725
- const topCatalog = getProperty2(root, "catalog");
726
- const topCatalogs = getProperty2(root, "catalogs");
727
- const workspaces = getProperty2(root, "workspaces");
728
- const workspacesCatalog = workspaces?.value?.type === "JSONObjectExpression" ? getProperty2(workspaces.value, "catalog") : void 0;
729
- const workspacesCatalogs = workspaces?.value?.type === "JSONObjectExpression" ? getProperty2(workspaces.value, "catalogs") : void 0;
730
- const catalogNode = topCatalog ?? workspacesCatalog;
731
- const catalogsNode = topCatalogs ?? workspacesCatalogs;
732
- const entries = /* @__PURE__ */ new Map();
733
- if (catalogNode?.value?.type === "JSONObjectExpression") {
734
- for (const property of catalogNode.value.properties || []) {
735
- entries.set(`${String(property.key.value)}:default`, property);
736
- }
737
- }
738
- if (catalogsNode?.value?.type === "JSONObjectExpression") {
739
- for (const named of catalogsNode.value.properties || []) {
740
- if (named.value.type !== "JSONObjectExpression") {
741
- continue;
742
- }
743
- const catalogName = String(named.key.value);
744
- for (const property of named.value.properties || []) {
745
- entries.set(`${String(property.key.value)}:${catalogName}`, property);
746
- }
747
- }
748
- }
749
- if (entries.size === 0) {
750
- return {};
751
- }
752
- const packages = collectWorkspacePackageJsonPaths(workspace2);
753
- for (const path of packages) {
754
- const pkg = JSON.parse(fs.readFileSync(path, "utf8"));
755
- for (const field of FIELDS) {
756
- const map = getObjectPath(pkg, field.split("."));
757
- if (!map) {
758
- continue;
759
- }
760
- for (const [name, value] of Object.entries(map)) {
761
- if (typeof value !== "string" || !value.startsWith("catalog:")) {
762
- continue;
763
- }
764
- const catalogName = value.slice(8) || "default";
765
- entries.delete(`${name}:${catalogName}`);
766
- }
767
- }
768
- }
769
- if (entries.size > 0) {
770
- for (const [key, property] of Array.from(entries.entries()).sort(
771
- (a, b) => a[0].localeCompare(b[0])
772
- )) {
773
- context.report({
774
- node: property.value,
775
- messageId: "unusedCatalogItem",
776
- data: { catalogItem: key }
777
- });
778
- }
779
- }
780
- return {};
781
- }
782
- });
783
-
784
- // src/rules/json-valid-catalog.ts
785
- var RULE_NAME4 = "json-valid-catalog";
786
- var DEFAULT_FIELDS2 = [
787
- "dependencies",
788
- "devDependencies",
789
- "optionalDependencies",
790
- "peerDependencies",
791
- "resolutions",
792
- "overrides"
793
- ];
794
- var json_valid_catalog_default = createRule({
795
- name: RULE_NAME4,
796
- meta: {
797
- type: "layout",
798
- docs: {
799
- description: "Enforce using valid Bun catalog references in `package.json`"
800
- },
801
- fixable: "code",
802
- schema: [
803
- {
804
- type: "object",
805
- properties: {
806
- autoInsert: {
807
- type: "boolean",
808
- description: "Whether to auto insert to catalog if missing",
809
- default: true
810
- },
811
- autoInsertDefaultSpecifier: {
812
- type: "string",
813
- description: "Default specifier to use when auto inserting to catalog",
814
- default: "^0.0.0"
815
- },
816
- autofix: {
817
- type: "boolean",
818
- description: "Whether to autofix the linting error",
819
- default: true
820
- },
821
- fields: {
822
- type: "array",
823
- description: "Fields to check for catalog",
824
- default: DEFAULT_FIELDS2
825
- }
826
- },
827
- additionalProperties: false
828
- }
829
- ],
830
- messages: {
831
- invalidCatalog: 'Catalog "{{specifier}}" for package "{{packageName}}" is not defined in the workspace root `package.json`.'
832
- }
833
- },
834
- defaultOptions: [{}],
835
- create(context, [options = {}]) {
836
- const {
837
- autoInsert = true,
838
- autofix = true,
839
- autoInsertDefaultSpecifier = "^0.0.0",
840
- fields = DEFAULT_FIELDS2
841
- } = options || {};
842
- for (const { packageName, specifier, property } of iterateDependencies(
843
- context,
844
- fields
845
- )) {
846
- if (!specifier.startsWith("catalog:")) {
847
- continue;
848
- }
849
- let workspace2;
850
- try {
851
- workspace2 = getBunWorkspace();
852
- } catch {
853
- return {};
854
- }
855
- const currentCatalog = specifier.replace(/^catalog:/, "").trim() || "default";
856
- const existingCatalogs = workspace2.getPackageCatalogs(packageName);
857
- if (!existingCatalogs.includes(currentCatalog)) {
858
- context.report({
859
- node: property.value,
860
- messageId: "invalidCatalog",
861
- data: {
862
- specifier,
863
- packageName
864
- },
865
- fix: !autofix || !autoInsert && !existingCatalogs.length ? void 0 : (fixer) => {
866
- let catalog = existingCatalogs[0];
867
- if (!catalog && autoInsert) {
868
- catalog = currentCatalog;
869
- workspace2.queueChange(() => {
870
- workspace2.setPackage(
871
- catalog,
872
- packageName,
873
- autoInsertDefaultSpecifier
874
- );
875
- }, "pre");
876
- }
877
- return fixer.replaceText(
878
- property.value,
879
- catalog === "default" ? JSON.stringify("catalog:") : JSON.stringify(`catalog:${catalog}`)
880
- );
881
- }
882
- });
883
- }
884
- }
885
- return {};
886
- }
887
- });
888
-
889
- // src/plugin.ts
890
- var plugin = {
891
- meta: {
892
- name: "bun",
893
- version: package_default.version
894
- },
895
- rules: {
896
- "json-enforce-catalog": json_enforce_catalog_default,
897
- "json-valid-catalog": json_valid_catalog_default,
898
- "json-no-unused-catalog-item": json_no_unused_catalog_item_default,
899
- "json-no-duplicate-catalog-item": json_no_duplicate_catalog_item_default
900
- }
901
- };
902
-
903
- // src/configs/recommended.ts
904
- var config = [
905
- {
906
- name: "bun/recommended/setup",
907
- plugins: {
908
- bun: plugin
909
- }
910
- },
911
- {
912
- name: "bun/recommended/package-json",
913
- ignores: GLOB_EXCLUDE,
914
- files: ["package.json", "**/package.json"],
915
- languageOptions: {
916
- parser: parserJsonc
917
- },
918
- rules: {
919
- "bun/json-enforce-catalog": [
920
- "error",
921
- {
922
- autofix: true,
923
- allowedProtocols: ["workspace", "link", "file"],
924
- defaultCatalog: "default",
925
- reuseExistingCatalog: true,
926
- conflicts: "overrides",
927
- fields: ["dependencies", "devDependencies"],
928
- ignore: ["typescript"]
929
- }
930
- ],
931
- "bun/json-valid-catalog": "error",
932
- "bun/json-no-unused-catalog-item": "error",
933
- "bun/json-no-duplicate-catalog-item": "error"
934
- }
935
- }
936
- ];
937
- var recommended_default = config;
938
-
939
- export { recommended_default as default };
1
+ import { t as plugin } from "../plugin-DfH7W_YX.mjs";
2
+ import { GLOB_EXCLUDE } from "@storm-software/package-constants/globs";
3
+ import parserJsonc from "jsonc-eslint-parser";
4
+ //#region src/configs/recommended.ts
5
+ const config = [{
6
+ name: "bun/recommended/setup",
7
+ plugins: { bun: plugin }
8
+ }, {
9
+ name: "bun/recommended/package-json",
10
+ ignores: GLOB_EXCLUDE,
11
+ files: ["package.json", "**/package.json"],
12
+ languageOptions: { parser: parserJsonc },
13
+ rules: {
14
+ "bun/json-enforce-catalog": ["error", {
15
+ autofix: true,
16
+ allowedProtocols: [
17
+ "workspace",
18
+ "link",
19
+ "file"
20
+ ],
21
+ defaultCatalog: "default",
22
+ reuseExistingCatalog: true,
23
+ conflicts: "overrides",
24
+ fields: ["dependencies", "devDependencies"],
25
+ ignore: ["typescript"]
26
+ }],
27
+ "bun/json-valid-catalog": "error",
28
+ "bun/json-no-unused-catalog-item": "error",
29
+ "bun/json-no-duplicate-catalog-item": "error"
30
+ }
31
+ }];
32
+ //#endregion
33
+ export { config as default };