From 920768f0381d5a2ddb8c8c229ab95642dd343686 Mon Sep 17 00:00:00 2001 From: Adrien Boutigny Date: Wed, 22 May 2024 16:48:59 +0200 Subject: [PATCH 1/4] generate and copy api types on install --- confiture-rest-api/.gitignore | 5 ++- confiture-rest-api/package.json | 4 ++- .../src/generate-api-typings.ts | 24 +++++++++++++ confiture-rest-api/tsconfig.build.json | 9 ++++- confiture-web-app/.gitignore | 1 + package.json | 4 +++ yarn.lock | 35 +++++++++++++++++-- 7 files changed, 76 insertions(+), 6 deletions(-) create mode 100644 confiture-rest-api/src/generate-api-typings.ts diff --git a/confiture-rest-api/.gitignore b/confiture-rest-api/.gitignore index 2bca70298..ee7b77e8a 100644 --- a/confiture-rest-api/.gitignore +++ b/confiture-rest-api/.gitignore @@ -36,4 +36,7 @@ lerna-debug.log* .env -src/generated \ No newline at end of file +src/generated + +# Generated API typings +confiture-api.ts \ No newline at end of file diff --git a/confiture-rest-api/package.json b/confiture-rest-api/package.json index 5f51bdea2..bffe079ed 100644 --- a/confiture-rest-api/package.json +++ b/confiture-rest-api/package.json @@ -12,7 +12,8 @@ "lint": "eslint \"src/**/*.ts\" --fix", "migrate:dev": "prisma migrate dev", "migrate:prod": "prisma migrate deploy", - "postinstall": "prisma generate" + "postinstall": "prisma generate && yarn generate-api-types", + "generate-api-types": "nest start --entryFile generate-api-typings.js" }, "dependencies": { "@aws-sdk/client-s3": "^3.218.0", @@ -59,6 +60,7 @@ "eslint": "^8.55.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-prettier": "^5.0.1", + "openapi-typescript": "^6.7.6", "prettier": "^3.1.1", "source-map-support": "^0.5.20", "ts-loader": "^9.2.3", diff --git a/confiture-rest-api/src/generate-api-typings.ts b/confiture-rest-api/src/generate-api-typings.ts new file mode 100644 index 000000000..e34bc4d4b --- /dev/null +++ b/confiture-rest-api/src/generate-api-typings.ts @@ -0,0 +1,24 @@ +import { NestFactory } from "@nestjs/core"; +import { DocumentBuilder, SwaggerModule } from "@nestjs/swagger"; +import { writeFile } from "fs/promises"; +import openapiTS, { OpenAPI3 } from "openapi-typescript"; +import { resolve } from "path"; + +import { AppModule } from "./app.module"; + +async function main() { + const app = await NestFactory.create(AppModule); + + const config = new DocumentBuilder().setTitle("Confiture API").build(); + const document = SwaggerModule.createDocument(app, config); + + const ast = await openapiTS(document as OpenAPI3); + const fileContent = "/* eslint-disable */\n" + ast; + const resolvedPath = resolve(process.cwd(), "./confiture-api.ts"); + await writeFile(resolvedPath, fileContent, { + encoding: "utf-8" + }); + console.log("✅ Typings saved to", resolvedPath); +} + +main(); diff --git a/confiture-rest-api/tsconfig.build.json b/confiture-rest-api/tsconfig.build.json index 052134cd3..08260a7f3 100644 --- a/confiture-rest-api/tsconfig.build.json +++ b/confiture-rest-api/tsconfig.build.json @@ -1,4 +1,11 @@ { "extends": "./tsconfig.json", - "exclude": ["node_modules", "test", "dist", "**/*spec.ts", "scripts"] + "exclude": [ + "node_modules", + "test", + "dist", + "**/*spec.ts", + "scripts", + "date-poll-api.ts" + ] } diff --git a/confiture-web-app/.gitignore b/confiture-web-app/.gitignore index 16d6e70d1..44065d600 100644 --- a/confiture-web-app/.gitignore +++ b/confiture-web-app/.gitignore @@ -30,3 +30,4 @@ coverage accessibilite.numerique.gouv.fr src/methodologies.json src/criteres.json +src/types/confiture-api.ts \ No newline at end of file diff --git a/package.json b/package.json index df64a71ec..3bd825b92 100644 --- a/package.json +++ b/package.json @@ -8,5 +8,9 @@ "cypress": "^13.6.1", "husky": "^8.0.3", "lint-staged": "^15.2.0" + }, + "scripts": { + "copytypes": "yarn workspace confiture-rest-api run generate-api-types && cp ./confiture-rest-api/confiture-api.ts ./confiture-web-app/src/types", + "postinstall": "yarn copytypes" } } diff --git a/yarn.lock b/yarn.lock index d6a8949e1..3209cb9af 100644 --- a/yarn.lock +++ b/yarn.lock @@ -857,6 +857,11 @@ resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.55.0.tgz#b721d52060f369aa259cf97392403cb9ce892ec6" integrity sha512-qQfo2mxH5yVom1kacMtZZJFVdW+E70mqHMJvVg6WTLo+VBuQJ4TojZlfWBjK0ve5BdEeNAVxOsl/nvNMpJOaJA== +"@fastify/busboy@^2.0.0": + version "2.1.1" + resolved "https://registry.yarnpkg.com/@fastify/busboy/-/busboy-2.1.1.tgz#b9da6a878a371829a0502c9b6c1c143ef6663f4d" + integrity sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA== + "@gouvfr/dsfr@1.11.2": version "1.11.2" resolved "https://registry.yarnpkg.com/@gouvfr/dsfr/-/dsfr-1.11.2.tgz#aa815e458b266acd8e457bdad35b7e3ad5e6c2ab" @@ -2750,7 +2755,7 @@ ajv@^6.12.4, ajv@^6.12.5: json-schema-traverse "^0.4.1" uri-js "^4.2.2" -ansi-colors@4.1.3, ansi-colors@^4.1.1: +ansi-colors@4.1.3, ansi-colors@^4.1.1, ansi-colors@^4.1.3: version "4.1.3" resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.3.tgz#37611340eb2243e70cc604cad35d63270d48781b" integrity sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw== @@ -4430,7 +4435,7 @@ fast-diff@^1.1.2: resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.3.0.tgz#ece407fa550a64d638536cd727e129c61616e0f0" integrity sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw== -fast-glob@^3.2.9, fast-glob@^3.3.0: +fast-glob@^3.2.9, fast-glob@^3.3.0, fast-glob@^3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow== @@ -6549,6 +6554,18 @@ open@^9.1.0: is-inside-container "^1.0.0" is-wsl "^2.2.0" +openapi-typescript@^6.7.6: + version "6.7.6" + resolved "https://registry.yarnpkg.com/openapi-typescript/-/openapi-typescript-6.7.6.tgz#4f387199203bd7bfb94545cbc613751b52e3fa37" + integrity sha512-c/hfooPx+RBIOPM09GSxABOZhYPblDoyaGhqBkD/59vtpN21jEuWKDlM0KYTvqJVlSYjKs0tBcIdeXKChlSPtw== + dependencies: + ansi-colors "^4.1.3" + fast-glob "^3.3.2" + js-yaml "^4.1.0" + supports-color "^9.4.0" + undici "^5.28.4" + yargs-parser "^21.1.1" + optionator@^0.9.3: version "0.9.3" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.3.tgz#007397d44ed1872fdc6ed31360190f81814e2c64" @@ -7664,6 +7681,11 @@ supports-color@^8.0.0, supports-color@^8.1.1: dependencies: has-flag "^4.0.0" +supports-color@^9.4.0: + version "9.4.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-9.4.0.tgz#17bfcf686288f531db3dea3215510621ccb55954" + integrity sha512-VL+lNrEoIXww1coLPOmiEmK/0sGigko5COxI09KzHc2VJXJsQ37UaQ+8quuxjDeA7+KnLGTWRyOXSLLR2Wb4jw== + supports-hyperlinks@^2.0.0: version "2.3.0" resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz#3943544347c1ff90b15effb03fc14ae45ec10624" @@ -8049,6 +8071,13 @@ undici@5.1.1: resolved "https://registry.yarnpkg.com/undici/-/undici-5.1.1.tgz#356427b0d1f032ca4cf85537b1e1694a52090438" integrity sha512-CmK9JzLSMGx+2msOao8LhkKn3J7eKo2M50v0KZQ2XbiHcGqLS1HiIj01ceIm3jbUYlspw/FTSb6nMdSNyvVyaQ== +undici@^5.28.4: + version "5.28.4" + resolved "https://registry.yarnpkg.com/undici/-/undici-5.28.4.tgz#6b280408edb6a1a604a9b20340f45b422e373068" + integrity sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g== + dependencies: + "@fastify/busboy" "^2.0.0" + unhead@1.8.9: version "1.8.9" resolved "https://registry.yarnpkg.com/unhead/-/unhead-1.8.9.tgz#f13ecee175381d634d085e52a7945c6e7937b56d" @@ -8460,7 +8489,7 @@ yaml@^1.10.0: resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== -yargs-parser@21.1.1: +yargs-parser@21.1.1, yargs-parser@^21.1.1: version "21.1.1" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== From 82c767007243e35a7a43903071c831137c2d44a2 Mon Sep 17 00:00:00 2001 From: Adrien Boutigny Date: Fri, 24 May 2024 14:43:52 +0200 Subject: [PATCH 2/4] delete dist folder before generating types --- confiture-rest-api/package.json | 2 +- confiture-rest-api/tsconfig.build.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/confiture-rest-api/package.json b/confiture-rest-api/package.json index bffe079ed..a14081141 100644 --- a/confiture-rest-api/package.json +++ b/confiture-rest-api/package.json @@ -13,7 +13,7 @@ "migrate:dev": "prisma migrate dev", "migrate:prod": "prisma migrate deploy", "postinstall": "prisma generate && yarn generate-api-types", - "generate-api-types": "nest start --entryFile generate-api-typings.js" + "generate-api-types": "rimraf dist && nest start --entryFile generate-api-typings.js" }, "dependencies": { "@aws-sdk/client-s3": "^3.218.0", diff --git a/confiture-rest-api/tsconfig.build.json b/confiture-rest-api/tsconfig.build.json index 08260a7f3..82089442f 100644 --- a/confiture-rest-api/tsconfig.build.json +++ b/confiture-rest-api/tsconfig.build.json @@ -6,6 +6,6 @@ "dist", "**/*spec.ts", "scripts", - "date-poll-api.ts" + "confiture-api.ts" ] } From 90b0494898d78f17d44852c97040890bc3d0991a Mon Sep 17 00:00:00 2001 From: Adrien Boutigny Date: Fri, 31 May 2024 10:56:25 +0200 Subject: [PATCH 3/4] disable config validation when generating types --- confiture-rest-api/package.json | 2 +- confiture-rest-api/src/app.module.ts | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/confiture-rest-api/package.json b/confiture-rest-api/package.json index a14081141..421b4fe27 100644 --- a/confiture-rest-api/package.json +++ b/confiture-rest-api/package.json @@ -13,7 +13,7 @@ "migrate:dev": "prisma migrate dev", "migrate:prod": "prisma migrate deploy", "postinstall": "prisma generate && yarn generate-api-types", - "generate-api-types": "rimraf dist && nest start --entryFile generate-api-typings.js" + "generate-api-types": "rimraf dist && GENERATE_TYPES=1 nest start --entryFile generate-api-typings.js" }, "dependencies": { "@aws-sdk/client-s3": "^3.218.0", diff --git a/confiture-rest-api/src/app.module.ts b/confiture-rest-api/src/app.module.ts index 149f65d6a..937c4ff0f 100644 --- a/confiture-rest-api/src/app.module.ts +++ b/confiture-rest-api/src/app.module.ts @@ -13,7 +13,9 @@ import { UserMiddleware } from "./auth/user.middleware"; imports: [ ConfigModule.forRoot({ isGlobal: true, - validationSchema: configValidationSchema + validationSchema: !process.env.GENERATE_TYPES + ? configValidationSchema + : undefined }), FeedbackModule, AuditsModule, From 5801e83e6f397e6d910c1558592b7eb782d0477c Mon Sep 17 00:00:00 2001 From: Adrien Boutigny Date: Fri, 31 May 2024 16:19:59 +0200 Subject: [PATCH 4/4] use generated types in report --- .../src/audits/dto/audit-report.dto.ts | 36 +++--- .../src/components/report/ReportErrors.vue | 6 +- confiture-web-app/src/types/report.ts | 113 +----------------- confiture-web-app/src/types/types.ts | 2 + confiture-web-app/src/utils.ts | 9 +- 5 files changed, 32 insertions(+), 134 deletions(-) diff --git a/confiture-rest-api/src/audits/dto/audit-report.dto.ts b/confiture-rest-api/src/audits/dto/audit-report.dto.ts index f7baacf2f..6d3265a93 100644 --- a/confiture-rest-api/src/audits/dto/audit-report.dto.ts +++ b/confiture-rest-api/src/audits/dto/audit-report.dto.ts @@ -36,24 +36,7 @@ export class AuditReportDto { */ accessibilityRate: number; - /** - * @example { - * total: 106; - * compliant: 30; - * notCompliant: 46; - * blocking: 12; - * applicable: 76; - * notApplicable: 30; - * } - */ - criteriaCount: { - total: number; - compliant: number; - notCompliant: number; - blocking: number; - applicable: number; - notApplicable: number; - }; + criteriaCount: CriteriaCount; /** Global distribution of criteria by result */ resultDistribution: ResultDistribution; @@ -67,6 +50,21 @@ export class AuditReportDto { results: ReportCriterionResult[]; } +class CriteriaCount { + /** @example 106 */ + total: number; + /** @example 30 */ + compliant: number; + /** @example 46 */ + notCompliant: number; + /** @example 12 */ + blocking: number; + /** @example 76 */ + applicable: number; + /** @example 30 */ + notApplicable: number; +} + class RawAndPercentage { /** * @example 47 @@ -204,6 +202,8 @@ class ReportCriterionResult { recommandation: string | null; notApplicableComment: string | null; + + quickWin: boolean; } class ExampleImage { diff --git a/confiture-web-app/src/components/report/ReportErrors.vue b/confiture-web-app/src/components/report/ReportErrors.vue index fa0d74619..0057e1921 100644 --- a/confiture-web-app/src/components/report/ReportErrors.vue +++ b/confiture-web-app/src/components/report/ReportErrors.vue @@ -124,9 +124,9 @@ const defaultUserImpactFillters = [ null ]; -const userImpactFilters = ref>( - defaultUserImpactFillters -); +const userImpactFilters = ref< + Array +>(defaultUserImpactFillters); const disabledResetFilters = computed( () => diff --git a/confiture-web-app/src/types/report.ts b/confiture-web-app/src/types/report.ts index 86e2494d7..61aa2003d 100644 --- a/confiture-web-app/src/types/report.ts +++ b/confiture-web-app/src/types/report.ts @@ -1,111 +1,4 @@ -import { AuditType, CriteriumResult } from "../types"; +import { paths } from "./confiture-api"; -export interface AuditReport { - consultUniqueId: string; - - contactEmail?: string; - contactFormUrl?: string; - - procedureInitiator?: string; - procedureName: string; - procedureUrl?: string; - - creationDate?: string; - publishDate?: string; - updateDate?: string; - - notCompliantContent?: string; - derogatedContent?: string; - notInScopeContent?: string; - notes?: string; - - auditType: AuditType; - - context: AuditReportContext; - - accessibilityRate: number; - - criteriaCount: { - total: number; - compliant: number; - notCompliant: number; - blocking: number; - applicable: number; - notApplicable: number; - }; - - /** Global distribution of criteria by result */ - resultDistribution: ResultDistribution; - - /** Distribution of criteria by page */ - pageDistributions: PageResultDistribution[]; - - /** Distribution of criteria by topic */ - topicDistributions: TopicResultDistribution[]; - - results: Array< - Omit & { - exampleImages: { - url: string; - filename: string; - }[]; - } - >; -} - -interface ResultDistribution { - compliant: { - raw: number; - percentage: number; - }; - notCompliant: { - raw: number; - percentage: number; - }; - notApplicable: { - raw: number; - percentage: number; - }; -} - -interface PageResultDistribution extends ResultDistribution { - name: string; -} - -interface TopicResultDistribution extends ResultDistribution { - name: string; -} - -interface AuditReportContext { - referencial: string; - - auditorName: string; - auditorEmail: string | null; - auditorOrganisation: string; - - technologies: string[]; - - samples: PageSample[]; - - tools: string[]; - - desktopEnvironments: Environment[]; - mobileEnvironments: Environment[]; -} - -interface PageSample { - // number: number; - id: number; - order: number; - name: string; - url: string; -} - -interface Environment { - operatingSystem: string; - operatingSystemVersion?: string; - assistiveTechnology: string; - assistiveTechnologyVersion?: string; - browser: string; - browserVersion?: string; -} +export type AuditReport = + paths["/reports/{consultUniqueId}"]["get"]["responses"]["200"]["content"]["application/json"]; diff --git a/confiture-web-app/src/types/types.ts b/confiture-web-app/src/types/types.ts index 41d84b97a..b7ba49ce6 100644 --- a/confiture-web-app/src/types/types.ts +++ b/confiture-web-app/src/types/types.ts @@ -28,6 +28,8 @@ export enum AuditType { FULL = "FULL" } +export type AuditTypeString = `${AuditType}`; + export enum AuditStatus { IN_PROGRESS = "IN_PROGRESS", COMPLETED = "COMPLETED", diff --git a/confiture-web-app/src/utils.ts b/confiture-web-app/src/utils.ts index 8ad9f0664..18bd7aa33 100644 --- a/confiture-web-app/src/utils.ts +++ b/confiture-web-app/src/utils.ts @@ -8,6 +8,7 @@ import { AuditReport, AuditStatus, AuditType, + AuditTypeString, CriterionResultUserImpact, CriteriumResultStatus } from "./types"; @@ -44,7 +45,7 @@ const FORMATTED_USER_IMPACT = { * Format a criterion result user impact type string into French. */ export function formatUserImpact( - userImpact: CriterionResultUserImpact + userImpact: CriterionResultUserImpact | `${CriterionResultUserImpact}` ): string { return FORMATTED_USER_IMPACT[userImpact]; } @@ -59,7 +60,9 @@ const FORMATTED_STATUS = { /** * Format a criterion result status type string into French. */ -export function formatStatus(status: CriteriumResultStatus): string { +export function formatStatus( + status: CriteriumResultStatus | `${CriteriumResultStatus}` +): string { return FORMATTED_STATUS[status]; } @@ -72,7 +75,7 @@ const CRITERIA_COUNT = { /** * Return the number of criteria for a given audit type. */ -export function getCriteriaCount(auditType: AuditType): number { +export function getCriteriaCount(auditType: AuditTypeString): number { return CRITERIA_COUNT[auditType]; }