@code-pushup/core 0.56.0 → 0.58.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/package.json +8 -7
- package/src/index.d.ts +11 -11
- package/src/index.js +10 -0
- package/src/index.js.map +1 -0
- package/src/lib/collect-and-persist.d.ts +1 -1
- package/src/lib/collect-and-persist.js +21 -0
- package/src/lib/collect-and-persist.js.map +1 -0
- package/src/lib/compare.js +96 -0
- package/src/lib/compare.js.map +1 -0
- package/src/lib/history.d.ts +1 -1
- package/src/lib/history.js +38 -0
- package/src/lib/history.js.map +1 -0
- package/src/lib/implementation/collect.d.ts +1 -1
- package/src/lib/implementation/collect.js +25 -0
- package/src/lib/implementation/collect.js.map +1 -0
- package/src/lib/implementation/compare-scorables.js +117 -0
- package/src/lib/implementation/compare-scorables.js.map +1 -0
- package/src/lib/implementation/execute-plugin.js +126 -0
- package/src/lib/implementation/execute-plugin.js.map +1 -0
- package/src/lib/implementation/persist.js +56 -0
- package/src/lib/implementation/persist.js.map +1 -0
- package/src/lib/implementation/read-rc-file.js +43 -0
- package/src/lib/implementation/read-rc-file.js.map +1 -0
- package/src/lib/implementation/report-to-gql.js +133 -0
- package/src/lib/implementation/report-to-gql.js.map +1 -0
- package/src/lib/implementation/runner.js +36 -0
- package/src/lib/implementation/runner.js.map +1 -0
- package/src/lib/load-portal-client.js +11 -0
- package/src/lib/load-portal-client.js.map +1 -0
- package/src/lib/merge-diffs.js +33 -0
- package/src/lib/merge-diffs.js.map +1 -0
- package/src/lib/normalize.js +31 -0
- package/src/lib/normalize.js.map +1 -0
- package/src/lib/types.js +2 -0
- package/src/lib/types.js.map +1 -0
- package/src/lib/upload.d.ts +1 -1
- package/src/lib/upload.js +34 -0
- package/src/lib/upload.js.map +1 -0
- package/index.js +0 -3249
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@code-pushup/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.58.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "Core business logic for the used by the Code PushUp CLI",
|
|
6
6
|
"homepage": "https://github.com/code-pushup/cli/tree/main/packages/core#readme",
|
|
@@ -38,11 +38,9 @@
|
|
|
38
38
|
"access": "public"
|
|
39
39
|
},
|
|
40
40
|
"type": "module",
|
|
41
|
-
"main": "./index.js",
|
|
42
|
-
"types": "./src/index.d.ts",
|
|
43
41
|
"dependencies": {
|
|
44
|
-
"@code-pushup/models": "0.
|
|
45
|
-
"@code-pushup/utils": "0.
|
|
42
|
+
"@code-pushup/models": "0.58.0",
|
|
43
|
+
"@code-pushup/utils": "0.58.0",
|
|
46
44
|
"ansis": "^3.3.0"
|
|
47
45
|
},
|
|
48
46
|
"peerDependencies": {
|
|
@@ -52,5 +50,8 @@
|
|
|
52
50
|
"@code-pushup/portal-client": {
|
|
53
51
|
"optional": true
|
|
54
52
|
}
|
|
55
|
-
}
|
|
56
|
-
|
|
53
|
+
},
|
|
54
|
+
"module": "./src/index.js",
|
|
55
|
+
"main": "./src/index.js",
|
|
56
|
+
"types": "./src/index.d.ts"
|
|
57
|
+
}
|
package/src/index.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
export { type CollectAndPersistReportsOptions, collectAndPersistReports, } from './lib/collect-and-persist';
|
|
2
|
-
export { compareReportFiles, compareReports } from './lib/compare';
|
|
3
|
-
export { type CollectOptions, collect } from './lib/implementation/collect';
|
|
4
|
-
export type { ReportsToCompare } from './lib/implementation/compare-scorables';
|
|
5
|
-
export { PluginOutputMissingAuditError, executePlugin, executePlugins, } from './lib/implementation/execute-plugin';
|
|
6
|
-
export { PersistDirError, PersistError, persistReport, } from './lib/implementation/persist';
|
|
7
|
-
export { history, type HistoryOptions, type HistoryOnlyOptions, } from './lib/history';
|
|
8
|
-
export { ConfigPathError, autoloadRc, readRcByPath, } from './lib/implementation/read-rc-file';
|
|
9
|
-
export type { GlobalOptions } from './lib/types';
|
|
10
|
-
export { type UploadOptions, upload } from './lib/upload';
|
|
11
|
-
export { mergeDiffs } from './lib/merge-diffs';
|
|
1
|
+
export { type CollectAndPersistReportsOptions, collectAndPersistReports, } from './lib/collect-and-persist.js';
|
|
2
|
+
export { compareReportFiles, compareReports } from './lib/compare.js';
|
|
3
|
+
export { type CollectOptions, collect } from './lib/implementation/collect.js';
|
|
4
|
+
export type { ReportsToCompare } from './lib/implementation/compare-scorables.js';
|
|
5
|
+
export { PluginOutputMissingAuditError, executePlugin, executePlugins, } from './lib/implementation/execute-plugin.js';
|
|
6
|
+
export { PersistDirError, PersistError, persistReport, } from './lib/implementation/persist.js';
|
|
7
|
+
export { history, type HistoryOptions, type HistoryOnlyOptions, } from './lib/history.js';
|
|
8
|
+
export { ConfigPathError, autoloadRc, readRcByPath, } from './lib/implementation/read-rc-file.js';
|
|
9
|
+
export type { GlobalOptions } from './lib/types.js';
|
|
10
|
+
export { type UploadOptions, upload } from './lib/upload.js';
|
|
11
|
+
export { mergeDiffs } from './lib/merge-diffs.js';
|
package/src/index.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { collectAndPersistReports, } from './lib/collect-and-persist.js';
|
|
2
|
+
export { compareReportFiles, compareReports } from './lib/compare.js';
|
|
3
|
+
export { collect } from './lib/implementation/collect.js';
|
|
4
|
+
export { PluginOutputMissingAuditError, executePlugin, executePlugins, } from './lib/implementation/execute-plugin.js';
|
|
5
|
+
export { PersistDirError, PersistError, persistReport, } from './lib/implementation/persist.js';
|
|
6
|
+
export { history, } from './lib/history.js';
|
|
7
|
+
export { ConfigPathError, autoloadRc, readRcByPath, } from './lib/implementation/read-rc-file.js';
|
|
8
|
+
export { upload } from './lib/upload.js';
|
|
9
|
+
export { mergeDiffs } from './lib/merge-diffs.js';
|
|
10
|
+
//# sourceMappingURL=index.js.map
|
package/src/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../packages/core/src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,wBAAwB,GACzB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AACtE,OAAO,EAAuB,OAAO,EAAE,MAAM,iCAAiC,CAAC;AAE/E,OAAO,EACL,6BAA6B,EAC7B,aAAa,EACb,cAAc,GACf,MAAM,wCAAwC,CAAC;AAChD,OAAO,EACL,eAAe,EACf,YAAY,EACZ,aAAa,GACd,MAAM,iCAAiC,CAAC;AACzC,OAAO,EACL,OAAO,GAGR,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,eAAe,EACf,UAAU,EACV,YAAY,GACb,MAAM,sCAAsC,CAAC;AAE9C,OAAO,EAAsB,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAC7D,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type CoreConfig, type PersistConfig } from '@code-pushup/models';
|
|
2
|
-
import type { GlobalOptions } from './types';
|
|
2
|
+
import type { GlobalOptions } from './types.js';
|
|
3
3
|
export type CollectAndPersistReportsOptions = Pick<CoreConfig, 'plugins' | 'categories'> & {
|
|
4
4
|
persist: Required<PersistConfig>;
|
|
5
5
|
} & Partial<GlobalOptions>;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { pluginReportSchema, } from '@code-pushup/models';
|
|
2
|
+
import { logStdoutSummary, scoreReport, sortReport, verboseUtils, } from '@code-pushup/utils';
|
|
3
|
+
import { collect } from './implementation/collect.js';
|
|
4
|
+
import { logPersistedResults, persistReport, } from './implementation/persist.js';
|
|
5
|
+
export async function collectAndPersistReports(options) {
|
|
6
|
+
const { exec } = verboseUtils(options.verbose);
|
|
7
|
+
const report = await collect(options);
|
|
8
|
+
const sortedScoredReport = sortReport(scoreReport(report));
|
|
9
|
+
const persistResults = await persistReport(report, sortedScoredReport, options.persist);
|
|
10
|
+
// terminal output
|
|
11
|
+
logStdoutSummary(sortedScoredReport, options.verbose);
|
|
12
|
+
exec(() => {
|
|
13
|
+
logPersistedResults(persistResults);
|
|
14
|
+
});
|
|
15
|
+
// validate report and throw if invalid
|
|
16
|
+
report.plugins.forEach(plugin => {
|
|
17
|
+
// Running checks after persisting helps while debugging as you can check the invalid output after the error is thrown
|
|
18
|
+
pluginReportSchema.parse(plugin);
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=collect-and-persist.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"collect-and-persist.js","sourceRoot":"","sources":["../../../../../packages/core/src/lib/collect-and-persist.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,kBAAkB,GACnB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,gBAAgB,EAChB,WAAW,EACX,UAAU,EACV,YAAY,GACb,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,OAAO,EAAE,MAAM,6BAA6B,CAAC;AACtD,OAAO,EACL,mBAAmB,EACnB,aAAa,GACd,MAAM,6BAA6B,CAAC;AAQrC,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAC5C,OAAwC;IAExC,MAAM,EAAE,IAAI,EAAE,GAAG,YAAY,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAE/C,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;IACtC,MAAM,kBAAkB,GAAG,UAAU,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC;IAE3D,MAAM,cAAc,GAAG,MAAM,aAAa,CACxC,MAAM,EACN,kBAAkB,EAClB,OAAO,CAAC,OAAO,CAChB,CAAC;IAEF,kBAAkB;IAClB,gBAAgB,CAAC,kBAAkB,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;IAEtD,IAAI,CAAC,GAAG,EAAE;QACR,mBAAmB,CAAC,cAAc,CAAC,CAAC;IACtC,CAAC,CAAC,CAAC;IAEH,uCAAuC;IACvC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE;QAC9B,sHAAsH;QACtH,kBAAkB,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IACnC,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { writeFile } from 'node:fs/promises';
|
|
2
|
+
import { createRequire } from 'node:module';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { reportSchema, } from '@code-pushup/models';
|
|
5
|
+
import { calcDuration, ensureDirectoryExists, generateMdReportsDiff, readJsonFile, scoreReport, ui, } from '@code-pushup/utils';
|
|
6
|
+
import { compareAudits, compareCategories, compareGroups, } from './implementation/compare-scorables.js';
|
|
7
|
+
import { loadPortalClient } from './load-portal-client.js';
|
|
8
|
+
export async function compareReportFiles(inputPaths, persistConfig, uploadConfig, label) {
|
|
9
|
+
const { outputDir, filename, format } = persistConfig;
|
|
10
|
+
const [reportBefore, reportAfter] = await Promise.all([
|
|
11
|
+
readJsonFile(inputPaths.before),
|
|
12
|
+
readJsonFile(inputPaths.after),
|
|
13
|
+
]);
|
|
14
|
+
const reports = {
|
|
15
|
+
before: reportSchema.parse(reportBefore),
|
|
16
|
+
after: reportSchema.parse(reportAfter),
|
|
17
|
+
};
|
|
18
|
+
const diff = compareReports(reports);
|
|
19
|
+
if (label) {
|
|
20
|
+
// eslint-disable-next-line functional/immutable-data
|
|
21
|
+
diff.label = label;
|
|
22
|
+
}
|
|
23
|
+
if (uploadConfig && diff.commits) {
|
|
24
|
+
// eslint-disable-next-line functional/immutable-data
|
|
25
|
+
diff.portalUrl = await fetchPortalComparisonLink(uploadConfig, diff.commits);
|
|
26
|
+
}
|
|
27
|
+
return Promise.all(format.map(async (fmt) => {
|
|
28
|
+
const outputPath = path.join(outputDir, `${filename}-diff.${fmt}`);
|
|
29
|
+
const content = reportsDiffToFileContent(diff, fmt);
|
|
30
|
+
await ensureDirectoryExists(outputDir);
|
|
31
|
+
await writeFile(outputPath, content);
|
|
32
|
+
return outputPath;
|
|
33
|
+
}));
|
|
34
|
+
}
|
|
35
|
+
export function compareReports(reports) {
|
|
36
|
+
const start = performance.now();
|
|
37
|
+
const date = new Date().toISOString();
|
|
38
|
+
const commits = reports.before.commit != null && reports.after.commit != null
|
|
39
|
+
? { before: reports.before.commit, after: reports.after.commit }
|
|
40
|
+
: null;
|
|
41
|
+
const scoredReports = {
|
|
42
|
+
before: scoreReport(reports.before),
|
|
43
|
+
after: scoreReport(reports.after),
|
|
44
|
+
};
|
|
45
|
+
const categories = compareCategories(scoredReports);
|
|
46
|
+
const groups = compareGroups(scoredReports);
|
|
47
|
+
const audits = compareAudits(scoredReports);
|
|
48
|
+
const duration = calcDuration(start);
|
|
49
|
+
const packageJson = createRequire(import.meta.url)('../../package.json');
|
|
50
|
+
return {
|
|
51
|
+
commits,
|
|
52
|
+
categories,
|
|
53
|
+
groups,
|
|
54
|
+
audits,
|
|
55
|
+
packageName: packageJson.name,
|
|
56
|
+
version: packageJson.version,
|
|
57
|
+
date,
|
|
58
|
+
duration,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
function reportsDiffToFileContent(reportsDiff, format) {
|
|
62
|
+
switch (format) {
|
|
63
|
+
case 'json':
|
|
64
|
+
return JSON.stringify(reportsDiff, null, 2);
|
|
65
|
+
case 'md':
|
|
66
|
+
return generateMdReportsDiff(reportsDiff);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
async function fetchPortalComparisonLink(uploadConfig, commits) {
|
|
70
|
+
const { server, apiKey, organization, project } = uploadConfig;
|
|
71
|
+
const portalClient = await loadPortalClient();
|
|
72
|
+
if (!portalClient) {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
const { PortalOperationError, getPortalComparisonLink } = portalClient;
|
|
76
|
+
try {
|
|
77
|
+
return await getPortalComparisonLink({
|
|
78
|
+
server,
|
|
79
|
+
apiKey,
|
|
80
|
+
parameters: {
|
|
81
|
+
organization,
|
|
82
|
+
project,
|
|
83
|
+
before: commits.before.hash,
|
|
84
|
+
after: commits.after.hash,
|
|
85
|
+
},
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
catch (error) {
|
|
89
|
+
if (error instanceof PortalOperationError) {
|
|
90
|
+
ui().logger.warning(`Failed to fetch portal comparison link - ${error.message}`);
|
|
91
|
+
return undefined;
|
|
92
|
+
}
|
|
93
|
+
throw error;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=compare.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compare.js","sourceRoot":"","sources":["../../../../../packages/core/src/lib/compare.ts"],"names":[],"mappings":"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"}
|
package/src/lib/history.d.ts
CHANGED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { getCurrentBranchOrTag, safeCheckout, ui } from '@code-pushup/utils';
|
|
2
|
+
import { collectAndPersistReports } from './collect-and-persist.js';
|
|
3
|
+
import { upload } from './upload.js';
|
|
4
|
+
export async function history(config, commits) {
|
|
5
|
+
const initialBranch = await getCurrentBranchOrTag();
|
|
6
|
+
const { skipUploads = false, forceCleanStatus, persist } = config;
|
|
7
|
+
const reports = [];
|
|
8
|
+
// eslint-disable-next-line functional/no-loop-statements
|
|
9
|
+
for (const commit of commits) {
|
|
10
|
+
ui().logger.info(`Collect ${commit}`);
|
|
11
|
+
await safeCheckout(commit, forceCleanStatus);
|
|
12
|
+
const currentConfig = {
|
|
13
|
+
...config,
|
|
14
|
+
persist: {
|
|
15
|
+
...persist,
|
|
16
|
+
format: ['json'],
|
|
17
|
+
filename: `${commit}-report`,
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
|
+
await collectAndPersistReports(currentConfig);
|
|
21
|
+
if (skipUploads) {
|
|
22
|
+
ui().logger.info('Upload is skipped because skipUploads is set to true.');
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
if (currentConfig.upload) {
|
|
26
|
+
await upload(currentConfig);
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
ui().logger.info('Upload is skipped because upload config is undefined.');
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
// eslint-disable-next-line functional/immutable-data
|
|
33
|
+
reports.push(currentConfig.persist.filename);
|
|
34
|
+
}
|
|
35
|
+
await safeCheckout(initialBranch, forceCleanStatus);
|
|
36
|
+
return reports;
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=history.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"history.js","sourceRoot":"","sources":["../../../../../packages/core/src/lib/history.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,qBAAqB,EAAE,YAAY,EAAE,EAAE,EAAE,MAAM,oBAAoB,CAAC;AAC7E,OAAO,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AAEpE,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAarC,MAAM,CAAC,KAAK,UAAU,OAAO,CAC3B,MAAsB,EACtB,OAAiB;IAEjB,MAAM,aAAa,GAAW,MAAM,qBAAqB,EAAE,CAAC;IAE5D,MAAM,EAAE,WAAW,GAAG,KAAK,EAAE,gBAAgB,EAAE,OAAO,EAAE,GAAG,MAAM,CAAC;IAElE,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,yDAAyD;IACzD,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,MAAM,EAAE,CAAC,CAAC;QACtC,MAAM,YAAY,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;QAE7C,MAAM,aAAa,GAAmB;YACpC,GAAG,MAAM;YACT,OAAO,EAAE;gBACP,GAAG,OAAO;gBACV,MAAM,EAAE,CAAC,MAAM,CAAC;gBAChB,QAAQ,EAAE,GAAG,MAAM,SAAS;aAC7B;SACF,CAAC;QAEF,MAAM,wBAAwB,CAAC,aAAa,CAAC,CAAC;QAE9C,IAAI,WAAW,EAAE,CAAC;YAChB,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,uDAAuD,CAAC,CAAC;QAC5E,CAAC;aAAM,CAAC;YACN,IAAI,aAAa,CAAC,MAAM,EAAE,CAAC;gBACzB,MAAM,MAAM,CAAC,aAAa,CAAC,CAAC;YAC9B,CAAC;iBAAM,CAAC;gBACN,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CACd,uDAAuD,CACxD,CAAC;YACJ,CAAC;QACH,CAAC;QAED,qDAAqD;QACrD,OAAO,CAAC,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC/C,CAAC;IAED,MAAM,YAAY,CAAC,aAAa,EAAE,gBAAgB,CAAC,CAAC;IAEpD,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { CoreConfig, Report } from '@code-pushup/models';
|
|
2
|
-
import type { GlobalOptions } from '../types';
|
|
2
|
+
import type { GlobalOptions } from '../types.js';
|
|
3
3
|
export type CollectOptions = Pick<CoreConfig, 'plugins' | 'categories'> & Partial<GlobalOptions>;
|
|
4
4
|
/**
|
|
5
5
|
* Run audits, collect plugin output and aggregate it into a JSON object
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { createRequire } from 'node:module';
|
|
2
|
+
import { calcDuration, getLatestCommit } from '@code-pushup/utils';
|
|
3
|
+
import { executePlugins } from './execute-plugin.js';
|
|
4
|
+
/**
|
|
5
|
+
* Run audits, collect plugin output and aggregate it into a JSON object
|
|
6
|
+
* @param options
|
|
7
|
+
*/
|
|
8
|
+
export async function collect(options) {
|
|
9
|
+
const { plugins, categories } = options;
|
|
10
|
+
const date = new Date().toISOString();
|
|
11
|
+
const start = performance.now();
|
|
12
|
+
const commit = await getLatestCommit();
|
|
13
|
+
const pluginOutputs = await executePlugins(plugins, options);
|
|
14
|
+
const packageJson = createRequire(import.meta.url)('../../../package.json');
|
|
15
|
+
return {
|
|
16
|
+
commit,
|
|
17
|
+
packageName: packageJson.name,
|
|
18
|
+
version: packageJson.version,
|
|
19
|
+
date,
|
|
20
|
+
duration: calcDuration(start),
|
|
21
|
+
categories,
|
|
22
|
+
plugins: pluginOutputs,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=collect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"collect.js","sourceRoot":"","sources":["../../../../../../packages/core/src/lib/implementation/collect.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAEnE,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAKrD;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,OAAuB;IACnD,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC;IACxC,MAAM,IAAI,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACtC,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;IAChC,MAAM,MAAM,GAAG,MAAM,eAAe,EAAE,CAAC;IACvC,MAAM,aAAa,GAAG,MAAM,cAAc,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAC7D,MAAM,WAAW,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAChD,uBAAuB,CACkB,CAAC;IAC5C,OAAO;QACL,MAAM;QACN,WAAW,EAAE,WAAW,CAAC,IAAI;QAC7B,OAAO,EAAE,WAAW,CAAC,OAAO;QAC5B,IAAI;QACJ,QAAQ,EAAE,YAAY,CAAC,KAAK,CAAC;QAC7B,UAAU;QACV,OAAO,EAAE,aAAa;KACvB,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { comparePairs, listAuditsFromAllPlugins, listGroupsFromAllPlugins, matchArrayItemsByKey, } from '@code-pushup/utils';
|
|
2
|
+
export function compareCategories(reports) {
|
|
3
|
+
const { pairs, added, removed } = matchArrayItemsByKey({
|
|
4
|
+
before: reports.before.categories ?? [],
|
|
5
|
+
after: reports.after.categories ?? [],
|
|
6
|
+
key: 'slug',
|
|
7
|
+
});
|
|
8
|
+
const { changed, unchanged } = comparePairs(pairs, ({ before, after }) => before.score === after.score);
|
|
9
|
+
return {
|
|
10
|
+
changed: changed.map(categoryPairToDiff),
|
|
11
|
+
unchanged: unchanged.map(categoryToResult),
|
|
12
|
+
added: added.map(categoryToResult),
|
|
13
|
+
removed: removed.map(categoryToResult),
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
export function compareGroups(reports) {
|
|
17
|
+
const { pairs, added, removed } = matchArrayItemsByKey({
|
|
18
|
+
before: listGroupsFromAllPlugins(reports.before),
|
|
19
|
+
after: listGroupsFromAllPlugins(reports.after),
|
|
20
|
+
key: ({ plugin, group }) => `${plugin.slug}/${group.slug}`,
|
|
21
|
+
});
|
|
22
|
+
const { changed, unchanged } = comparePairs(pairs, ({ before, after }) => before.group.score === after.group.score);
|
|
23
|
+
return {
|
|
24
|
+
changed: changed.map(pluginGroupPairToDiff),
|
|
25
|
+
unchanged: unchanged.map(pluginGroupToResult),
|
|
26
|
+
added: added.map(pluginGroupToResult),
|
|
27
|
+
removed: removed.map(pluginGroupToResult),
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
export function compareAudits(reports) {
|
|
31
|
+
const { pairs, added, removed } = matchArrayItemsByKey({
|
|
32
|
+
before: listAuditsFromAllPlugins(reports.before),
|
|
33
|
+
after: listAuditsFromAllPlugins(reports.after),
|
|
34
|
+
key: ({ plugin, audit }) => `${plugin.slug}/${audit.slug}`,
|
|
35
|
+
});
|
|
36
|
+
const { changed, unchanged } = comparePairs(pairs, ({ before, after }) => before.audit.value === after.audit.value &&
|
|
37
|
+
before.audit.score === after.audit.score);
|
|
38
|
+
return {
|
|
39
|
+
changed: changed.map(pluginAuditPairToDiff),
|
|
40
|
+
unchanged: unchanged.map(pluginAuditToResult),
|
|
41
|
+
added: added.map(pluginAuditToResult),
|
|
42
|
+
removed: removed.map(pluginAuditToResult),
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
function categoryToResult(category) {
|
|
46
|
+
return {
|
|
47
|
+
...selectMeta(category),
|
|
48
|
+
score: category.score,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
function categoryPairToDiff({ before, after, }) {
|
|
52
|
+
return {
|
|
53
|
+
...selectMeta(after),
|
|
54
|
+
scores: {
|
|
55
|
+
before: before.score,
|
|
56
|
+
after: after.score,
|
|
57
|
+
diff: after.score - before.score,
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
function pluginGroupToResult({ group, plugin }) {
|
|
62
|
+
return {
|
|
63
|
+
...selectMeta(group),
|
|
64
|
+
plugin: selectMeta(plugin),
|
|
65
|
+
score: group.score,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
function pluginGroupPairToDiff({ before, after, }) {
|
|
69
|
+
return {
|
|
70
|
+
...selectMeta(after.group),
|
|
71
|
+
plugin: selectMeta(after.plugin),
|
|
72
|
+
scores: {
|
|
73
|
+
before: before.group.score,
|
|
74
|
+
after: after.group.score,
|
|
75
|
+
diff: after.group.score - before.group.score,
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
function pluginAuditToResult({ audit, plugin }) {
|
|
80
|
+
return {
|
|
81
|
+
...selectMeta(audit),
|
|
82
|
+
plugin: selectMeta(plugin),
|
|
83
|
+
score: audit.score,
|
|
84
|
+
value: audit.value,
|
|
85
|
+
displayValue: audit.displayValue,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
function pluginAuditPairToDiff({ before, after, }) {
|
|
89
|
+
return {
|
|
90
|
+
...selectMeta(after.audit),
|
|
91
|
+
plugin: selectMeta(after.plugin),
|
|
92
|
+
scores: {
|
|
93
|
+
before: before.audit.score,
|
|
94
|
+
after: after.audit.score,
|
|
95
|
+
diff: after.audit.score - before.audit.score,
|
|
96
|
+
},
|
|
97
|
+
values: {
|
|
98
|
+
before: before.audit.value,
|
|
99
|
+
after: after.audit.value,
|
|
100
|
+
diff: after.audit.value - before.audit.value,
|
|
101
|
+
},
|
|
102
|
+
displayValues: {
|
|
103
|
+
before: before.audit.displayValue,
|
|
104
|
+
after: after.audit.displayValue,
|
|
105
|
+
},
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
function selectMeta(meta) {
|
|
109
|
+
return {
|
|
110
|
+
slug: meta.slug,
|
|
111
|
+
title: meta.title,
|
|
112
|
+
...(meta.docsUrl && {
|
|
113
|
+
docsUrl: meta.docsUrl,
|
|
114
|
+
}),
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=compare-scorables.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compare-scorables.js","sourceRoot":"","sources":["../../../../../../packages/core/src/lib/implementation/compare-scorables.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { bold } from 'ansis';
|
|
2
|
+
import { auditOutputsSchema, } from '@code-pushup/models';
|
|
3
|
+
import { getProgressBar, groupByStatus, logMultipleResults, pluralizeToken, } from '@code-pushup/utils';
|
|
4
|
+
import { normalizeAuditOutputs } from '../normalize.js';
|
|
5
|
+
import { executeRunnerConfig, executeRunnerFunction } from './runner.js';
|
|
6
|
+
/**
|
|
7
|
+
* Error thrown when plugin output is invalid.
|
|
8
|
+
*/
|
|
9
|
+
export class PluginOutputMissingAuditError extends Error {
|
|
10
|
+
constructor(auditSlug) {
|
|
11
|
+
super(`Audit metadata not present in plugin config. Missing slug: ${bold(auditSlug)}`);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Execute a plugin.
|
|
16
|
+
*
|
|
17
|
+
* @public
|
|
18
|
+
* @param pluginConfig - {@link ProcessConfig} object with runner and meta
|
|
19
|
+
* @param onProgress - progress handler {@link OnProgress}
|
|
20
|
+
* @returns {Promise<AuditOutput[]>} - audit outputs from plugin runner
|
|
21
|
+
* @throws {PluginOutputMissingAuditError} - if plugin runner output is invalid
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* // plugin execution
|
|
25
|
+
* const pluginCfg = pluginConfigSchema.parse({...});
|
|
26
|
+
* const output = await executePlugin(pluginCfg);
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* // error handling
|
|
30
|
+
* try {
|
|
31
|
+
* await executePlugin(pluginCfg);
|
|
32
|
+
* } catch (e) {
|
|
33
|
+
* console.error(e.message);
|
|
34
|
+
* }
|
|
35
|
+
*/
|
|
36
|
+
export async function executePlugin(pluginConfig, onProgress) {
|
|
37
|
+
const { runner, audits: pluginConfigAudits, description, docsUrl, groups, ...pluginMeta } = pluginConfig;
|
|
38
|
+
// execute plugin runner
|
|
39
|
+
const runnerResult = typeof runner === 'object'
|
|
40
|
+
? await executeRunnerConfig(runner, onProgress)
|
|
41
|
+
: await executeRunnerFunction(runner, onProgress);
|
|
42
|
+
const { audits: unvalidatedAuditOutputs, ...executionMeta } = runnerResult;
|
|
43
|
+
// validate auditOutputs
|
|
44
|
+
const result = auditOutputsSchema.safeParse(unvalidatedAuditOutputs);
|
|
45
|
+
if (!result.success) {
|
|
46
|
+
throw new Error(`Audit output is invalid: ${result.error.message}`);
|
|
47
|
+
}
|
|
48
|
+
const auditOutputs = result.data;
|
|
49
|
+
auditOutputsCorrelateWithPluginOutput(auditOutputs, pluginConfigAudits);
|
|
50
|
+
const normalizedAuditOutputs = await normalizeAuditOutputs(auditOutputs);
|
|
51
|
+
// enrich `AuditOutputs` to `AuditReport`
|
|
52
|
+
const auditReports = normalizedAuditOutputs.map((auditOutput) => ({
|
|
53
|
+
...auditOutput,
|
|
54
|
+
...pluginConfigAudits.find(audit => audit.slug === auditOutput.slug),
|
|
55
|
+
}));
|
|
56
|
+
// create plugin report
|
|
57
|
+
return {
|
|
58
|
+
...pluginMeta,
|
|
59
|
+
...executionMeta,
|
|
60
|
+
audits: auditReports,
|
|
61
|
+
...(description && { description }),
|
|
62
|
+
...(docsUrl && { docsUrl }),
|
|
63
|
+
...(groups && { groups }),
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
const wrapProgress = async (pluginCfg, steps, progressBar) => {
|
|
67
|
+
progressBar?.updateTitle(`Executing ${bold(pluginCfg.title)}`);
|
|
68
|
+
try {
|
|
69
|
+
const pluginReport = await executePlugin(pluginCfg);
|
|
70
|
+
progressBar?.incrementInSteps(steps);
|
|
71
|
+
return pluginReport;
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
progressBar?.incrementInSteps(steps);
|
|
75
|
+
throw new Error(error instanceof Error
|
|
76
|
+
? `- Plugin ${bold(pluginCfg.title)} (${bold(pluginCfg.slug)}) produced the following error:\n - ${error.message}`
|
|
77
|
+
: String(error));
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
/**
|
|
81
|
+
* Execute multiple plugins and aggregates their output.
|
|
82
|
+
* @public
|
|
83
|
+
* @param plugins array of {@link PluginConfig} objects
|
|
84
|
+
* @param {Object} [options] execution options
|
|
85
|
+
* @param {boolean} options.progress show progress bar
|
|
86
|
+
* @returns {Promise<PluginReport[]>} plugin report
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* // plugin execution
|
|
90
|
+
* const plugins = [pluginConfigSchema.parse({...})];
|
|
91
|
+
*
|
|
92
|
+
* @example
|
|
93
|
+
* // error handling
|
|
94
|
+
* try {
|
|
95
|
+
* await executePlugins(plugins);
|
|
96
|
+
* } catch (e) {
|
|
97
|
+
* console.error(e.message); // Plugin output is invalid
|
|
98
|
+
* }
|
|
99
|
+
*
|
|
100
|
+
*/
|
|
101
|
+
export async function executePlugins(plugins, options) {
|
|
102
|
+
const { progress = false } = options ?? {};
|
|
103
|
+
const progressBar = progress ? getProgressBar('Run plugins') : null;
|
|
104
|
+
const pluginsResult = plugins.map(pluginCfg => wrapProgress(pluginCfg, plugins.length, progressBar));
|
|
105
|
+
const errorsTransform = ({ reason }) => String(reason);
|
|
106
|
+
const results = await Promise.allSettled(pluginsResult);
|
|
107
|
+
progressBar?.endProgress('Done running plugins');
|
|
108
|
+
logMultipleResults(results, 'Plugins', undefined, errorsTransform);
|
|
109
|
+
const { fulfilled, rejected } = groupByStatus(results);
|
|
110
|
+
if (rejected.length > 0) {
|
|
111
|
+
const errorMessages = rejected
|
|
112
|
+
.map(({ reason }) => String(reason))
|
|
113
|
+
.join('\n');
|
|
114
|
+
throw new Error(`Executing ${pluralizeToken('plugin', rejected.length)} failed.\n\n${errorMessages}\n\n`);
|
|
115
|
+
}
|
|
116
|
+
return fulfilled.map(result => result.value);
|
|
117
|
+
}
|
|
118
|
+
function auditOutputsCorrelateWithPluginOutput(auditOutputs, pluginConfigAudits) {
|
|
119
|
+
auditOutputs.forEach(auditOutput => {
|
|
120
|
+
const auditMetadata = pluginConfigAudits.find(audit => audit.slug === auditOutput.slug);
|
|
121
|
+
if (!auditMetadata) {
|
|
122
|
+
throw new PluginOutputMissingAuditError(auditOutput.slug);
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
//# sourceMappingURL=execute-plugin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"execute-plugin.js","sourceRoot":"","sources":["../../../../../../packages/core/src/lib/implementation/execute-plugin.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { mkdir, stat, writeFile } from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { directoryExists, generateMdReport, logMultipleFileResults, ui, } from '@code-pushup/utils';
|
|
4
|
+
export class PersistDirError extends Error {
|
|
5
|
+
constructor(outputDir) {
|
|
6
|
+
super(`outPath: ${outputDir} is no directory.`);
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
export class PersistError extends Error {
|
|
10
|
+
constructor(reportPath) {
|
|
11
|
+
super(`fileName: ${reportPath} could not be saved.`);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
export async function persistReport(report, sortedScoredReport, options) {
|
|
15
|
+
const { outputDir, filename, format } = options;
|
|
16
|
+
// collect physical format outputs
|
|
17
|
+
const results = format.map(reportType => {
|
|
18
|
+
switch (reportType) {
|
|
19
|
+
case 'json':
|
|
20
|
+
return {
|
|
21
|
+
format: 'json',
|
|
22
|
+
content: JSON.stringify(report, null, 2),
|
|
23
|
+
};
|
|
24
|
+
case 'md':
|
|
25
|
+
return {
|
|
26
|
+
format: 'md',
|
|
27
|
+
content: generateMdReport(sortedScoredReport, { outputDir }),
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
if (!(await directoryExists(outputDir))) {
|
|
32
|
+
try {
|
|
33
|
+
await mkdir(outputDir, { recursive: true });
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
ui().logger.warning(error.toString());
|
|
37
|
+
throw new PersistDirError(outputDir);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
// write relevant format outputs to file system
|
|
41
|
+
return Promise.allSettled(results.map(result => persistResult(path.join(outputDir, `${filename}.${result.format}`), result.content)));
|
|
42
|
+
}
|
|
43
|
+
async function persistResult(reportPath, content) {
|
|
44
|
+
return (writeFile(reportPath, content)
|
|
45
|
+
// return reportPath instead of void
|
|
46
|
+
.then(() => stat(reportPath))
|
|
47
|
+
.then(stats => [reportPath, stats.size])
|
|
48
|
+
.catch(error => {
|
|
49
|
+
ui().logger.warning(error.toString());
|
|
50
|
+
throw new PersistError(reportPath);
|
|
51
|
+
}));
|
|
52
|
+
}
|
|
53
|
+
export function logPersistedResults(persistResults) {
|
|
54
|
+
logMultipleFileResults(persistResults, 'Generated reports');
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=persist.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"persist.js","sourceRoot":"","sources":["../../../../../../packages/core/src/lib/implementation/persist.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC1D,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EAGL,eAAe,EACf,gBAAgB,EAChB,sBAAsB,EACtB,EAAE,GACH,MAAM,oBAAoB,CAAC;AAE5B,MAAM,OAAO,eAAgB,SAAQ,KAAK;IACxC,YAAY,SAAiB;QAC3B,KAAK,CAAC,YAAY,SAAS,mBAAmB,CAAC,CAAC;IAClD,CAAC;CACF;AAED,MAAM,OAAO,YAAa,SAAQ,KAAK;IACrC,YAAY,UAAkB;QAC5B,KAAK,CAAC,aAAa,UAAU,sBAAsB,CAAC,CAAC;IACvD,CAAC;CACF;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,MAAc,EACd,kBAAgC,EAChC,OAAgC;IAEhC,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;IAEhD,kCAAkC;IAClC,MAAM,OAAO,GAAG,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE;QACtC,QAAQ,UAAU,EAAE,CAAC;YACnB,KAAK,MAAM;gBACT,OAAO;oBACL,MAAM,EAAE,MAAM;oBACd,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;iBACzC,CAAC;YACJ,KAAK,IAAI;gBACP,OAAO;oBACL,MAAM,EAAE,IAAI;oBACZ,OAAO,EAAE,gBAAgB,CAAC,kBAAkB,EAAE,EAAE,SAAS,EAAE,CAAC;iBAC7D,CAAC;QACN,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,CAAC,MAAM,eAAe,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC;QACxC,IAAI,CAAC;YACH,MAAM,KAAK,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC9C,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,EAAE,EAAE,CAAC,MAAM,CAAC,OAAO,CAAE,KAAe,CAAC,QAAQ,EAAE,CAAC,CAAC;YACjD,MAAM,IAAI,eAAe,CAAC,SAAS,CAAC,CAAC;QACvC,CAAC;IACH,CAAC;IAED,+CAA+C;IAC/C,OAAO,OAAO,CAAC,UAAU,CACvB,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CACnB,aAAa,CACX,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,QAAQ,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC,EACpD,MAAM,CAAC,OAAO,CACf,CACF,CACF,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,aAAa,CAAC,UAAkB,EAAE,OAAe;IAC9D,OAAO,CACL,SAAS,CAAC,UAAU,EAAE,OAAO,CAAC;QAC5B,oCAAoC;SACnC,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;SAC5B,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,UAAU,EAAE,KAAK,CAAC,IAAI,CAAU,CAAC;SAChD,KAAK,CAAC,KAAK,CAAC,EAAE;QACb,EAAE,EAAE,CAAC,MAAM,CAAC,OAAO,CAAE,KAAe,CAAC,QAAQ,EAAE,CAAC,CAAC;QACjD,MAAM,IAAI,YAAY,CAAC,UAAU,CAAC,CAAC;IACrC,CAAC,CAAC,CACL,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,cAAmC;IACrE,sBAAsB,CAAC,cAAc,EAAE,mBAAmB,CAAC,CAAC;AAC9D,CAAC"}
|