@ovh-ux/manager-static-analysis-kit 0.11.2 → 0.13.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/CHANGELOG.md +22 -0
- package/README.md +2 -2
- package/bin/cli-path-config.js +9 -8
- package/bin/code-duplication-tests-cli.js +9 -9
- package/bin/lint-cli.js +26 -10
- package/bin/perf-budgets-tests-cli.js +9 -9
- package/bin/tests-coverage-cli-tests.js +9 -9
- package/bin/types-coverage-cli.js +7 -0
- package/bin/types-coverage-tests-cli.js +9 -9
- package/bin/utils/args-parse-utils.js +3 -2
- package/dist/adapters/code-duplication/helpers/code-duplication-analysis-helper.d.ts +1 -1
- package/dist/adapters/code-duplication/helpers/code-duplication-analysis-helper.d.ts.map +1 -1
- package/dist/adapters/code-duplication/helpers/code-duplication-analysis-helper.js +16 -146
- package/dist/adapters/code-duplication/helpers/code-duplication-reports-render.d.ts +4 -0
- package/dist/adapters/code-duplication/helpers/code-duplication-reports-render.d.ts.map +1 -0
- package/dist/adapters/code-duplication/helpers/code-duplication-reports-render.js +141 -0
- package/dist/adapters/eslint/rules/eslint-prettier.d.ts.map +1 -1
- package/dist/adapters/eslint/rules/eslint-prettier.js +3 -2
- package/dist/adapters/html-w3c-validation/helpers/html-w3c-tests-setup.d.ts +2 -2
- package/dist/configs/code-formatter-config.d.ts +0 -1
- package/dist/configs/code-formatter-config.d.ts.map +1 -1
- package/dist/configs/code-formatter-config.js +0 -10
- package/dist/configs/shared-exclusion-patterns.d.ts +2 -0
- package/dist/configs/shared-exclusion-patterns.d.ts.map +1 -1
- package/dist/configs/shared-exclusion-patterns.js +40 -27
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +28 -28
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,28 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
# [0.13.0](https://github.com/ovh/manager/compare/@ovh-ux/manager-static-analysis-kit@0.12.0...@ovh-ux/manager-static-analysis-kit@0.13.0) (2025-11-16)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
* pnpm hybrid improvements ([3b45577](https://github.com/ovh/manager/commit/3b455770da0c7aeb7603f7c731abf6fac9eb4b3f))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
# [0.12.0](https://github.com/ovh/manager/compare/@ovh-ux/manager-static-analysis-kit@0.11.2...@ovh-ux/manager-static-analysis-kit@0.12.0) (2025-11-02)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
### Features
|
|
21
|
+
|
|
22
|
+
* **muk:** static quality improvement ([2ca8694](https://github.com/ovh/manager/commit/2ca8694747cce2ea2901b6d04286ac07a65be03d))
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
6
28
|
## [0.11.2](https://github.com/ovh/manager/compare/@ovh-ux/manager-static-analysis-kit@0.11.1...@ovh-ux/manager-static-analysis-kit@0.11.2) (2025-10-23)
|
|
7
29
|
|
|
8
30
|
|
package/README.md
CHANGED
|
@@ -101,13 +101,13 @@ yarn manager-types-coverage --package @ovh-ux/manager-container-app
|
|
|
101
101
|
### Analyze specific libraries (by `package.json` name)
|
|
102
102
|
|
|
103
103
|
```bash
|
|
104
|
-
yarn manager-types-coverage --libraries @ovh-ux/manager-wiki,@ovh-ux/
|
|
104
|
+
yarn manager-types-coverage --libraries @ovh-ux/manager-wiki,@ovh-ux/muk
|
|
105
105
|
```
|
|
106
106
|
|
|
107
107
|
or single library:
|
|
108
108
|
|
|
109
109
|
```bash
|
|
110
|
-
yarn manager-types-coverage --library @ovh-ux/
|
|
110
|
+
yarn manager-types-coverage --library @ovh-ux/muk
|
|
111
111
|
```
|
|
112
112
|
|
|
113
113
|
> In this mode:
|
package/bin/cli-path-config.js
CHANGED
|
@@ -58,13 +58,14 @@ export const combinedReportOutputRootDir = path.resolve(
|
|
|
58
58
|
|
|
59
59
|
export const staticDiscoveredLibraries = [
|
|
60
60
|
{
|
|
61
|
-
fullPath: 'packages/manager-
|
|
62
|
-
shortPath: 'manager-
|
|
63
|
-
packageName: '@ovh-ux/
|
|
64
|
-
},
|
|
65
|
-
{
|
|
66
|
-
fullPath: 'packages/manager-wiki',
|
|
67
|
-
shortPath: 'manager-wiki',
|
|
68
|
-
packageName: '@ovh-ux/manager-wiki',
|
|
61
|
+
fullPath: 'packages/manager-ui-kit',
|
|
62
|
+
shortPath: 'manager-ui-kit',
|
|
63
|
+
packageName: '@ovh-ux/muk',
|
|
69
64
|
},
|
|
70
65
|
];
|
|
66
|
+
|
|
67
|
+
export const typesSpecificIgnorePatterns = [
|
|
68
|
+
/(^|\/)(__tests__|tests?|spec|fixtures|stubs|mocks)\//i,
|
|
69
|
+
/\.(test|spec|stories?)\.(ts|tsx)$/i,
|
|
70
|
+
/(^|\/)i18n(\.ts|\.tsx)?$/i,
|
|
71
|
+
];
|
|
@@ -22,13 +22,13 @@ const cases = [
|
|
|
22
22
|
expect: 0,
|
|
23
23
|
},
|
|
24
24
|
{
|
|
25
|
-
name: 'Single library static path by folder name (manager-
|
|
26
|
-
cmd: 'yarn manager-code-duplication --library manager-
|
|
25
|
+
name: 'Single library static path by folder name (manager-ui-kit)',
|
|
26
|
+
cmd: 'yarn manager-code-duplication --library manager-ui-kit',
|
|
27
27
|
expect: 0,
|
|
28
28
|
},
|
|
29
29
|
{
|
|
30
|
-
name: 'Single library static path by package name (manager-
|
|
31
|
-
cmd: 'yarn manager-code-duplication --library @ovh-ux/
|
|
30
|
+
name: 'Single library static path by package name (manager-ui-kit)',
|
|
31
|
+
cmd: 'yarn manager-code-duplication --library @ovh-ux/muk',
|
|
32
32
|
expect: 0,
|
|
33
33
|
},
|
|
34
34
|
{
|
|
@@ -42,13 +42,13 @@ const cases = [
|
|
|
42
42
|
expect: 0,
|
|
43
43
|
},
|
|
44
44
|
{
|
|
45
|
-
name: 'Multiple libraries by folder names (manager-wiki,manager-
|
|
46
|
-
cmd: 'yarn manager-code-duplication --libraries manager-wiki,manager-
|
|
45
|
+
name: 'Multiple libraries by folder names (manager-wiki,manager-ui-kit,shell-client,logs-to-customer)',
|
|
46
|
+
cmd: 'yarn manager-code-duplication --libraries manager-wiki,manager-ui-kit,shell-client,logs-to-customer',
|
|
47
47
|
expect: 0,
|
|
48
48
|
},
|
|
49
49
|
{
|
|
50
|
-
name: 'Multiple libraries by package names (manager-wiki,manager-
|
|
51
|
-
cmd: 'yarn manager-code-duplication --libraries @ovh-ux/manager-wiki,@ovh-ux/
|
|
50
|
+
name: 'Multiple libraries by package names (manager-wiki,manager-ui-kit,shell-client,logs-to-customer)',
|
|
51
|
+
cmd: 'yarn manager-code-duplication --libraries @ovh-ux/manager-wiki,@ovh-ux/muk,@ovh-ux/manager-react-shell-client,@ovh-ux/logs-to-customer',
|
|
52
52
|
expect: 0,
|
|
53
53
|
},
|
|
54
54
|
{
|
|
@@ -58,7 +58,7 @@ const cases = [
|
|
|
58
58
|
},
|
|
59
59
|
{
|
|
60
60
|
name: 'Mixed valid+invalid packages',
|
|
61
|
-
cmd: 'yarn manager-code-duplication --packages @ovh-ux/manager-wiki,manager-
|
|
61
|
+
cmd: 'yarn manager-code-duplication --packages @ovh-ux/manager-wiki,manager-ui-kit,@ovh-ux/manager-ghost-app',
|
|
62
62
|
expect: 0,
|
|
63
63
|
},
|
|
64
64
|
{
|
package/bin/lint-cli.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { spawn } from 'node:child_process';
|
|
3
3
|
import { existsSync } from 'node:fs';
|
|
4
|
+
import { createRequire } from 'node:module';
|
|
4
5
|
import { dirname, join, resolve } from 'node:path';
|
|
5
6
|
import process, { cwd, execPath } from 'node:process';
|
|
6
7
|
import { fileURLToPath } from 'node:url';
|
|
7
|
-
import { createRequire } from 'node:module';
|
|
8
8
|
|
|
9
9
|
import { logError, logInfo } from './utils/log-utils.js';
|
|
10
10
|
|
|
@@ -44,16 +44,25 @@ const firstNonFlag = () => args.find((a) => !a.startsWith('--'));
|
|
|
44
44
|
|
|
45
45
|
const hasExplicitConfig = hasFlag('--config');
|
|
46
46
|
const localConfigCandidates = [
|
|
47
|
-
'eslint.config.ts',
|
|
48
|
-
'eslint.config.
|
|
47
|
+
'eslint.config.ts',
|
|
48
|
+
'eslint.config.mts',
|
|
49
|
+
'eslint.config.cts',
|
|
50
|
+
'eslint.config.mjs',
|
|
51
|
+
'eslint.config.cjs',
|
|
52
|
+
'eslint.config.js',
|
|
49
53
|
];
|
|
50
54
|
const localConfigPath = localConfigCandidates
|
|
51
55
|
.map((f) => join(userCwd, f))
|
|
52
56
|
.find((p) => existsSync(p));
|
|
53
57
|
|
|
54
|
-
const sharedDefaultPath = resolve(
|
|
58
|
+
const sharedDefaultPath = resolve(
|
|
59
|
+
__dirname,
|
|
60
|
+
'../dist/adapters/eslint/config/eslint-shared-config.js',
|
|
61
|
+
);
|
|
55
62
|
|
|
56
|
-
const configPath = hasExplicitConfig
|
|
63
|
+
const configPath = hasExplicitConfig
|
|
64
|
+
? getFlagValue('--config')
|
|
65
|
+
: (localConfigPath ?? sharedDefaultPath);
|
|
57
66
|
|
|
58
67
|
// ---------------------------------------------------------------------------
|
|
59
68
|
// Node preload for TS configs
|
|
@@ -67,14 +76,14 @@ if (needsTsx) {
|
|
|
67
76
|
require.resolve('tsx');
|
|
68
77
|
} catch {
|
|
69
78
|
logError('[manager-lint] A TypeScript eslint config was detected, but "tsx" is not installed.');
|
|
70
|
-
logError(
|
|
79
|
+
logError(
|
|
80
|
+
'Install it in @ovh-ux/manager-static-analysis-kit (or the invoking package) and retry.',
|
|
81
|
+
);
|
|
71
82
|
process.exit(1);
|
|
72
83
|
}
|
|
73
84
|
}
|
|
74
85
|
|
|
75
|
-
const nodePreload = needsTsx
|
|
76
|
-
? (nodeMajor >= 20 ? ['--import', 'tsx'] : ['--loader', 'tsx'])
|
|
77
|
-
: [];
|
|
86
|
+
const nodePreload = needsTsx ? (nodeMajor >= 20 ? ['--import', 'tsx'] : ['--loader', 'tsx']) : [];
|
|
78
87
|
|
|
79
88
|
// ---------------------------------------------------------------------------
|
|
80
89
|
// Build final ESLint argv
|
|
@@ -109,7 +118,14 @@ function run(procArgs) {
|
|
|
109
118
|
if (hasFlag('--print-config')) {
|
|
110
119
|
const target = firstNonFlag() ?? '.';
|
|
111
120
|
logInfo('[manager-lint] Using config:', configPath);
|
|
112
|
-
const code = await run([
|
|
121
|
+
const code = await run([
|
|
122
|
+
...nodePreload,
|
|
123
|
+
eslintCli,
|
|
124
|
+
'--config',
|
|
125
|
+
configPath,
|
|
126
|
+
'--print-config',
|
|
127
|
+
target,
|
|
128
|
+
]);
|
|
113
129
|
process.exit(code);
|
|
114
130
|
}
|
|
115
131
|
|
|
@@ -22,13 +22,13 @@ const cases = [
|
|
|
22
22
|
expect: 0,
|
|
23
23
|
},
|
|
24
24
|
{
|
|
25
|
-
name: 'Single library static path by folder name (manager-
|
|
26
|
-
cmd: 'yarn manager-perf-budgets --library manager-
|
|
25
|
+
name: 'Single library static path by folder name (manager-ui-kit)',
|
|
26
|
+
cmd: 'yarn manager-perf-budgets --library manager-ui-kit',
|
|
27
27
|
expect: 0,
|
|
28
28
|
},
|
|
29
29
|
{
|
|
30
|
-
name: 'Single library static path by package name (manager-
|
|
31
|
-
cmd: 'yarn manager-perf-budgets --library @ovh-ux/
|
|
30
|
+
name: 'Single library static path by package name (manager-ui-kit)',
|
|
31
|
+
cmd: 'yarn manager-perf-budgets --library @ovh-ux/muk',
|
|
32
32
|
expect: 0,
|
|
33
33
|
},
|
|
34
34
|
{
|
|
@@ -42,13 +42,13 @@ const cases = [
|
|
|
42
42
|
expect: 0,
|
|
43
43
|
},
|
|
44
44
|
{
|
|
45
|
-
name: 'Multiple libraries by folder names (manager-wiki,manager-
|
|
46
|
-
cmd: 'yarn manager-perf-budgets --libraries manager-wiki,manager-
|
|
45
|
+
name: 'Multiple libraries by folder names (manager-wiki,manager-ui-kit,shell-client,logs-to-customer)',
|
|
46
|
+
cmd: 'yarn manager-perf-budgets --libraries manager-wiki,manager-ui-kit,shell-client,logs-to-customer',
|
|
47
47
|
expect: 0,
|
|
48
48
|
},
|
|
49
49
|
{
|
|
50
|
-
name: 'Multiple libraries by package names (manager-wiki,manager-
|
|
51
|
-
cmd: 'yarn manager-perf-budgets --libraries @ovh-ux/manager-wiki,@ovh-ux/
|
|
50
|
+
name: 'Multiple libraries by package names (manager-wiki,manager-ui-kit,shell-client,logs-to-customer)',
|
|
51
|
+
cmd: 'yarn manager-perf-budgets --libraries @ovh-ux/manager-wiki,@ovh-ux/muk,@ovh-ux/manager-react-shell-client,@ovh-ux/logs-to-customer',
|
|
52
52
|
expect: 0,
|
|
53
53
|
},
|
|
54
54
|
{
|
|
@@ -58,7 +58,7 @@ const cases = [
|
|
|
58
58
|
},
|
|
59
59
|
{
|
|
60
60
|
name: 'Mixed valid+invalid packages',
|
|
61
|
-
cmd: 'yarn manager-perf-budgets --packages @ovh-ux/manager-wiki,manager-
|
|
61
|
+
cmd: 'yarn manager-perf-budgets --packages @ovh-ux/manager-wiki,manager-ui-kit,@ovh-ux/manager-ghost-app',
|
|
62
62
|
expect: 0,
|
|
63
63
|
},
|
|
64
64
|
{
|
|
@@ -22,13 +22,13 @@ const cases = [
|
|
|
22
22
|
expect: 0,
|
|
23
23
|
},
|
|
24
24
|
{
|
|
25
|
-
name: 'Single library static path by folder name (manager-
|
|
26
|
-
cmd: 'yarn manager-tests-coverage --library manager-
|
|
25
|
+
name: 'Single library static path by folder name (manager-ui-kit)',
|
|
26
|
+
cmd: 'yarn manager-tests-coverage --library manager-ui-kit',
|
|
27
27
|
expect: 0,
|
|
28
28
|
},
|
|
29
29
|
{
|
|
30
|
-
name: 'Single library static path by package name (manager-
|
|
31
|
-
cmd: 'yarn manager-tests-coverage --library @ovh-ux/
|
|
30
|
+
name: 'Single library static path by package name (manager-ui-kit)',
|
|
31
|
+
cmd: 'yarn manager-tests-coverage --library @ovh-ux/muk',
|
|
32
32
|
expect: 0,
|
|
33
33
|
},
|
|
34
34
|
{
|
|
@@ -42,13 +42,13 @@ const cases = [
|
|
|
42
42
|
expect: 0,
|
|
43
43
|
},
|
|
44
44
|
{
|
|
45
|
-
name: 'Multiple libraries by folder names (manager-wiki,manager-
|
|
46
|
-
cmd: 'yarn manager-tests-coverage --libraries manager-wiki,manager-
|
|
45
|
+
name: 'Multiple libraries by folder names (manager-wiki,manager-ui-kit,shell-client,logs-to-customer)',
|
|
46
|
+
cmd: 'yarn manager-tests-coverage --libraries manager-wiki,manager-ui-kit,shell-client,logs-to-customer',
|
|
47
47
|
expect: 0,
|
|
48
48
|
},
|
|
49
49
|
{
|
|
50
|
-
name: 'Multiple libraries by package names (manager-wiki,manager-
|
|
51
|
-
cmd: 'yarn manager-tests-coverage --libraries @ovh-ux/manager-wiki,@ovh-ux/
|
|
50
|
+
name: 'Multiple libraries by package names (manager-wiki,manager-ui-kit,shell-client,logs-to-customer)',
|
|
51
|
+
cmd: 'yarn manager-tests-coverage --libraries @ovh-ux/manager-wiki,@ovh-ux/muk,@ovh-ux/manager-react-shell-client,@ovh-ux/logs-to-customer',
|
|
52
52
|
expect: 0,
|
|
53
53
|
},
|
|
54
54
|
{
|
|
@@ -58,7 +58,7 @@ const cases = [
|
|
|
58
58
|
},
|
|
59
59
|
{
|
|
60
60
|
name: 'Mixed valid+invalid packages',
|
|
61
|
-
cmd: 'yarn manager-tests-coverage --packages @ovh-ux/manager-wiki,manager-
|
|
61
|
+
cmd: 'yarn manager-tests-coverage --packages @ovh-ux/manager-wiki,manager-ui-kit,@ovh-ux/manager-ghost-app',
|
|
62
62
|
expect: 0,
|
|
63
63
|
},
|
|
64
64
|
{
|
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
typesCoverageCombinedJsonReportName,
|
|
15
15
|
typesCoverageOutputRootDir,
|
|
16
16
|
typesCoverageReportsRootDirName,
|
|
17
|
+
typesSpecificIgnorePatterns,
|
|
17
18
|
} from './cli-path-config.js';
|
|
18
19
|
import { buildTypesCoverageArgs, parseCliTargets } from './utils/args-parse-utils.js';
|
|
19
20
|
import { logError, logInfo, logWarn } from './utils/log-utils.js';
|
|
@@ -102,12 +103,18 @@ export function countLooseTypes(appDir) {
|
|
|
102
103
|
visit(source);
|
|
103
104
|
}
|
|
104
105
|
|
|
106
|
+
function shouldIgnore(filePath) {
|
|
107
|
+
return typesSpecificIgnorePatterns.some((re) => re.test(filePath));
|
|
108
|
+
}
|
|
109
|
+
|
|
105
110
|
function walk(dir) {
|
|
106
111
|
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
107
112
|
const fullPath = path.join(dir, entry.name);
|
|
108
113
|
if (entry.isDirectory()) {
|
|
114
|
+
if (shouldIgnore(fullPath)) continue;
|
|
109
115
|
walk(fullPath);
|
|
110
116
|
} else if (/\.(ts|tsx)$/.test(entry.name)) {
|
|
117
|
+
if (shouldIgnore(fullPath)) continue;
|
|
111
118
|
analyzeFile(fullPath);
|
|
112
119
|
}
|
|
113
120
|
}
|
|
@@ -22,13 +22,13 @@ const cases = [
|
|
|
22
22
|
expect: 0,
|
|
23
23
|
},
|
|
24
24
|
{
|
|
25
|
-
name: 'Single library static path by folder name (manager-
|
|
26
|
-
cmd: 'yarn manager-types-coverage --library manager-
|
|
25
|
+
name: 'Single library static path by folder name (manager-ui-kit)',
|
|
26
|
+
cmd: 'yarn manager-types-coverage --library manager-ui-kit',
|
|
27
27
|
expect: 0,
|
|
28
28
|
},
|
|
29
29
|
{
|
|
30
|
-
name: 'Single library static path by package name (manager-
|
|
31
|
-
cmd: 'yarn manager-types-coverage --library @ovh-ux/
|
|
30
|
+
name: 'Single library static path by package name (manager-ui-kit)',
|
|
31
|
+
cmd: 'yarn manager-types-coverage --library @ovh-ux/muk',
|
|
32
32
|
expect: 0,
|
|
33
33
|
},
|
|
34
34
|
{
|
|
@@ -42,13 +42,13 @@ const cases = [
|
|
|
42
42
|
expect: 0,
|
|
43
43
|
},
|
|
44
44
|
{
|
|
45
|
-
name: 'Multiple libraries by folder names (manager-wiki,manager-
|
|
46
|
-
cmd: 'yarn manager-types-coverage --libraries manager-wiki,manager-
|
|
45
|
+
name: 'Multiple libraries by folder names (manager-wiki,manager-ui-kit,shell-client,logs-to-customer)',
|
|
46
|
+
cmd: 'yarn manager-types-coverage --libraries manager-wiki,manager-ui-kit,shell-client,logs-to-customer',
|
|
47
47
|
expect: 0,
|
|
48
48
|
},
|
|
49
49
|
{
|
|
50
|
-
name: 'Multiple libraries by package names (manager-wiki,manager-
|
|
51
|
-
cmd: 'yarn manager-types-coverage --libraries @ovh-ux/manager-wiki,@ovh-ux/
|
|
50
|
+
name: 'Multiple libraries by package names (manager-wiki,manager-ui-kit,shell-client,logs-to-customer)',
|
|
51
|
+
cmd: 'yarn manager-types-coverage --libraries @ovh-ux/manager-wiki,@ovh-ux/muk,@ovh-ux/manager-react-shell-client,@ovh-ux/logs-to-customer',
|
|
52
52
|
expect: 0,
|
|
53
53
|
},
|
|
54
54
|
{
|
|
@@ -58,7 +58,7 @@ const cases = [
|
|
|
58
58
|
},
|
|
59
59
|
{
|
|
60
60
|
name: 'Mixed valid+invalid packages',
|
|
61
|
-
cmd: 'yarn manager-types-coverage --packages @ovh-ux/manager-wiki,manager-
|
|
61
|
+
cmd: 'yarn manager-types-coverage --packages @ovh-ux/manager-wiki,manager-ui-kit,@ovh-ux/manager-ghost-app',
|
|
62
62
|
expect: 0,
|
|
63
63
|
},
|
|
64
64
|
{
|
|
@@ -2,6 +2,7 @@ import process from 'node:process';
|
|
|
2
2
|
|
|
3
3
|
import { codeDuplicationConfig } from '../../dist/configs/code-duplication-config.js';
|
|
4
4
|
import { typesCoverageConfig } from '../../dist/configs/types-coverage-config.js';
|
|
5
|
+
import { staticDiscoveredLibraries } from '../cli-path-config.js';
|
|
5
6
|
import { logError, logInfo } from './log-utils.js';
|
|
6
7
|
import { discoverModules, getModule } from './module-utils.js';
|
|
7
8
|
|
|
@@ -44,7 +45,7 @@ import { discoverModules, getModule } from './module-utils.js';
|
|
|
44
45
|
* parseArgs();
|
|
45
46
|
* // → [
|
|
46
47
|
* // { fullPath: "/.../packages/manager/core/core-shell", shortPath: "core-shell", packageName: "@ovh-ux/manager-core-shell" },
|
|
47
|
-
* // { fullPath: "/.../packages/components/react-components", shortPath: "react-components", packageName: "@ovh-ux/
|
|
48
|
+
* // { fullPath: "/.../packages/components/react-components", shortPath: "react-components", packageName: "@ovh-ux/muk" }
|
|
48
49
|
* // ]
|
|
49
50
|
*/
|
|
50
51
|
export function parseArgs() {
|
|
@@ -54,7 +55,7 @@ export function parseArgs() {
|
|
|
54
55
|
|
|
55
56
|
const moduleModeArgs = libsArg || packagesArg || appsArg;
|
|
56
57
|
|
|
57
|
-
if (!moduleModeArgs) return discoverModules(false);
|
|
58
|
+
if (!moduleModeArgs) return [...discoverModules(false), ...staticDiscoveredLibraries];
|
|
58
59
|
|
|
59
60
|
const index = process.argv.indexOf(moduleModeArgs);
|
|
60
61
|
const rawValue = process.argv[index + 1] || '';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { CombinedCodeDuplicationSummary, JscpdReportV4, WorstCodeDuplicationFile } from '../types/CodeDuplication.js';
|
|
2
|
-
export declare const
|
|
2
|
+
export declare const buildExtensionPriority: (file: string) => number;
|
|
3
3
|
export declare function extractWorstFiles(report: JscpdReportV4): {
|
|
4
4
|
files: WorstCodeDuplicationFile[];
|
|
5
5
|
fileCount: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"code-duplication-analysis-helper.d.ts","sourceRoot":"","sources":["../../../../src/adapters/code-duplication/helpers/code-duplication-analysis-helper.ts"],"names":[],"mappings":"AAIA,OAAO,EAEL,8BAA8B,EAC9B,aAAa,EACb,wBAAwB,EAEzB,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"code-duplication-analysis-helper.d.ts","sourceRoot":"","sources":["../../../../src/adapters/code-duplication/helpers/code-duplication-analysis-helper.ts"],"names":[],"mappings":"AAIA,OAAO,EAEL,8BAA8B,EAC9B,aAAa,EACb,wBAAwB,EAEzB,MAAM,0BAA0B,CAAC;AAelC,eAAO,MAAM,sBAAsB,GAAI,MAAM,MAAM,KAAG,MAMrD,CAAC;AAmBF,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,aAAa;;;EAsDtD;AAyED,wBAAgB,sBAAsB,CAAC,eAAe,EAAE,MAAM,GAAG,8BAA8B,CA+B9F;AAOD,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,8BAA8B,GAAG,MAAM,CAQ3F"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { codeDuplicationConfig } from '../../../configs/code-duplication-config.js';
|
|
4
|
-
|
|
4
|
+
import { buildDuplicationReportBody, buildDuplicationReportHead, } from './code-duplication-reports-render.js';
|
|
5
|
+
export const buildExtensionPriority = (file) => {
|
|
5
6
|
const f = file.toLowerCase();
|
|
6
7
|
if (/\.(d\.ts)$/.test(f))
|
|
7
8
|
return 2;
|
|
@@ -11,7 +12,7 @@ export const extPriority = (file) => {
|
|
|
11
12
|
return 1;
|
|
12
13
|
return 2;
|
|
13
14
|
};
|
|
14
|
-
const
|
|
15
|
+
const countRealLines = (file) => {
|
|
15
16
|
try {
|
|
16
17
|
const txt = fs.readFileSync(file, 'utf8');
|
|
17
18
|
return txt.split(/\r?\n/).length;
|
|
@@ -20,15 +21,6 @@ const safeCountLines = (file) => {
|
|
|
20
21
|
return 0;
|
|
21
22
|
}
|
|
22
23
|
};
|
|
23
|
-
function shortPathFromAppsRoot(filePath, app) {
|
|
24
|
-
const norm = filePath.replace(/\\/g, '/');
|
|
25
|
-
const appsIdx = norm.indexOf('/apps/');
|
|
26
|
-
if (appsIdx >= 0) {
|
|
27
|
-
return norm.slice(appsIdx + 1);
|
|
28
|
-
}
|
|
29
|
-
const parts = norm.split('/');
|
|
30
|
-
return parts.slice(Math.max(0, parts.length - 5)).join('/');
|
|
31
|
-
}
|
|
32
24
|
export function extractWorstFiles(report) {
|
|
33
25
|
const dups = Array.isArray(report?.duplicates) ? report.duplicates : [];
|
|
34
26
|
if (dups.length === 0)
|
|
@@ -52,7 +44,7 @@ export function extractWorstFiles(report) {
|
|
|
52
44
|
}
|
|
53
45
|
}
|
|
54
46
|
for (const file of Object.keys(fileMap)) {
|
|
55
|
-
const realTotal =
|
|
47
|
+
const realTotal = countRealLines(file);
|
|
56
48
|
const estTotal = fileMap[file].estimatedTotal;
|
|
57
49
|
fileMap[file].total = Math.max(realTotal || estTotal || 0, fileMap[file].dup);
|
|
58
50
|
}
|
|
@@ -68,19 +60,17 @@ export function extractWorstFiles(report) {
|
|
|
68
60
|
})
|
|
69
61
|
.filter(([, s]) => s.percentage >= threshold)
|
|
70
62
|
.sort((a, b) => {
|
|
71
|
-
const pa =
|
|
72
|
-
const pb =
|
|
63
|
+
const pa = buildExtensionPriority(a[0]);
|
|
64
|
+
const pb = buildExtensionPriority(b[0]);
|
|
73
65
|
if (pa !== pb)
|
|
74
66
|
return pa - pb;
|
|
75
67
|
const pct = b[1].percentage - a[1].percentage;
|
|
76
68
|
if (pct !== 0)
|
|
77
69
|
return pct;
|
|
78
|
-
if (b[1].duplicatedLines !== a[1].duplicatedLines)
|
|
70
|
+
if (b[1].duplicatedLines !== a[1].duplicatedLines)
|
|
79
71
|
return b[1].duplicatedLines - a[1].duplicatedLines;
|
|
80
|
-
|
|
81
|
-
if (b[1].totalLines !== a[1].totalLines) {
|
|
72
|
+
if (b[1].totalLines !== a[1].totalLines)
|
|
82
73
|
return b[1].totalLines - a[1].totalLines;
|
|
83
|
-
}
|
|
84
74
|
return a[0].localeCompare(b[0]);
|
|
85
75
|
})
|
|
86
76
|
.slice(0, count);
|
|
@@ -126,7 +116,7 @@ function parseAppCodeDuplicationReport(jsonPath) {
|
|
|
126
116
|
};
|
|
127
117
|
}
|
|
128
118
|
}
|
|
129
|
-
function
|
|
119
|
+
function aggregateDuplicationTotals(apps) {
|
|
130
120
|
return Object.values(apps).reduce((acc, app) => {
|
|
131
121
|
acc.totalLines += app.totalLines;
|
|
132
122
|
acc.totalTokens += app.totalTokens;
|
|
@@ -156,139 +146,19 @@ export function collectCodeDuplication(reportOutputDir) {
|
|
|
156
146
|
apps[appDirName] = parseAppCodeDuplicationReport(jsonPath);
|
|
157
147
|
}
|
|
158
148
|
}
|
|
159
|
-
const totals =
|
|
149
|
+
const totals = aggregateDuplicationTotals(apps);
|
|
160
150
|
return {
|
|
161
151
|
apps,
|
|
162
152
|
...totals,
|
|
163
153
|
percentage: totals.totalLines > 0 ? (totals.totalDuplicateLines / totals.totalLines) * 100 : 0,
|
|
164
154
|
};
|
|
165
155
|
}
|
|
166
|
-
const getColorForDuplicationStatus = (pct) => {
|
|
167
|
-
const green = codeDuplicationConfig.thresholds?.green ?? 10;
|
|
168
|
-
const orange = codeDuplicationConfig.thresholds?.orange ?? 20;
|
|
169
|
-
return pct < green ? 'green' : pct < orange ? 'orange' : 'red';
|
|
170
|
-
};
|
|
171
|
-
function renderWorstFiles(app, worstFiles = []) {
|
|
172
|
-
const threshold = codeDuplicationConfig.worstFiles.threshold;
|
|
173
|
-
if (!worstFiles.length) {
|
|
174
|
-
return `
|
|
175
|
-
<details class="coverage-details">
|
|
176
|
-
<summary>📊 Duplication Overview for <strong>${app}</strong></summary>
|
|
177
|
-
<p class="coverage-empty">No files above threshold 🎉</p>
|
|
178
|
-
</details>`;
|
|
179
|
-
}
|
|
180
|
-
const rows = worstFiles
|
|
181
|
-
.map(([file, f]) => {
|
|
182
|
-
const short = shortPathFromAppsRoot(file, app);
|
|
183
|
-
const color = getColorForDuplicationStatus(f.percentage);
|
|
184
|
-
return `
|
|
185
|
-
<tr>
|
|
186
|
-
<td colspan="2" title="${file}">${short}</td>
|
|
187
|
-
<td>${f.duplicatedLines}/${f.totalLines}</td>
|
|
188
|
-
<td style="color:${color}">${f.percentage.toFixed(2)}%</td>
|
|
189
|
-
</tr>`;
|
|
190
|
-
})
|
|
191
|
-
.join('');
|
|
192
|
-
return `
|
|
193
|
-
<details class="coverage-details">
|
|
194
|
-
<summary>📊 Duplication Overview for <strong>${app}</strong> (≥ ${threshold}%)</summary>
|
|
195
|
-
<table class="coverage-subtable">
|
|
196
|
-
<tbody>${rows}</tbody>
|
|
197
|
-
</table>
|
|
198
|
-
</details>`;
|
|
199
|
-
}
|
|
200
|
-
function renderDuplicationCell(stats) {
|
|
201
|
-
const min = stats.minPercentage ?? stats.percentage;
|
|
202
|
-
const max = stats.maxPercentage ?? stats.percentage;
|
|
203
|
-
if (stats.duplicateLines === 0) {
|
|
204
|
-
return `<span style="color:${getColorForDuplicationStatus(0)}">0.00%</span>`;
|
|
205
|
-
}
|
|
206
|
-
if (min.toFixed(2) === max.toFixed(2)) {
|
|
207
|
-
return `
|
|
208
|
-
${stats.percentage.toFixed(2)}% (${stats.filesWithDuplication} files cluster at
|
|
209
|
-
<span style="color:${getColorForDuplicationStatus(min)}">${min.toFixed(2)}%</span>)
|
|
210
|
-
`;
|
|
211
|
-
}
|
|
212
|
-
return `
|
|
213
|
-
${stats.percentage.toFixed(2)}% (range:
|
|
214
|
-
<span style="color:${getColorForDuplicationStatus(min)}">${min.toFixed(2)}%</span> –
|
|
215
|
-
<span style="color:${getColorForDuplicationStatus(max)}">${max.toFixed(2)}%</span>)
|
|
216
|
-
`;
|
|
217
|
-
}
|
|
218
|
-
function buildAppRow(app, stats) {
|
|
219
|
-
if (stats.error) {
|
|
220
|
-
return `<tr style="background:#ffe0e0">
|
|
221
|
-
<td>${app}</td>
|
|
222
|
-
<td colspan="5" style="color:red">${stats.error}</td>
|
|
223
|
-
</tr>`;
|
|
224
|
-
}
|
|
225
|
-
const max = stats.maxPercentage ?? stats.percentage;
|
|
226
|
-
const rowColor = getColorForDuplicationStatus(max);
|
|
227
|
-
const bg = rowColor === 'green' ? '#e6ffed' : rowColor === 'orange' ? '#fff8e1' : '#ffe6e6';
|
|
228
|
-
return `
|
|
229
|
-
<tr style="background:${bg}">
|
|
230
|
-
<td>${app}</td>
|
|
231
|
-
<td>${stats.totalLines}</td>
|
|
232
|
-
<td>${stats.duplicateLines}</td>
|
|
233
|
-
<td>${stats.clonesCount}</td>
|
|
234
|
-
<td style="font-weight:bold;">${renderDuplicationCell(stats)}</td>
|
|
235
|
-
</tr>
|
|
236
|
-
<tr><td colspan="5">${renderWorstFiles(app, stats.worstFiles)}</td></tr>`;
|
|
237
|
-
}
|
|
238
156
|
export function generateCodeDuplicationHtml(summary) {
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
.join('');
|
|
242
|
-
return `<!DOCTYPE html>
|
|
157
|
+
return `
|
|
158
|
+
<!DOCTYPE html>
|
|
243
159
|
<html lang="en">
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
body { font-family: Arial, sans-serif; margin: 2rem; }
|
|
249
|
-
table { border-collapse: collapse; width: 100%; }
|
|
250
|
-
th, td { border: 1px solid #ccc; padding: 0.5rem; text-align: left; }
|
|
251
|
-
th { background: #f0f0f0; }
|
|
252
|
-
.coverage-details {
|
|
253
|
-
margin: 0.3rem 0 0.8rem 1.5rem;
|
|
254
|
-
padding: 0.5rem;
|
|
255
|
-
border-left: 3px solid #ccc;
|
|
256
|
-
background: #fafafa;
|
|
257
|
-
border-radius: 4px;
|
|
258
|
-
}
|
|
259
|
-
.coverage-details summary {
|
|
260
|
-
font-weight: bold;
|
|
261
|
-
cursor: pointer;
|
|
262
|
-
}
|
|
263
|
-
.coverage-subtable {
|
|
264
|
-
margin-top: 0.5rem;
|
|
265
|
-
border: 1px solid #ddd;
|
|
266
|
-
width: 95%;
|
|
267
|
-
font-size: 0.9em;
|
|
268
|
-
}
|
|
269
|
-
.coverage-empty {
|
|
270
|
-
margin: 0.5rem 0;
|
|
271
|
-
color: #888;
|
|
272
|
-
font-style: italic;
|
|
273
|
-
}
|
|
274
|
-
</style>
|
|
275
|
-
</head>
|
|
276
|
-
<body>
|
|
277
|
-
<h1>Code Duplication Report</h1>
|
|
278
|
-
<p>Total lines: ${summary.totalLines}, Duplicate lines: ${summary.totalDuplicateLines},
|
|
279
|
-
Percentage: ${summary.percentage.toFixed(2)}%</p>
|
|
280
|
-
<table>
|
|
281
|
-
<thead>
|
|
282
|
-
<tr>
|
|
283
|
-
<th>App</th>
|
|
284
|
-
<th>Total lines</th>
|
|
285
|
-
<th>Duplicate lines</th>
|
|
286
|
-
<th>Clones</th>
|
|
287
|
-
<th>Duplication %</th>
|
|
288
|
-
</tr>
|
|
289
|
-
</thead>
|
|
290
|
-
<tbody>${rows}</tbody>
|
|
291
|
-
</table>
|
|
292
|
-
</body>
|
|
293
|
-
</html>`;
|
|
160
|
+
${buildDuplicationReportHead()}
|
|
161
|
+
${buildDuplicationReportBody(summary)}
|
|
162
|
+
</html>
|
|
163
|
+
`.trim();
|
|
294
164
|
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { CombinedCodeDuplicationSummary } from '../types/CodeDuplication.js';
|
|
2
|
+
export declare function buildDuplicationReportHead(): string;
|
|
3
|
+
export declare function buildDuplicationReportBody(summary: CombinedCodeDuplicationSummary): string;
|
|
4
|
+
//# sourceMappingURL=code-duplication-reports-render.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"code-duplication-reports-render.d.ts","sourceRoot":"","sources":["../../../../src/adapters/code-duplication/helpers/code-duplication-reports-render.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,8BAA8B,EAC/B,MAAM,0BAA0B,CAAC;AA4HlC,wBAAgB,0BAA0B,IAAI,MAAM,CAgCnD;AAOD,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,8BAA8B,GAAG,MAAM,CA0B1F"}
|