@nextcloud/eslint-config 8.4.2 → 9.0.0-rc.0

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.
package/dist/index.mjs ADDED
@@ -0,0 +1,1464 @@
1
+ import stylistic from "@stylistic/eslint-plugin";
2
+ import jsdocPlugin from "eslint-plugin-jsdoc";
3
+ import globals from "globals";
4
+ import { XMLParser } from "fast-xml-parser";
5
+ import { readFileSync, lstatSync } from "fs";
6
+ import path, { isAbsolute, resolve, dirname, sep } from "path";
7
+ import { lte, valid } from "semver";
8
+ import jsonPlugin from "@eslint/json";
9
+ import sortPackageJson from "sort-package-json";
10
+ import typescriptPlugin from "typescript-eslint";
11
+ import vuePlugin from "eslint-plugin-vue";
12
+ /*!
13
+ * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
14
+ * SPDX-License-Identifier: AGPL-3.0-or-later
15
+ */
16
+ const GLOB_FILES_TESTING = [
17
+ "**.test.*",
18
+ "**.spec.*",
19
+ "**.cy.*",
20
+ "**/test",
21
+ "**/tests"
22
+ ];
23
+ const GLOB_FILES_TYPESCRIPT = [
24
+ "**/*.ts",
25
+ "**/*.mts",
26
+ "**/*.cts",
27
+ "**/*.tsx"
28
+ ];
29
+ const GLOB_FILES_JAVASCRIPT = [
30
+ "**/*.js",
31
+ "**/*.cjs",
32
+ "**/*.mjs",
33
+ "**/*.jsx"
34
+ ];
35
+ const GLOB_FILES_JSON = ["**/*.json"];
36
+ const GLOB_FILES_JSONC = ["**/*.jsonc"];
37
+ const GLOB_FILES_MS_JSON = [
38
+ "**/tsconfig.json",
39
+ ".vscode/*.json"
40
+ ];
41
+ const GLOB_FILES_VUE = ["**/*.vue"];
42
+ /*!
43
+ * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
44
+ * SPDX-License-Identifier: AGPL-3.0-or-later
45
+ */
46
+ function codeStyle(options) {
47
+ return [
48
+ // Nextcloud code style
49
+ {
50
+ name: "@stylistic/configs/recommended",
51
+ files: [
52
+ ...GLOB_FILES_JAVASCRIPT,
53
+ ...GLOB_FILES_TYPESCRIPT,
54
+ ...GLOB_FILES_VUE
55
+ ],
56
+ ...stylistic.configs.customize({
57
+ indent: "tab",
58
+ semi: false,
59
+ quotes: "single",
60
+ quoteProps: "as-needed",
61
+ commaDangle: "always-multiline",
62
+ arrowParens: true,
63
+ braceStyle: "1tbs"
64
+ })
65
+ },
66
+ {
67
+ files: [
68
+ ...GLOB_FILES_JAVASCRIPT,
69
+ ...GLOB_FILES_TYPESCRIPT,
70
+ ...GLOB_FILES_VUE
71
+ ],
72
+ rules: {
73
+ // Overrides for the stylistic recommended rules
74
+ // Tabs should only be used for indention
75
+ "@stylistic/no-tabs": [
76
+ "error",
77
+ { allowIndentationTabs: true }
78
+ ],
79
+ // allow spaces after tabs for alignment
80
+ "@stylistic/no-mixed-spaces-and-tabs": [
81
+ "error",
82
+ "smart-tabs"
83
+ ],
84
+ // allow backticks for strings that contain single quotes
85
+ "@stylistic/quotes": [
86
+ "error",
87
+ "single",
88
+ {
89
+ allowTemplateLiterals: false,
90
+ avoidEscape: true
91
+ }
92
+ ],
93
+ // Not included in stylistic preset but set by us:
94
+ // Enforce camelCase but allow legacy webpack variables
95
+ camelcase: [
96
+ "error",
97
+ {
98
+ allow: ["^__webpack_"],
99
+ properties: "never",
100
+ ignoreGlobals: true
101
+ }
102
+ ],
103
+ // Make sure to use object shorthand properties
104
+ "object-shorthand": [
105
+ "error",
106
+ "properties",
107
+ { avoidQuotes: true }
108
+ ],
109
+ // Enforce new lines after [ and before ] if there are multiline entries or more than 1 item in the array (better git diff)
110
+ "@stylistic/array-bracket-newline": [
111
+ "error",
112
+ {
113
+ multiline: true,
114
+ minItems: 2
115
+ }
116
+ ],
117
+ // Enforce new lines between array elements (better git diff)
118
+ "@stylistic/array-element-newline": [
119
+ "error",
120
+ "always"
121
+ ],
122
+ // Same for objects as for arrays
123
+ "@stylistic/object-curly-newline": [
124
+ "error",
125
+ {
126
+ consistent: true,
127
+ multiline: true
128
+ }
129
+ ],
130
+ "@stylistic/object-property-newline": "error",
131
+ // No space between function name and parenthesis. Enforce fn() instead of fn ()
132
+ "@stylistic/function-call-spacing": [
133
+ "error",
134
+ "never"
135
+ ],
136
+ // No space between function name and parenthesis on definition. Enforce `function foo()` instead of `function foo ()`.
137
+ "@stylistic/space-before-function-paren": [
138
+ "error",
139
+ {
140
+ // good: `function() {}` bad: `function () {}`
141
+ anonymous: "never",
142
+ // good `function foo() {}` bad: `function foo () {}`
143
+ named: "never",
144
+ // consistency for arrow functions regardless of async or sync:
145
+ // good `async () => {}` bad `async() => {}`
146
+ asyncArrow: "always"
147
+ }
148
+ ],
149
+ // Enforce consistent newlines in function parameters, if one parameter is separated by newline, than all should
150
+ "@stylistic/function-call-argument-newline": [
151
+ "error",
152
+ "consistent"
153
+ ],
154
+ // If parameters are separated by newlines, then the first one should also be separated by a newline from the parenthesis
155
+ "@stylistic/function-paren-newline": [
156
+ "error",
157
+ "multiline"
158
+ ],
159
+ // Generator functions should have the * on the function keyword as this defines the type of function. "function* generator()"
160
+ "@stylistic/generator-star-spacing": [
161
+ "error",
162
+ "after"
163
+ ],
164
+ // Arrow functions with implicit return should not have line breaks
165
+ // TODO: Discuss
166
+ "@stylistic/implicit-arrow-linebreak": [
167
+ "error",
168
+ "beside"
169
+ ],
170
+ // Prevent issues with different OS by enforcing single line feed for new lien
171
+ "@stylistic/linebreak-style": [
172
+ "error",
173
+ "unix"
174
+ ],
175
+ // Chained calls should be separated by newline (e.g. foo().forEach().map()...)
176
+ "@stylistic/newline-per-chained-call": ["error"],
177
+ // No useless semicolons
178
+ "@stylistic/no-extra-semi": ["error"],
179
+ "no-useless-concat": "error",
180
+ // Prefer { ...foo } over Object.assign({}, foo)
181
+ "prefer-object-spread": "warn",
182
+ // Prefer string templates
183
+ "prefer-template": "warn"
184
+ },
185
+ name: "nextcloud/stylistic/rules"
186
+ },
187
+ {
188
+ files: [
189
+ ...GLOB_FILES_TYPESCRIPT,
190
+ ...options.vueIsTypescript ? GLOB_FILES_VUE : []
191
+ ],
192
+ rules: {
193
+ // consistent spacing for types
194
+ "@stylistic/type-annotation-spacing": "error",
195
+ // consistent spacing for generics
196
+ "@stylistic/type-generic-spacing": "error",
197
+ "@stylistic/type-named-tuple-spacing": "error"
198
+ },
199
+ name: "nextcloud/stylistic/ts-rules"
200
+ }
201
+ ];
202
+ }
203
+ /*!
204
+ * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
205
+ * SPDX-License-Identifier: AGPL-3.0-or-later
206
+ */
207
+ function documentation(options) {
208
+ return [
209
+ {
210
+ ...jsdocPlugin.configs["flat/recommended-typescript"],
211
+ files: [
212
+ ...GLOB_FILES_JAVASCRIPT,
213
+ ...GLOB_FILES_TYPESCRIPT,
214
+ ...GLOB_FILES_VUE
215
+ ],
216
+ plugins: {
217
+ jsdoc: jsdocPlugin
218
+ }
219
+ },
220
+ {
221
+ ...jsdocPlugin.configs["flat/recommended"],
222
+ files: [
223
+ ...GLOB_FILES_JAVASCRIPT,
224
+ ...options.vueIsTypescript ? [] : GLOB_FILES_VUE
225
+ ],
226
+ ignores: GLOB_FILES_TESTING
227
+ },
228
+ {
229
+ ...jsdocPlugin.configs["flat/recommended-typescript"],
230
+ files: [
231
+ ...GLOB_FILES_TYPESCRIPT,
232
+ ...options.vueIsTypescript ? GLOB_FILES_VUE : []
233
+ ],
234
+ ignores: GLOB_FILES_TESTING
235
+ },
236
+ {
237
+ rules: {
238
+ // Force proper documentation
239
+ "jsdoc/check-tag-names": "error",
240
+ // But ignore return values
241
+ "jsdoc/require-returns": "off",
242
+ "jsdoc/require-returns-description": "off",
243
+ // Allow one empty line in jsdoc blocks
244
+ "jsdoc/tag-lines": [
245
+ "warn",
246
+ "any",
247
+ { startLines: 1 }
248
+ ]
249
+ },
250
+ files: [
251
+ ...GLOB_FILES_JAVASCRIPT,
252
+ ...GLOB_FILES_TYPESCRIPT,
253
+ ...GLOB_FILES_VUE
254
+ ],
255
+ name: "nextcloud/documentation/rules"
256
+ },
257
+ {
258
+ rules: {
259
+ // Overwrites for documentation as types are already provided by Typescript
260
+ "jsdoc/require-param-type": "off",
261
+ "jsdoc/require-property-type": "off",
262
+ "jsdoc/require-returns-type": "off"
263
+ },
264
+ files: [
265
+ ...GLOB_FILES_TYPESCRIPT,
266
+ ...options.vueIsTypescript ? GLOB_FILES_VUE : []
267
+ ],
268
+ name: "nextcloud/documentation/rules-typescript"
269
+ }
270
+ ];
271
+ }
272
+ /*!
273
+ * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
274
+ * SPDX-License-Identifier: AGPL-3.0-or-later
275
+ */
276
+ const filesystem = [
277
+ {
278
+ name: "nextcloud/filesystem/ignores",
279
+ ignores: [
280
+ "**/dist",
281
+ "**/vendor",
282
+ "**/vendor-bin",
283
+ "**/package-lock.json"
284
+ ]
285
+ }
286
+ ];
287
+ function getDefaultExportFromCjs(x) {
288
+ return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, "default") ? x["default"] : x;
289
+ }
290
+ const name = "@eslint/js";
291
+ const version = "9.23.0";
292
+ const require$$0 = {
293
+ name,
294
+ version
295
+ };
296
+ var eslintAll;
297
+ var hasRequiredEslintAll;
298
+ function requireEslintAll() {
299
+ if (hasRequiredEslintAll) return eslintAll;
300
+ hasRequiredEslintAll = 1;
301
+ eslintAll = Object.freeze({
302
+ "rules": {
303
+ "accessor-pairs": "error",
304
+ "array-callback-return": "error",
305
+ "arrow-body-style": "error",
306
+ "block-scoped-var": "error",
307
+ "camelcase": "error",
308
+ "capitalized-comments": "error",
309
+ "class-methods-use-this": "error",
310
+ "complexity": "error",
311
+ "consistent-return": "error",
312
+ "consistent-this": "error",
313
+ "constructor-super": "error",
314
+ "curly": "error",
315
+ "default-case": "error",
316
+ "default-case-last": "error",
317
+ "default-param-last": "error",
318
+ "dot-notation": "error",
319
+ "eqeqeq": "error",
320
+ "for-direction": "error",
321
+ "func-name-matching": "error",
322
+ "func-names": "error",
323
+ "func-style": "error",
324
+ "getter-return": "error",
325
+ "grouped-accessor-pairs": "error",
326
+ "guard-for-in": "error",
327
+ "id-denylist": "error",
328
+ "id-length": "error",
329
+ "id-match": "error",
330
+ "init-declarations": "error",
331
+ "logical-assignment-operators": "error",
332
+ "max-classes-per-file": "error",
333
+ "max-depth": "error",
334
+ "max-lines": "error",
335
+ "max-lines-per-function": "error",
336
+ "max-nested-callbacks": "error",
337
+ "max-params": "error",
338
+ "max-statements": "error",
339
+ "new-cap": "error",
340
+ "no-alert": "error",
341
+ "no-array-constructor": "error",
342
+ "no-async-promise-executor": "error",
343
+ "no-await-in-loop": "error",
344
+ "no-bitwise": "error",
345
+ "no-caller": "error",
346
+ "no-case-declarations": "error",
347
+ "no-class-assign": "error",
348
+ "no-compare-neg-zero": "error",
349
+ "no-cond-assign": "error",
350
+ "no-console": "error",
351
+ "no-const-assign": "error",
352
+ "no-constant-binary-expression": "error",
353
+ "no-constant-condition": "error",
354
+ "no-constructor-return": "error",
355
+ "no-continue": "error",
356
+ "no-control-regex": "error",
357
+ "no-debugger": "error",
358
+ "no-delete-var": "error",
359
+ "no-div-regex": "error",
360
+ "no-dupe-args": "error",
361
+ "no-dupe-class-members": "error",
362
+ "no-dupe-else-if": "error",
363
+ "no-dupe-keys": "error",
364
+ "no-duplicate-case": "error",
365
+ "no-duplicate-imports": "error",
366
+ "no-else-return": "error",
367
+ "no-empty": "error",
368
+ "no-empty-character-class": "error",
369
+ "no-empty-function": "error",
370
+ "no-empty-pattern": "error",
371
+ "no-empty-static-block": "error",
372
+ "no-eq-null": "error",
373
+ "no-eval": "error",
374
+ "no-ex-assign": "error",
375
+ "no-extend-native": "error",
376
+ "no-extra-bind": "error",
377
+ "no-extra-boolean-cast": "error",
378
+ "no-extra-label": "error",
379
+ "no-fallthrough": "error",
380
+ "no-func-assign": "error",
381
+ "no-global-assign": "error",
382
+ "no-implicit-coercion": "error",
383
+ "no-implicit-globals": "error",
384
+ "no-implied-eval": "error",
385
+ "no-import-assign": "error",
386
+ "no-inline-comments": "error",
387
+ "no-inner-declarations": "error",
388
+ "no-invalid-regexp": "error",
389
+ "no-invalid-this": "error",
390
+ "no-irregular-whitespace": "error",
391
+ "no-iterator": "error",
392
+ "no-label-var": "error",
393
+ "no-labels": "error",
394
+ "no-lone-blocks": "error",
395
+ "no-lonely-if": "error",
396
+ "no-loop-func": "error",
397
+ "no-loss-of-precision": "error",
398
+ "no-magic-numbers": "error",
399
+ "no-misleading-character-class": "error",
400
+ "no-multi-assign": "error",
401
+ "no-multi-str": "error",
402
+ "no-negated-condition": "error",
403
+ "no-nested-ternary": "error",
404
+ "no-new": "error",
405
+ "no-new-func": "error",
406
+ "no-new-native-nonconstructor": "error",
407
+ "no-new-wrappers": "error",
408
+ "no-nonoctal-decimal-escape": "error",
409
+ "no-obj-calls": "error",
410
+ "no-object-constructor": "error",
411
+ "no-octal": "error",
412
+ "no-octal-escape": "error",
413
+ "no-param-reassign": "error",
414
+ "no-plusplus": "error",
415
+ "no-promise-executor-return": "error",
416
+ "no-proto": "error",
417
+ "no-prototype-builtins": "error",
418
+ "no-redeclare": "error",
419
+ "no-regex-spaces": "error",
420
+ "no-restricted-exports": "error",
421
+ "no-restricted-globals": "error",
422
+ "no-restricted-imports": "error",
423
+ "no-restricted-properties": "error",
424
+ "no-restricted-syntax": "error",
425
+ "no-return-assign": "error",
426
+ "no-script-url": "error",
427
+ "no-self-assign": "error",
428
+ "no-self-compare": "error",
429
+ "no-sequences": "error",
430
+ "no-setter-return": "error",
431
+ "no-shadow": "error",
432
+ "no-shadow-restricted-names": "error",
433
+ "no-sparse-arrays": "error",
434
+ "no-template-curly-in-string": "error",
435
+ "no-ternary": "error",
436
+ "no-this-before-super": "error",
437
+ "no-throw-literal": "error",
438
+ "no-undef": "error",
439
+ "no-undef-init": "error",
440
+ "no-undefined": "error",
441
+ "no-underscore-dangle": "error",
442
+ "no-unexpected-multiline": "error",
443
+ "no-unmodified-loop-condition": "error",
444
+ "no-unneeded-ternary": "error",
445
+ "no-unreachable": "error",
446
+ "no-unreachable-loop": "error",
447
+ "no-unsafe-finally": "error",
448
+ "no-unsafe-negation": "error",
449
+ "no-unsafe-optional-chaining": "error",
450
+ "no-unused-expressions": "error",
451
+ "no-unused-labels": "error",
452
+ "no-unused-private-class-members": "error",
453
+ "no-unused-vars": "error",
454
+ "no-use-before-define": "error",
455
+ "no-useless-assignment": "error",
456
+ "no-useless-backreference": "error",
457
+ "no-useless-call": "error",
458
+ "no-useless-catch": "error",
459
+ "no-useless-computed-key": "error",
460
+ "no-useless-concat": "error",
461
+ "no-useless-constructor": "error",
462
+ "no-useless-escape": "error",
463
+ "no-useless-rename": "error",
464
+ "no-useless-return": "error",
465
+ "no-var": "error",
466
+ "no-void": "error",
467
+ "no-warning-comments": "error",
468
+ "no-with": "error",
469
+ "object-shorthand": "error",
470
+ "one-var": "error",
471
+ "operator-assignment": "error",
472
+ "prefer-arrow-callback": "error",
473
+ "prefer-const": "error",
474
+ "prefer-destructuring": "error",
475
+ "prefer-exponentiation-operator": "error",
476
+ "prefer-named-capture-group": "error",
477
+ "prefer-numeric-literals": "error",
478
+ "prefer-object-has-own": "error",
479
+ "prefer-object-spread": "error",
480
+ "prefer-promise-reject-errors": "error",
481
+ "prefer-regex-literals": "error",
482
+ "prefer-rest-params": "error",
483
+ "prefer-spread": "error",
484
+ "prefer-template": "error",
485
+ "radix": "error",
486
+ "require-atomic-updates": "error",
487
+ "require-await": "error",
488
+ "require-unicode-regexp": "error",
489
+ "require-yield": "error",
490
+ "sort-imports": "error",
491
+ "sort-keys": "error",
492
+ "sort-vars": "error",
493
+ "strict": "error",
494
+ "symbol-description": "error",
495
+ "unicode-bom": "error",
496
+ "use-isnan": "error",
497
+ "valid-typeof": "error",
498
+ "vars-on-top": "error",
499
+ "yoda": "error"
500
+ }
501
+ });
502
+ return eslintAll;
503
+ }
504
+ var eslintRecommended;
505
+ var hasRequiredEslintRecommended;
506
+ function requireEslintRecommended() {
507
+ if (hasRequiredEslintRecommended) return eslintRecommended;
508
+ hasRequiredEslintRecommended = 1;
509
+ eslintRecommended = Object.freeze({
510
+ rules: Object.freeze({
511
+ "constructor-super": "error",
512
+ "for-direction": "error",
513
+ "getter-return": "error",
514
+ "no-async-promise-executor": "error",
515
+ "no-case-declarations": "error",
516
+ "no-class-assign": "error",
517
+ "no-compare-neg-zero": "error",
518
+ "no-cond-assign": "error",
519
+ "no-const-assign": "error",
520
+ "no-constant-binary-expression": "error",
521
+ "no-constant-condition": "error",
522
+ "no-control-regex": "error",
523
+ "no-debugger": "error",
524
+ "no-delete-var": "error",
525
+ "no-dupe-args": "error",
526
+ "no-dupe-class-members": "error",
527
+ "no-dupe-else-if": "error",
528
+ "no-dupe-keys": "error",
529
+ "no-duplicate-case": "error",
530
+ "no-empty": "error",
531
+ "no-empty-character-class": "error",
532
+ "no-empty-pattern": "error",
533
+ "no-empty-static-block": "error",
534
+ "no-ex-assign": "error",
535
+ "no-extra-boolean-cast": "error",
536
+ "no-fallthrough": "error",
537
+ "no-func-assign": "error",
538
+ "no-global-assign": "error",
539
+ "no-import-assign": "error",
540
+ "no-invalid-regexp": "error",
541
+ "no-irregular-whitespace": "error",
542
+ "no-loss-of-precision": "error",
543
+ "no-misleading-character-class": "error",
544
+ "no-new-native-nonconstructor": "error",
545
+ "no-nonoctal-decimal-escape": "error",
546
+ "no-obj-calls": "error",
547
+ "no-octal": "error",
548
+ "no-prototype-builtins": "error",
549
+ "no-redeclare": "error",
550
+ "no-regex-spaces": "error",
551
+ "no-self-assign": "error",
552
+ "no-setter-return": "error",
553
+ "no-shadow-restricted-names": "error",
554
+ "no-sparse-arrays": "error",
555
+ "no-this-before-super": "error",
556
+ "no-undef": "error",
557
+ "no-unexpected-multiline": "error",
558
+ "no-unreachable": "error",
559
+ "no-unsafe-finally": "error",
560
+ "no-unsafe-negation": "error",
561
+ "no-unsafe-optional-chaining": "error",
562
+ "no-unused-labels": "error",
563
+ "no-unused-private-class-members": "error",
564
+ "no-unused-vars": "error",
565
+ "no-useless-backreference": "error",
566
+ "no-useless-catch": "error",
567
+ "no-useless-escape": "error",
568
+ "no-with": "error",
569
+ "require-yield": "error",
570
+ "use-isnan": "error",
571
+ "valid-typeof": "error"
572
+ })
573
+ });
574
+ return eslintRecommended;
575
+ }
576
+ var src;
577
+ var hasRequiredSrc;
578
+ function requireSrc() {
579
+ if (hasRequiredSrc) return src;
580
+ hasRequiredSrc = 1;
581
+ const { name: name2, version: version2 } = require$$0;
582
+ src = {
583
+ meta: {
584
+ name: name2,
585
+ version: version2
586
+ },
587
+ configs: {
588
+ all: requireEslintAll(),
589
+ recommended: requireEslintRecommended()
590
+ }
591
+ };
592
+ return src;
593
+ }
594
+ var srcExports = requireSrc();
595
+ const eslintRules = /* @__PURE__ */ getDefaultExportFromCjs(srcExports);
596
+ /*!
597
+ * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
598
+ * SPDX-License-Identifier: AGPL-3.0-or-later
599
+ */
600
+ function isDirectory(filePath) {
601
+ const stats = lstatSync(filePath, { throwIfNoEntry: false });
602
+ return stats !== void 0 && stats.isDirectory();
603
+ }
604
+ function isFile(filePath) {
605
+ const stats = lstatSync(filePath, { throwIfNoEntry: false });
606
+ return stats !== void 0 && stats.isFile();
607
+ }
608
+ function findAppinfo(currentPath) {
609
+ while (currentPath && currentPath !== sep) {
610
+ const appinfoPath = `${currentPath}${sep}appinfo`;
611
+ if (isDirectory(appinfoPath) && isFile(`${appinfoPath}${sep}info.xml`)) {
612
+ return `${appinfoPath}${sep}info.xml`;
613
+ }
614
+ currentPath = resolve(currentPath, "..");
615
+ }
616
+ return void 0;
617
+ }
618
+ function sanitizeTargetVersion(version2) {
619
+ let sanitizedVersion = version2;
620
+ const sections = sanitizedVersion.split(".").length;
621
+ if (sections < 3) {
622
+ sanitizedVersion = sanitizedVersion + ".0".repeat(3 - sections);
623
+ }
624
+ if (!valid(sanitizedVersion)) {
625
+ throw Error(`[@nextcloud/eslint-plugin] Invalid target version ${version2} found`);
626
+ }
627
+ return sanitizedVersion;
628
+ }
629
+ function createVersionValidator({ cwd, physicalFilename, options }) {
630
+ const settings = options[0];
631
+ if (settings?.targetVersion) {
632
+ const maxVersion = sanitizeTargetVersion(settings.targetVersion);
633
+ return (version2) => lte(version2, maxVersion);
634
+ }
635
+ if (settings?.parseAppInfo !== false) {
636
+ const currentDirectory = isAbsolute(physicalFilename) ? resolve(dirname(physicalFilename)) : dirname(resolve(cwd, physicalFilename));
637
+ const appinfoPath = findAppinfo(currentDirectory);
638
+ if (appinfoPath) {
639
+ const parser = new XMLParser({
640
+ attributeNamePrefix: "@",
641
+ ignoreAttributes: false
642
+ });
643
+ const xml = parser.parse(readFileSync(appinfoPath));
644
+ let maxVersion = xml?.info?.dependencies?.nextcloud?.["@max-version"];
645
+ if (typeof maxVersion !== "string") {
646
+ throw new Error(`[@nextcloud/eslint-plugin] AppInfo does not contain a max-version (location: ${appinfoPath})`);
647
+ }
648
+ maxVersion = sanitizeTargetVersion(maxVersion);
649
+ return (version2) => lte(version2, maxVersion);
650
+ }
651
+ if (settings?.parseAppInfo === true) {
652
+ throw new Error("[@nextcloud/eslint-plugin] AppInfo parsing was enabled, but no `appinfo/info.xml` was found.");
653
+ }
654
+ }
655
+ return () => true;
656
+ }
657
+ /*!
658
+ * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
659
+ * SPDX-License-Identifier: AGPL-3.0-or-later
660
+ */
661
+ const global$1 = {
662
+ $: "19.0.0",
663
+ Backbone: "18.0.0",
664
+ Clipboard: "18.0.0",
665
+ ClipboardJs: "18.0.0",
666
+ DOMPurify: "18.0.0",
667
+ formatDate: "16.0.0",
668
+ getURLParameter: "16.0.0",
669
+ Handlebars: "18.0.0",
670
+ humanFileSize: "16.0.0",
671
+ initCore: "17.0.0",
672
+ jQuery: "19.0.0",
673
+ jstimezonedetect: "18.0.0",
674
+ jstz: "18.0.0",
675
+ md5: "18.0.0",
676
+ moment: "18.0.0",
677
+ oc_appconfig: "17.0.0",
678
+ oc_appswebroots: "17.0.0",
679
+ oc_capabilities: "17.0.0",
680
+ oc_config: "17.0.0",
681
+ oc_current_user: "17.0.0",
682
+ oc_debug: "17.0.0",
683
+ oc_isadmin: "17.0.0",
684
+ oc_requesttoken: "17.0.0",
685
+ oc_webroot: "17.0.0",
686
+ OCDialogs: "17.0.0",
687
+ relative_modified_date: "16.0.0"
688
+ };
689
+ const oc$1 = {
690
+ L10n: "26.0.0",
691
+ _capabilities: "17.0.0",
692
+ addTranslations: "17.0.0",
693
+ basename: "18.0.0",
694
+ coreApps: "17.0.0",
695
+ currentUser: "19.0.0",
696
+ dirname: "18.0.0",
697
+ encodePath: "18.0.0",
698
+ fileIsBlacklisted: "17.0.0",
699
+ filePath: "19.0.0",
700
+ generateUrl: "19.0.0",
701
+ get: "19.0.0",
702
+ getCanonicalLocale: "20.0.0",
703
+ getCurrentUser: "19.0.0",
704
+ getHost: "17.0.0",
705
+ getHostName: "17.0.0",
706
+ getPort: "17.0.0",
707
+ getProtocol: "17.0.0",
708
+ getRootPath: "19.0.0",
709
+ imagePath: "19.0.0",
710
+ isSamePath: "18.0.0",
711
+ joinPaths: "18.0.0",
712
+ linkTo: "19.0.0",
713
+ linkToOCS: "19.0.0",
714
+ linkToRemote: "19.0.0",
715
+ set: "19.0.0",
716
+ webroot: "19.0.0"
717
+ };
718
+ const oca$1 = {
719
+ Search: "20.0.0"
720
+ };
721
+ const ocp = {
722
+ Toast: "19.0.0"
723
+ };
724
+ const ocNested$1 = {
725
+ Util: {
726
+ formatDate: "20.0.0",
727
+ humanFileSize: "20.0.0",
728
+ relativeModifiedDate: "20.0.0"
729
+ }
730
+ };
731
+ const rule$1 = {
732
+ meta: {
733
+ docs: {
734
+ description: "Deprecated Nextcloud APIs",
735
+ category: "Nextcloud",
736
+ recommended: true
737
+ },
738
+ // fixable: null or "code" or "whitespace"
739
+ schema: [
740
+ {
741
+ // We accept one option which is an object
742
+ type: "object",
743
+ properties: {
744
+ // if we should try to find an appinfo and only handle APIs removed before the max-version
745
+ parseAppInfo: {
746
+ type: "boolean"
747
+ },
748
+ // Set a Nextcloud target version, only APIs removed before that versions are checked
749
+ targetVersion: {
750
+ type: "string"
751
+ }
752
+ },
753
+ additionalProperties: false
754
+ }
755
+ ],
756
+ messages: {
757
+ deprecatedGlobal: "The global property or function {{name}} was deprecated in Nextcloud {{version}}"
758
+ }
759
+ },
760
+ create: function(context) {
761
+ const checkTargetVersion = createVersionValidator(context);
762
+ return {
763
+ MemberExpression: function(node2) {
764
+ if ("name" in node2.object && "name" in node2.property && node2.object.name === "OC" && Object.hasOwn(oc$1, node2.property.name) && checkTargetVersion(oc$1[node2.property.name])) {
765
+ context.report({
766
+ node: node2,
767
+ message: `The property or function OC.${node2.property.name} was deprecated in Nextcloud ${oc$1[node2.property.name]}`
768
+ });
769
+ }
770
+ if ("name" in node2.object && "name" in node2.property && node2.object.name === "OCA" && Object.hasOwn(oca$1, node2.property.name) && checkTargetVersion(oca$1[node2.property.name])) {
771
+ context.report({
772
+ node: node2,
773
+ message: `The property or function OCA.${node2.property.name} was deprecated in Nextcloud ${oca$1[node2.property.name]}`
774
+ });
775
+ }
776
+ if ("name" in node2.object && "name" in node2.property && node2.object.name === "OCP" && Object.hasOwn(ocp, node2.property.name) && checkTargetVersion(ocp[node2.property.name])) {
777
+ context.report({
778
+ node: node2,
779
+ message: `The property or function OCP.${node2.property.name} was deprecated in Nextcloud ${ocp[node2.property.name]}`
780
+ });
781
+ }
782
+ if (node2.object.type === "MemberExpression" && "name" in node2.object.object && node2.object.object.name === "OC" && "name" in node2.property && "name" in node2.object.property && Object.hasOwn(ocNested$1, node2.object.property.name) && Object.hasOwn(ocNested$1[node2.object.property.name], node2.property.name)) {
783
+ const version2 = ocNested$1[node2.object.property.name][node2.property.name];
784
+ if (checkTargetVersion(version2)) {
785
+ const prop = [
786
+ "OC",
787
+ node2.object.property.name,
788
+ node2.property.name
789
+ ].join(".");
790
+ const deprecatedSince = ocNested$1[node2.object.property.name][node2.property.name];
791
+ context.report({
792
+ node: node2,
793
+ message: `The property or function ${prop} was deprecated in Nextcloud ${deprecatedSince}`
794
+ });
795
+ }
796
+ }
797
+ },
798
+ Program(node2) {
799
+ const scope = context.sourceCode.getScope(node2);
800
+ const report = ({ identifier }) => {
801
+ if (checkTargetVersion(global$1[identifier.name])) {
802
+ context.report({
803
+ node: node2,
804
+ messageId: "deprecatedGlobal",
805
+ data: {
806
+ name: identifier.name,
807
+ version: global$1[identifier.name]
808
+ }
809
+ });
810
+ }
811
+ };
812
+ scope.variables.forEach((variable) => {
813
+ if (!variable.defs.length && Object.hasOwn(global$1, variable.name)) {
814
+ variable.references.forEach(report);
815
+ }
816
+ });
817
+ scope.through.forEach((reference) => {
818
+ if (Object.hasOwn(global$1, reference.identifier.name)) {
819
+ report(reference);
820
+ }
821
+ });
822
+ }
823
+ };
824
+ }
825
+ };
826
+ /*!
827
+ * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
828
+ * SPDX-License-Identifier: AGPL-3.0-or-later
829
+ */
830
+ const global = {
831
+ autosize: "29.0.0",
832
+ escapeHTML: "20.0.0",
833
+ fileDownloadPath: "15.0.0",
834
+ formatDate: "19.0.0",
835
+ getScrollBarWidth: "15.0.0",
836
+ getURLParameter: "19.0.0",
837
+ humanFileSize: "19.0.0",
838
+ marked: "19.0.0",
839
+ relative_modified_date: "19.0.0"
840
+ };
841
+ const oc = {
842
+ getScrollBarWidth: "15.0.0",
843
+ addTranslations: "26.0.0",
844
+ appSettings: "28.0.0",
845
+ loadScript: "28.0.0",
846
+ loadStyle: "28.0.0"
847
+ };
848
+ const ocNested = {
849
+ AppConfig: {
850
+ hasKey: "15.0.0",
851
+ deleteApp: "15.0.0"
852
+ },
853
+ Util: {
854
+ hasSVGSupport: "15.0.0",
855
+ replaceSVGIcon: "15.0.0",
856
+ replaceSVG: "15.0.0",
857
+ scaleFixForIE8: "15.0.0",
858
+ isIE8: "15.0.0"
859
+ }
860
+ };
861
+ const oca = {
862
+ // ref: https://github.com/nextcloud/server/commit/6eced42b7a40f5b0ea0489244583219d0ee2e7af
863
+ Search: "20.0.0"
864
+ };
865
+ const rule = {
866
+ meta: {
867
+ docs: {
868
+ description: "Removed Nextcloud APIs",
869
+ category: "Nextcloud",
870
+ recommended: true
871
+ },
872
+ // fixable: "code" or "whitespace"
873
+ schema: [
874
+ {
875
+ // We accept one option which is an object
876
+ type: "object",
877
+ properties: {
878
+ // if we should try to find an appinfo and only handle APIs removed before the max-version
879
+ parseAppInfo: {
880
+ type: "boolean"
881
+ },
882
+ // Set a Nextcloud target version, only APIs removed before that versions are checked
883
+ targetVersion: {
884
+ type: "string"
885
+ }
886
+ },
887
+ additionalProperties: false
888
+ }
889
+ ],
890
+ messages: {
891
+ removedGlobal: "The global property or function {{name}} was removed in Nextcloud {{version}}"
892
+ }
893
+ },
894
+ create: function(context) {
895
+ const checkTargetVersion = createVersionValidator(context);
896
+ return {
897
+ MemberExpression: function(node2) {
898
+ if ("name" in node2.object && "name" in node2.property && node2.object.name === "OCA" && Object.hasOwn(oca, node2.property.name)) {
899
+ context.report({
900
+ node: node2,
901
+ message: `The property or function OCA.${node2.property.name} was removed in Nextcloud ${oc[node2.property.name]}`
902
+ });
903
+ }
904
+ if ("name" in node2.object && "name" in node2.property && node2.object.name === "OC" && Object.hasOwn(oc, node2.property.name) && checkTargetVersion(oc[node2.property.name])) {
905
+ context.report({
906
+ node: node2,
907
+ message: `The property or function OC.${node2.property.name} was removed in Nextcloud ${oc[node2.property.name]}`
908
+ });
909
+ }
910
+ if (node2.object.type === "MemberExpression" && "name" in node2.object.object && node2.object.object.name === "OC" && "name" in node2.object.property && Object.hasOwn(ocNested, node2.object.property.name) && "name" in node2.property && Object.hasOwn(ocNested[node2.object.property.name], node2.property.name)) {
911
+ const version2 = ocNested[node2.object.property.name][node2.property.name];
912
+ if (checkTargetVersion(version2)) {
913
+ const prop = [
914
+ "OC",
915
+ node2.object.property.name,
916
+ node2.property.name
917
+ ].join(".");
918
+ context.report({
919
+ node: node2,
920
+ message: `The property or function ${prop} was removed in Nextcloud ${version2}`
921
+ });
922
+ }
923
+ }
924
+ },
925
+ Program(node2) {
926
+ const scope = context.sourceCode.getScope(node2);
927
+ const report = (ref) => {
928
+ const { identifier } = ref;
929
+ if (checkTargetVersion(global[identifier.name])) {
930
+ context.report({
931
+ node: node2,
932
+ messageId: "removedGlobal",
933
+ data: {
934
+ name: identifier.name,
935
+ version: global[identifier.name]
936
+ }
937
+ });
938
+ }
939
+ };
940
+ scope.variables.forEach((variable) => {
941
+ if (!variable.defs.length && Object.hasOwn(global, variable.name)) {
942
+ variable.references.forEach(report);
943
+ }
944
+ });
945
+ scope.through.forEach((reference) => {
946
+ if (Object.hasOwn(global, reference.identifier.name)) {
947
+ report(reference);
948
+ }
949
+ });
950
+ }
951
+ };
952
+ }
953
+ };
954
+ /*!
955
+ * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
956
+ * SPDX-License-Identifier: AGPL-3.0-or-later
957
+ */
958
+ const rules = {
959
+ "no-deprecations": rule$1,
960
+ "no-removed-apis": rule
961
+ };
962
+ /*!
963
+ * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
964
+ * SPDX-License-Identifier: AGPL-3.0-or-later
965
+ */
966
+ const nextcloudPlugin = {
967
+ rules,
968
+ meta: {
969
+ name: "@nextcloud/eslint-plugin",
970
+ version: "9.0.0-rc.0"
971
+ }
972
+ };
973
+ /*!
974
+ * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
975
+ * SPDX-License-Identifier: AGPL-3.0-or-later
976
+ */
977
+ const javascript = [
978
+ {
979
+ name: "nextcloud/javascript/setup",
980
+ languageOptions: {
981
+ ecmaVersion: "latest",
982
+ globals: {
983
+ ...globals.browser,
984
+ ...globals.es2025,
985
+ OC: "writable",
986
+ OCA: "readonly",
987
+ OCP: "readonly",
988
+ // legacy global Nextcloud translation function
989
+ t: "readonly",
990
+ n: "readonly",
991
+ // webpack support
992
+ __webpack_nonce__: "writable"
993
+ },
994
+ parserOptions: {
995
+ ecmaFeatures: {
996
+ jsx: true
997
+ },
998
+ ecmaVersion: "latest",
999
+ sourceType: "module"
1000
+ },
1001
+ sourceType: "module"
1002
+ },
1003
+ linterOptions: {
1004
+ reportUnusedDisableDirectives: true
1005
+ }
1006
+ },
1007
+ // General rules we built upon
1008
+ {
1009
+ name: "eslint/configs/recommended",
1010
+ files: [
1011
+ ...GLOB_FILES_JAVASCRIPT,
1012
+ ...GLOB_FILES_TYPESCRIPT,
1013
+ ...GLOB_FILES_VUE
1014
+ ],
1015
+ ...eslintRules.configs.recommended
1016
+ },
1017
+ // The Nextcloud plugin for detecting deprecated and removed global API
1018
+ {
1019
+ name: "nextcloud/javascript/plugin",
1020
+ plugins: {
1021
+ "@nextcloud": nextcloudPlugin
1022
+ },
1023
+ rules: {
1024
+ "@nextcloud/no-deprecations": ["warn"],
1025
+ "@nextcloud/no-removed-apis": ["error"]
1026
+ },
1027
+ files: [
1028
+ ...GLOB_FILES_JAVASCRIPT,
1029
+ ...GLOB_FILES_TYPESCRIPT,
1030
+ ...GLOB_FILES_VUE
1031
+ ]
1032
+ },
1033
+ // Nextcloud specific overwrite
1034
+ {
1035
+ name: "nextcloud/javascript/rules",
1036
+ files: [
1037
+ ...GLOB_FILES_JAVASCRIPT,
1038
+ ...GLOB_FILES_TYPESCRIPT,
1039
+ ...GLOB_FILES_VUE
1040
+ ],
1041
+ rules: {
1042
+ "no-eval": "error",
1043
+ // Require strict checks
1044
+ eqeqeq: "error",
1045
+ // Use dot notation where possible as we also only use quote where needed
1046
+ "dot-notation": "error",
1047
+ // prevent bugs and increasing code clarity by ensuring that block statements are wrapped in curly braces
1048
+ curly: [
1049
+ "error",
1050
+ "all"
1051
+ ],
1052
+ // disallow use of "var", use let and const - see rule description for reasons.
1053
+ "no-var": "error",
1054
+ // Prevent bugs by enforce const if variable is not changed.
1055
+ "prefer-const": "error",
1056
+ // `@nextcloud/logger` should be used
1057
+ "no-console": "error",
1058
+ // We support ES2022 so we should use `hasOwn` instead
1059
+ "prefer-object-has-own": "error"
1060
+ }
1061
+ },
1062
+ // Testing related overwrites
1063
+ {
1064
+ name: "nextcloud/javascript/testing-overwrites",
1065
+ files: GLOB_FILES_TESTING,
1066
+ rules: {
1067
+ // Allow to test console output
1068
+ "no-console": "off"
1069
+ }
1070
+ }
1071
+ ];
1072
+ /*!
1073
+ * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
1074
+ * SPDX-License-Identifier: AGPL-3.0-or-later
1075
+ */
1076
+ const SortPackageJsonRule = {
1077
+ meta: {
1078
+ fixable: "code",
1079
+ docs: {
1080
+ recommended: true,
1081
+ description: "Sort package json in consistent order"
1082
+ },
1083
+ schema: [
1084
+ {
1085
+ type: "object",
1086
+ properties: {
1087
+ sortOrder: {
1088
+ type: "array",
1089
+ minItems: 0,
1090
+ items: {
1091
+ type: "string"
1092
+ }
1093
+ }
1094
+ },
1095
+ additionalProperties: false
1096
+ }
1097
+ ]
1098
+ },
1099
+ create(context) {
1100
+ const filename = context.getFilename();
1101
+ if (path.basename(filename) !== "package.json") {
1102
+ return {};
1103
+ }
1104
+ const options = context.options ? context.options[0] : void 0;
1105
+ return {
1106
+ Document({ body }) {
1107
+ const sourceCode = context.sourceCode.text;
1108
+ const packageJsonText = sourceCode.slice(...body.range);
1109
+ const sortedPackageJsonText = sortPackageJson(packageJsonText, options);
1110
+ if (packageJsonText !== sortedPackageJsonText) {
1111
+ context.report({
1112
+ node: body,
1113
+ message: "package.json is not sorted correctly",
1114
+ fix(fixer) {
1115
+ return fixer.replaceText(body, sortedPackageJsonText);
1116
+ }
1117
+ });
1118
+ }
1119
+ }
1120
+ };
1121
+ }
1122
+ };
1123
+ const Plugin = {
1124
+ meta: {
1125
+ name: "@nextcloud/package-json",
1126
+ version: "9.0.0-rc.0"
1127
+ },
1128
+ rules: {
1129
+ "sort-package-json": SortPackageJsonRule
1130
+ }
1131
+ };
1132
+ /*!
1133
+ * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
1134
+ * SPDX-License-Identifier: AGPL-3.0-or-later
1135
+ */
1136
+ const json = [
1137
+ {
1138
+ language: "json/json",
1139
+ plugins: {
1140
+ json: jsonPlugin,
1141
+ "package-json": Plugin
1142
+ },
1143
+ rules: {
1144
+ ...jsonPlugin.configs.recommended.rules
1145
+ },
1146
+ files: GLOB_FILES_JSON,
1147
+ name: "nextcloud/json"
1148
+ },
1149
+ // lint package.json files
1150
+ {
1151
+ files: ["**/package.json"],
1152
+ language: "json/json",
1153
+ rules: {
1154
+ "package-json/sort-package-json": "error"
1155
+ }
1156
+ },
1157
+ // Special handing of JSONC
1158
+ {
1159
+ files: GLOB_FILES_JSONC,
1160
+ language: "json/jsonc",
1161
+ ...jsonPlugin.configs.recommended,
1162
+ name: "nextcloud/jsonc"
1163
+ },
1164
+ // Microsoft specific JSONC (e.g. Typescript config)
1165
+ {
1166
+ files: GLOB_FILES_MS_JSON,
1167
+ language: "json/jsonc",
1168
+ languageOptions: {
1169
+ allowTrailingCommas: true
1170
+ },
1171
+ ...jsonPlugin.configs.recommended,
1172
+ name: "nextcloud/ms-json"
1173
+ }
1174
+ ];
1175
+ /*!
1176
+ * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
1177
+ * SPDX-License-Identifier: AGPL-3.0-or-later
1178
+ */
1179
+ const node = [
1180
+ {
1181
+ name: "nextcloud/node/setup",
1182
+ files: [
1183
+ "**/*.config.*",
1184
+ "**/*.cjs",
1185
+ "**/*.cts",
1186
+ ...GLOB_FILES_TESTING
1187
+ ],
1188
+ languageOptions: {
1189
+ globals: {
1190
+ ...globals.es2023,
1191
+ ...globals.node,
1192
+ ...globals.nodeBuiltin
1193
+ }
1194
+ }
1195
+ }
1196
+ ];
1197
+ /*!
1198
+ * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
1199
+ * SPDX-License-Identifier: AGPL-3.0-or-later
1200
+ */
1201
+ function restrictConfigFiles(configs, files) {
1202
+ return configs.map((config) => ({
1203
+ ...config,
1204
+ files: [
1205
+ ...config.files ?? [],
1206
+ ...files
1207
+ ]
1208
+ }));
1209
+ }
1210
+ /*!
1211
+ * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
1212
+ * SPDX-License-Identifier: AGPL-3.0-or-later
1213
+ */
1214
+ function typescript(options) {
1215
+ return [
1216
+ ...restrictConfigFiles(
1217
+ typescriptPlugin.configs.recommended,
1218
+ [
1219
+ ...GLOB_FILES_TYPESCRIPT,
1220
+ ...options.vueIsTypescript ? GLOB_FILES_VUE : []
1221
+ ]
1222
+ ),
1223
+ {
1224
+ files: [
1225
+ ...GLOB_FILES_TYPESCRIPT,
1226
+ ...options.vueIsTypescript ? GLOB_FILES_VUE : []
1227
+ ],
1228
+ rules: {
1229
+ // Allow expect-error as we can sometimes not prevent it...
1230
+ "@typescript-eslint/ban-ts-comment": [
1231
+ "error",
1232
+ {
1233
+ "ts-expect-error": "allow-with-description",
1234
+ minimumDescriptionLength: 9
1235
+ }
1236
+ ],
1237
+ // No nullish coalescing if left side can not be nullish
1238
+ "@typescript-eslint/no-non-null-asserted-nullish-coalescing": "error",
1239
+ // Do not use types, variables etc before they are defined
1240
+ "no-use-before-define": "off",
1241
+ "@typescript-eslint/no-use-before-define": "error",
1242
+ // Do not shadow outer variables / functions - this can lead to wrong assumptions
1243
+ "no-shadow": "off",
1244
+ "@typescript-eslint/no-shadow": "error"
1245
+ },
1246
+ name: "nextcloud/typescript/rules"
1247
+ },
1248
+ {
1249
+ files: GLOB_FILES_TESTING,
1250
+ rules: {
1251
+ // Allow "any" in tests
1252
+ "@typescript-eslint/no-explicit-any": "off"
1253
+ },
1254
+ name: "nextcloud/typescript/test-rules"
1255
+ }
1256
+ ];
1257
+ }
1258
+ /*!
1259
+ * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
1260
+ * SPDX-License-Identifier: AGPL-3.0-or-later
1261
+ */
1262
+ const stylisticRules = codeStyle({ vueIsTypescript: false }).reduce((rules2, config) => ({
1263
+ ...rules2,
1264
+ ...config.rules ?? {}
1265
+ }), {});
1266
+ const vueStylisticRules = Object.keys(vuePlugin.rules).filter((rule2) => `@stylistic/${rule2}` in stylisticRules).map((rule2) => [
1267
+ `vue/${rule2}`,
1268
+ stylisticRules[`@stylistic/${rule2}`]
1269
+ ]);
1270
+ function vue(options) {
1271
+ return [
1272
+ ...options.vueIsTypescript ? [
1273
+ {
1274
+ languageOptions: {
1275
+ parserOptions: {
1276
+ parser: "@typescript-eslint/parser"
1277
+ }
1278
+ }
1279
+ }
1280
+ ] : [],
1281
+ {
1282
+ files: GLOB_FILES_VUE,
1283
+ rules: {
1284
+ // PascalCase components names for vuejs
1285
+ "vue/component-name-in-template-casing": [
1286
+ "error",
1287
+ "PascalCase"
1288
+ ],
1289
+ // space before self-closing elements
1290
+ "vue/html-closing-bracket-spacing": "error",
1291
+ // no ending html tag on a new line
1292
+ "vue/html-closing-bracket-newline": [
1293
+ "error",
1294
+ {
1295
+ multiline: "never"
1296
+ }
1297
+ ],
1298
+ // Enforce documentation of properties
1299
+ "vue/require-prop-comment": [
1300
+ "error",
1301
+ {
1302
+ type: "JSDoc"
1303
+ }
1304
+ ],
1305
+ // When a prop allows Boolean and some other type, then Boolean should come first to allow short-hand properties
1306
+ "vue/prefer-prop-type-boolean-first": "error",
1307
+ // Prevent useless string interpolation where not needed
1308
+ "vue/no-useless-mustaches": "error",
1309
+ // If there is a default then it is not required - this is either way a bug
1310
+ "vue/no-required-prop-with-default": "error",
1311
+ // Omit empty blocks
1312
+ "vue/no-empty-component-block": "error",
1313
+ // Boolean properties should behave like HTML properties
1314
+ "vue/no-boolean-default": [
1315
+ "warn",
1316
+ "default-false"
1317
+ ],
1318
+ // Allow 3 attributes on the same line if singe line
1319
+ "vue/max-attributes-per-line": [
1320
+ "error",
1321
+ {
1322
+ singleline: {
1323
+ max: 3
1324
+ }
1325
+ }
1326
+ ],
1327
+ // Component names should match their export names - readability and maintainability ("where does this component come from?")
1328
+ "vue/match-component-import-name": "error",
1329
+ "vue/match-component-file-name": "error",
1330
+ // Warn on undefined components - we need this on warning level as long as people use mixins (then we can move to error)
1331
+ "vue/no-undef-components": [
1332
+ "warn",
1333
+ {
1334
+ // Ignore the router view as this is most often globally registered
1335
+ ignorePatterns: ["router-?view"]
1336
+ }
1337
+ ],
1338
+ // Warn on unused refs
1339
+ "vue/no-unused-refs": "warn",
1340
+ // Warn on unused props
1341
+ "vue/no-unused-properties": "warn"
1342
+ },
1343
+ name: "nextcloud/vue/rules"
1344
+ },
1345
+ {
1346
+ files: GLOB_FILES_VUE,
1347
+ rules: {
1348
+ // same as the stylistic rules but for the <template> in Vue files
1349
+ ...Object.fromEntries(vueStylisticRules),
1350
+ // Also enforce tabs for template
1351
+ "vue/html-indent": [
1352
+ "error",
1353
+ "tab"
1354
+ ],
1355
+ // Consistent style of props
1356
+ "vue/new-line-between-multi-line-property": "error"
1357
+ },
1358
+ name: "nextcloud/vue/stylistic-rules"
1359
+ }
1360
+ ];
1361
+ }
1362
+ /*!
1363
+ * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
1364
+ * SPDX-License-Identifier: AGPL-3.0-or-later
1365
+ */
1366
+ function vue2(option) {
1367
+ return [
1368
+ ...restrictConfigFiles(
1369
+ vuePlugin.configs["flat/vue2-recommended"],
1370
+ GLOB_FILES_VUE
1371
+ ),
1372
+ ...vue(option),
1373
+ {
1374
+ rules: {
1375
+ // custom event naming convention
1376
+ "vue/custom-event-name-casing": [
1377
+ "error",
1378
+ "kebab-case",
1379
+ {
1380
+ // allows custom xxxx:xxx events formats
1381
+ ignores: ["/^[a-z]+(?:-[a-z]+)*:[a-z]+(?:-[a-z]+)*$/u"]
1382
+ }
1383
+ ]
1384
+ },
1385
+ files: GLOB_FILES_VUE,
1386
+ name: "nextcloud/vue2/rules"
1387
+ }
1388
+ ];
1389
+ }
1390
+ /*!
1391
+ * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
1392
+ * SPDX-License-Identifier: AGPL-3.0-or-later
1393
+ */
1394
+ function vue3(options) {
1395
+ return [
1396
+ ...restrictConfigFiles(
1397
+ vuePlugin.configs["flat/recommended"],
1398
+ GLOB_FILES_VUE
1399
+ ),
1400
+ ...vue(options),
1401
+ // Vue3 specific overrides
1402
+ {
1403
+ files: GLOB_FILES_VUE,
1404
+ rules: {
1405
+ // Deprecated thus we should not use it
1406
+ "vue/no-deprecated-delete-set": "error"
1407
+ },
1408
+ name: "nextcloud/vue3/rules"
1409
+ }
1410
+ ];
1411
+ }
1412
+ /*!
1413
+ * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
1414
+ * SPDX-License-Identifier: AGPL-3.0-or-later
1415
+ */
1416
+ const recommendedVue2Javascript = [
1417
+ ...filesystem,
1418
+ ...javascript,
1419
+ ...json,
1420
+ ...node,
1421
+ ...typescript({ vueIsTypescript: false }),
1422
+ ...vue2({ vueIsTypescript: false }),
1423
+ ...documentation({ vueIsTypescript: false }),
1424
+ ...codeStyle({ vueIsTypescript: false })
1425
+ ];
1426
+ const recommendedVue2 = [
1427
+ ...filesystem,
1428
+ ...javascript,
1429
+ ...json,
1430
+ ...node,
1431
+ ...typescript({ vueIsTypescript: true }),
1432
+ ...vue2({ vueIsTypescript: true }),
1433
+ ...documentation({ vueIsTypescript: true }),
1434
+ ...codeStyle({ vueIsTypescript: true })
1435
+ ];
1436
+ const recommendedJavascript = [
1437
+ ...filesystem,
1438
+ ...javascript,
1439
+ ...json,
1440
+ ...node,
1441
+ ...typescript({ vueIsTypescript: false }),
1442
+ ...vue3({ vueIsTypescript: false }),
1443
+ ...documentation({ vueIsTypescript: false }),
1444
+ ...codeStyle({ vueIsTypescript: false })
1445
+ ];
1446
+ const recommended = [
1447
+ ...filesystem,
1448
+ ...javascript,
1449
+ ...json,
1450
+ ...node,
1451
+ ...typescript({ vueIsTypescript: true }),
1452
+ ...vue3({ vueIsTypescript: true }),
1453
+ ...documentation({ vueIsTypescript: true }),
1454
+ ...codeStyle({ vueIsTypescript: true })
1455
+ ];
1456
+ export {
1457
+ nextcloudPlugin,
1458
+ Plugin as packageJsonPlugin,
1459
+ recommended,
1460
+ recommendedJavascript,
1461
+ recommendedVue2,
1462
+ recommendedVue2Javascript
1463
+ };
1464
+ //# sourceMappingURL=index.mjs.map