@anzusystems/common-admin 1.47.0-beta.dev-1771894836 → 1.47.0-beta.dev-1771894840
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/common-admin.js.map +1 -1
- package/package.json +4 -2
- package/src/eslint/plugin.mjs +406 -0
package/package.json
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
"name": "@anzusystems/common-admin",
|
|
3
3
|
"packageManager": "yarn@4.13.0",
|
|
4
4
|
"files": [
|
|
5
|
-
"dist"
|
|
5
|
+
"dist",
|
|
6
|
+
"src/eslint"
|
|
6
7
|
],
|
|
7
8
|
"module": "./dist/common-admin.es.js",
|
|
8
9
|
"types": "./dist/common-admin.d.ts",
|
|
@@ -16,9 +17,10 @@
|
|
|
16
17
|
"import": "./dist/labs.js",
|
|
17
18
|
"types": "./dist/labs.d.ts"
|
|
18
19
|
},
|
|
20
|
+
"./eslint": "./src/eslint/plugin.mjs",
|
|
19
21
|
"./*": "./*"
|
|
20
22
|
},
|
|
21
|
-
"version": "1.47.0-beta.dev-
|
|
23
|
+
"version": "1.47.0-beta.dev-1771894840",
|
|
22
24
|
"license": "Apache-2.0",
|
|
23
25
|
"repository": {
|
|
24
26
|
"type": "git",
|
|
@@ -0,0 +1,406 @@
|
|
|
1
|
+
const DEFAULT_DEPRECATED_IMPORTS = [
|
|
2
|
+
'AFilterWrapper',
|
|
3
|
+
'AFilterBooleanSelect',
|
|
4
|
+
'AFilterBooleanGroup',
|
|
5
|
+
'AFilterDatetimePicker',
|
|
6
|
+
'AFilterInteger',
|
|
7
|
+
'AFilterRemoteAutocomplete',
|
|
8
|
+
'AFilterRemoteAutocompleteWithMinimal',
|
|
9
|
+
'AFilterString',
|
|
10
|
+
'AFilterValueObjectOptionsSelect',
|
|
11
|
+
'ADatatableOrdering',
|
|
12
|
+
'ADatatablePagination',
|
|
13
|
+
'AFormRemoteAutocomplete',
|
|
14
|
+
'ASubjectSelect',
|
|
15
|
+
'usePagination',
|
|
16
|
+
'useFilterHelpers',
|
|
17
|
+
'createDatatableColumnsConfig',
|
|
18
|
+
'useSubjectSelect',
|
|
19
|
+
'useApiQueryBuilder',
|
|
20
|
+
'useJobApi',
|
|
21
|
+
'Pagination',
|
|
22
|
+
'makeFilterHelper',
|
|
23
|
+
'apiFetchList',
|
|
24
|
+
'FilterBag',
|
|
25
|
+
'Filter',
|
|
26
|
+
'apiFetchByIds',
|
|
27
|
+
'apiAnyRequest',
|
|
28
|
+
'apiCreateOne',
|
|
29
|
+
'apiDeleteOne',
|
|
30
|
+
'apiFetchOne',
|
|
31
|
+
'apiUpdateOne',
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
const DEFAULT_INTERNAL_DEPRECATED_IMPORTS = [
|
|
35
|
+
{
|
|
36
|
+
path: '@/services/api/apiFetchList',
|
|
37
|
+
imports: ['apiFetchList'],
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
path: '@/services/api/apiFetchListBatch',
|
|
41
|
+
imports: ['apiFetchListBatch'],
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
path: '@/composables/system/pagination',
|
|
45
|
+
imports: ['usePagination', 'Pagination'],
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
path: '@/composables/filter/filterHelpers',
|
|
49
|
+
imports: ['useFilterHelpers', 'makeFilterHelper'],
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
path: '@/composables/system/datatableColumns',
|
|
53
|
+
imports: ['createDatatableColumnsConfig'],
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
path: '@/components/subjectSelect/useSubjectSelect',
|
|
57
|
+
imports: ['useSubjectSelect'],
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
path: '@/services/api/queryBuilder',
|
|
61
|
+
imports: ['useApiQueryBuilder'],
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
path: '@/services/api/job/jobApi',
|
|
65
|
+
imports: ['useJobApi'],
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
path: '@/types/Filter',
|
|
69
|
+
imports: ['FilterBag', 'Filter'],
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
path: '@/components/filter/AFilterWrapper',
|
|
73
|
+
imports: ['AFilterWrapper'],
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
path: '@/components/filter/AFilterBooleanSelect',
|
|
77
|
+
imports: ['AFilterBooleanSelect'],
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
path: '@/components/filter/AFilterBooleanGroup',
|
|
81
|
+
imports: ['AFilterBooleanGroup'],
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
path: '@/components/filter/AFilterDatetimePicker',
|
|
85
|
+
imports: ['AFilterDatetimePicker'],
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
path: '@/components/filter/AFilterInteger',
|
|
89
|
+
imports: ['AFilterInteger'],
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
path: '@/components/filter/AFilterRemoteAutocomplete',
|
|
93
|
+
imports: ['AFilterRemoteAutocomplete'],
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
path: '@/components/filter/AFilterRemoteAutocompleteWithMinimal',
|
|
97
|
+
imports: ['AFilterRemoteAutocompleteWithMinimal'],
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
path: '@/components/filter/AFilterString',
|
|
101
|
+
imports: ['AFilterString'],
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
path: '@/components/filter/AFilterValueObjectOptionsSelect',
|
|
105
|
+
imports: ['AFilterValueObjectOptionsSelect'],
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
path: '@/components/ADatatableOrdering',
|
|
109
|
+
imports: ['ADatatableOrdering'],
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
path: '@/components/ADatatablePagination',
|
|
113
|
+
imports: ['ADatatablePagination'],
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
path: '@/components/form/AFormRemoteAutocomplete',
|
|
117
|
+
imports: ['AFormRemoteAutocomplete'],
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
path: '@/components/subjectSelect/ASubjectSelect',
|
|
121
|
+
imports: ['ASubjectSelect'],
|
|
122
|
+
},
|
|
123
|
+
]
|
|
124
|
+
|
|
125
|
+
const anzuPlugin = {
|
|
126
|
+
rules: {
|
|
127
|
+
'no-ts-extension': {
|
|
128
|
+
meta: {
|
|
129
|
+
type: 'problem',
|
|
130
|
+
docs: {
|
|
131
|
+
description: 'Disallow .ts extension in import statements',
|
|
132
|
+
},
|
|
133
|
+
fixable: 'code',
|
|
134
|
+
schema: [],
|
|
135
|
+
},
|
|
136
|
+
create(context) {
|
|
137
|
+
return {
|
|
138
|
+
ImportDeclaration(node) {
|
|
139
|
+
const source = node.source.value
|
|
140
|
+
if (typeof source === 'string' && source.endsWith('.ts')) {
|
|
141
|
+
context.report({
|
|
142
|
+
node,
|
|
143
|
+
message: 'Do not include .ts extension in import paths',
|
|
144
|
+
fix(fixer) {
|
|
145
|
+
const sourceText = node.source.raw
|
|
146
|
+
const newSource = sourceText.replace(/\.ts(['"])$/, '$1')
|
|
147
|
+
return fixer.replaceText(node.source, newSource)
|
|
148
|
+
},
|
|
149
|
+
})
|
|
150
|
+
}
|
|
151
|
+
},
|
|
152
|
+
}
|
|
153
|
+
},
|
|
154
|
+
},
|
|
155
|
+
|
|
156
|
+
'no-deprecated-imports': {
|
|
157
|
+
meta: {
|
|
158
|
+
type: 'problem',
|
|
159
|
+
docs: {
|
|
160
|
+
description: 'Disallow usage of deprecated imports',
|
|
161
|
+
},
|
|
162
|
+
schema: [
|
|
163
|
+
{
|
|
164
|
+
type: 'object',
|
|
165
|
+
properties: {
|
|
166
|
+
rules: {
|
|
167
|
+
type: 'array',
|
|
168
|
+
items: {
|
|
169
|
+
type: 'object',
|
|
170
|
+
properties: {
|
|
171
|
+
path: { type: 'string' },
|
|
172
|
+
module: { type: 'string' },
|
|
173
|
+
imports: {
|
|
174
|
+
type: 'array',
|
|
175
|
+
items: { type: 'string' },
|
|
176
|
+
},
|
|
177
|
+
},
|
|
178
|
+
required: ['imports'],
|
|
179
|
+
additionalProperties: false,
|
|
180
|
+
},
|
|
181
|
+
},
|
|
182
|
+
skipFiles: {
|
|
183
|
+
type: 'array',
|
|
184
|
+
items: { type: 'string' },
|
|
185
|
+
},
|
|
186
|
+
},
|
|
187
|
+
additionalProperties: false,
|
|
188
|
+
},
|
|
189
|
+
],
|
|
190
|
+
},
|
|
191
|
+
create(context) {
|
|
192
|
+
const options = context.options[0] || {}
|
|
193
|
+
const deprecationRules = options.rules || []
|
|
194
|
+
const skipFiles = options.skipFiles || []
|
|
195
|
+
|
|
196
|
+
// Collect source file paths from path-based rules for auto-skip
|
|
197
|
+
const ruleFilePaths = deprecationRules
|
|
198
|
+
.filter((rule) => rule.path)
|
|
199
|
+
.map((rule) => {
|
|
200
|
+
if (rule.path.startsWith('@/')) {
|
|
201
|
+
return rule.path.replace('@/', 'src/')
|
|
202
|
+
}
|
|
203
|
+
return rule.path
|
|
204
|
+
})
|
|
205
|
+
|
|
206
|
+
return {
|
|
207
|
+
ImportDeclaration(node) {
|
|
208
|
+
const filename = context.filename
|
|
209
|
+
const normalizedFilename = filename.replace(/\\/g, '/')
|
|
210
|
+
|
|
211
|
+
// Check manual skip list
|
|
212
|
+
if (skipFiles.some((skip) => normalizedFilename.endsWith(skip))) return
|
|
213
|
+
|
|
214
|
+
// Auto-skip source files of path-based rules
|
|
215
|
+
if (
|
|
216
|
+
ruleFilePaths.some(
|
|
217
|
+
(rulePath) =>
|
|
218
|
+
normalizedFilename.endsWith(rulePath + '.ts') ||
|
|
219
|
+
normalizedFilename.endsWith(rulePath + '.js') ||
|
|
220
|
+
normalizedFilename.endsWith(rulePath + '.vue') ||
|
|
221
|
+
normalizedFilename.endsWith(rulePath)
|
|
222
|
+
)
|
|
223
|
+
) return
|
|
224
|
+
|
|
225
|
+
const source = node.source.value
|
|
226
|
+
if (typeof source !== 'string') return
|
|
227
|
+
|
|
228
|
+
for (const rule of deprecationRules) {
|
|
229
|
+
const matchPath = rule.path || rule.module
|
|
230
|
+
if (!matchPath || source !== matchPath) continue
|
|
231
|
+
|
|
232
|
+
const deprecatedImports = node.specifiers
|
|
233
|
+
.filter((spec) => spec.type === 'ImportSpecifier')
|
|
234
|
+
.filter((spec) => rule.imports.includes(spec.imported.name))
|
|
235
|
+
|
|
236
|
+
for (const importSpec of deprecatedImports) {
|
|
237
|
+
context.report({
|
|
238
|
+
node: importSpec,
|
|
239
|
+
message: `'${importSpec.imported.name}' from '${matchPath}' is deprecated`,
|
|
240
|
+
})
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
},
|
|
244
|
+
}
|
|
245
|
+
},
|
|
246
|
+
},
|
|
247
|
+
|
|
248
|
+
'no-fatal-error-axios-check': {
|
|
249
|
+
meta: {
|
|
250
|
+
type: 'problem',
|
|
251
|
+
docs: {
|
|
252
|
+
description:
|
|
253
|
+
'Disallow isAnzuFatalError + axios.isAxiosError(error.cause) pattern.' +
|
|
254
|
+
' Labs API throws AnzuApiAxiosError instead.',
|
|
255
|
+
},
|
|
256
|
+
schema: [],
|
|
257
|
+
},
|
|
258
|
+
create(context) {
|
|
259
|
+
return {
|
|
260
|
+
LogicalExpression(node) {
|
|
261
|
+
if (node.operator !== '&&') return
|
|
262
|
+
if (node.parent.type === 'LogicalExpression' && node.parent.operator === '&&') return
|
|
263
|
+
|
|
264
|
+
const parts = []
|
|
265
|
+
let current = node
|
|
266
|
+
while (current.type === 'LogicalExpression' && current.operator === '&&') {
|
|
267
|
+
parts.unshift(current.right)
|
|
268
|
+
current = current.left
|
|
269
|
+
}
|
|
270
|
+
parts.unshift(current)
|
|
271
|
+
|
|
272
|
+
const hasFatalCheck = parts.some(
|
|
273
|
+
(part) => part.type === 'CallExpression' && part.callee.name === 'isAnzuFatalError'
|
|
274
|
+
)
|
|
275
|
+
const hasAxiosCheck = parts.some(
|
|
276
|
+
(part) =>
|
|
277
|
+
part.type === 'CallExpression' &&
|
|
278
|
+
part.callee.type === 'MemberExpression' &&
|
|
279
|
+
part.callee.object.name === 'axios' &&
|
|
280
|
+
part.callee.property.name === 'isAxiosError'
|
|
281
|
+
)
|
|
282
|
+
|
|
283
|
+
if (hasFatalCheck && hasAxiosCheck) {
|
|
284
|
+
context.report({
|
|
285
|
+
node,
|
|
286
|
+
message:
|
|
287
|
+
'Replace isAnzuFatalError(error) && axios.isAxiosError(error.cause)' +
|
|
288
|
+
' with isAnzuApiAxiosError(error).' +
|
|
289
|
+
' Labs API throws AnzuApiAxiosError with typed AxiosError cause.',
|
|
290
|
+
})
|
|
291
|
+
}
|
|
292
|
+
},
|
|
293
|
+
}
|
|
294
|
+
},
|
|
295
|
+
},
|
|
296
|
+
},
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* Creates an ESLint flat config entry for Anzu rules.
|
|
301
|
+
*
|
|
302
|
+
* @param {Object} [options]
|
|
303
|
+
* @param {boolean|'error'|'warn'|'off'} [options.noTsExtension='error'] - Severity for no-ts-extension rule.
|
|
304
|
+
* @param {boolean|'error'|'warn'|'off'} [options.noFatalErrorAxiosCheck='error']
|
|
305
|
+
* - Severity for no-fatal-error-axios-check rule.
|
|
306
|
+
* @param {boolean|'error'|'warn'|'off'|Object} [options.deprecatedImports='error'] - Severity or config object.
|
|
307
|
+
* @param {string[]} [options.deprecatedImports.exclude] - Import names to remove from the default list.
|
|
308
|
+
* @param {string[]} [options.deprecatedImports.include] - Additional import names to add to the default list.
|
|
309
|
+
* @param {Array} [options.deprecatedImports.extraRules]
|
|
310
|
+
* - Additional rule entries ({ path, imports } or { module, imports }).
|
|
311
|
+
* @param {string[]} [options.deprecatedImports.skipFiles] - Files to skip (matched by suffix).
|
|
312
|
+
* @param {'error'|'warn'} [options.deprecatedImports.severity='error'] - Severity level.
|
|
313
|
+
* @param {'consumer'|'internal'} [options.deprecatedImports.mode='consumer'] - 'consumer' uses module-based defaults,
|
|
314
|
+
* 'internal' uses path-based defaults for common-admin development.
|
|
315
|
+
* @returns {Object} ESLint flat config entry
|
|
316
|
+
*/
|
|
317
|
+
export function recommended(options = {}) {
|
|
318
|
+
const {
|
|
319
|
+
noTsExtension = 'error',
|
|
320
|
+
noFatalErrorAxiosCheck = 'error',
|
|
321
|
+
deprecatedImports = 'error',
|
|
322
|
+
} = options
|
|
323
|
+
|
|
324
|
+
const rules = {}
|
|
325
|
+
|
|
326
|
+
// no-ts-extension
|
|
327
|
+
const tsExtSeverity = normalizeSeverity(noTsExtension)
|
|
328
|
+
if (tsExtSeverity) {
|
|
329
|
+
rules['anzu/no-ts-extension'] = tsExtSeverity
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
// no-fatal-error-axios-check
|
|
333
|
+
const fatalSeverity = normalizeSeverity(noFatalErrorAxiosCheck)
|
|
334
|
+
if (fatalSeverity) {
|
|
335
|
+
rules['anzu/no-fatal-error-axios-check'] = fatalSeverity
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
// no-deprecated-imports
|
|
339
|
+
if (deprecatedImports !== false && deprecatedImports !== 'off') {
|
|
340
|
+
let severity = 'error'
|
|
341
|
+
const ruleEntries = []
|
|
342
|
+
let skipFiles = []
|
|
343
|
+
|
|
344
|
+
if (typeof deprecatedImports === 'object') {
|
|
345
|
+
severity = deprecatedImports.severity || 'error'
|
|
346
|
+
const mode = deprecatedImports.mode || 'consumer'
|
|
347
|
+
|
|
348
|
+
if (mode === 'internal') {
|
|
349
|
+
// Internal mode: path-based rules for common-admin development
|
|
350
|
+
ruleEntries.push(...DEFAULT_INTERNAL_DEPRECATED_IMPORTS)
|
|
351
|
+
} else {
|
|
352
|
+
// Consumer mode: module-based rules for projects using common-admin
|
|
353
|
+
let importsList = [...DEFAULT_DEPRECATED_IMPORTS]
|
|
354
|
+
if (deprecatedImports.exclude) {
|
|
355
|
+
importsList = importsList.filter((name) => !deprecatedImports.exclude.includes(name))
|
|
356
|
+
}
|
|
357
|
+
if (deprecatedImports.include) {
|
|
358
|
+
importsList.push(...deprecatedImports.include)
|
|
359
|
+
}
|
|
360
|
+
ruleEntries.push({
|
|
361
|
+
module: '@anzusystems/common-admin',
|
|
362
|
+
imports: importsList,
|
|
363
|
+
})
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
if (deprecatedImports.extraRules) {
|
|
367
|
+
ruleEntries.push(...deprecatedImports.extraRules)
|
|
368
|
+
}
|
|
369
|
+
if (deprecatedImports.skipFiles) {
|
|
370
|
+
skipFiles = deprecatedImports.skipFiles
|
|
371
|
+
}
|
|
372
|
+
} else {
|
|
373
|
+
if (deprecatedImports === 'warn') {
|
|
374
|
+
severity = 'warn'
|
|
375
|
+
}
|
|
376
|
+
// Default consumer mode
|
|
377
|
+
ruleEntries.push({
|
|
378
|
+
module: '@anzusystems/common-admin',
|
|
379
|
+
imports: [...DEFAULT_DEPRECATED_IMPORTS],
|
|
380
|
+
})
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
const ruleConfig = { rules: ruleEntries }
|
|
384
|
+
if (skipFiles.length > 0) {
|
|
385
|
+
ruleConfig.skipFiles = skipFiles
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
rules['anzu/no-deprecated-imports'] = [severity, ruleConfig]
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
return {
|
|
392
|
+
plugins: {
|
|
393
|
+
anzu: anzuPlugin,
|
|
394
|
+
},
|
|
395
|
+
rules,
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
function normalizeSeverity(value) {
|
|
400
|
+
if (value === false || value === 'off') return null
|
|
401
|
+
if (value === true || value === 'error') return 'error'
|
|
402
|
+
if (value === 'warn') return 'warn'
|
|
403
|
+
return 'error'
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
export { anzuPlugin, DEFAULT_DEPRECATED_IMPORTS, DEFAULT_INTERNAL_DEPRECATED_IMPORTS }
|