diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100755 index 000000000..765baae31 --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1,4 @@ +#!/usr/bin/env sh +. "$(dirname -- "$0")/_/husky.sh" + +yarn pre-commit diff --git a/package.json b/package.json index 53de1b182..bdadeb4fa 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ ], "type": "module", "scripts": { + "pre-commit": "yarn workspaces foreach -pi run pre-commit", "scalingo-postbuild": "echo 'yarn workspaces focus api && yarn workspace api run build' ; yarn workspaces focus api && yarn workspace api run build", "lint:eslintrc": "npx eslint-config-prettier .eslintrc.cjs", "lint:eslint": "NODE_OPTIONS='--max-old-space-size=4096' eslint .", @@ -24,7 +25,7 @@ "lint:prettier:fix": "yarn lint:prettier --write", "lint:fix": "yarn lint:eslint:fix ; yarn lint:prettier:fix", "lint": "yarn lint:eslintrc && yarn lint:eslint && yarn lint:prettier", - "postinstall": "yarn workspaces foreach -piv --exclude site run prepack", + "postinstall": "husky install && yarn workspaces foreach -piv --exclude site run prepack", "test": "yarn workspaces foreach run test", "test:type": "yarn workspaces foreach -pi run tsc --skipLibCheck --noEmit", "clean": "yarn workspaces foreach run clean && rimraf node_modules", @@ -50,6 +51,7 @@ "eslint-plugin-promise": "^6.0.0", "eslint-plugin-react": "^7.30.0", "eslint-plugin-react-hooks": "^4.5.0", + "husky": "^8.0.0", "prettier": "^2.6.2", "rimraf": "^3.0.2" } diff --git a/site/.gitignore b/site/.gitignore index 493737815..6c4ac34b7 100644 --- a/site/.gitignore +++ b/site/.gitignore @@ -4,3 +4,4 @@ source/data/* cypress/videos cypress/screenshots cypress/downloads +.deps.json diff --git a/site/package.json b/site/package.json index 3a6279a6a..da24c6231 100644 --- a/site/package.json +++ b/site/package.json @@ -10,7 +10,7 @@ }, "private": true, "engines": { - "node": ">=12.16.1" + "node": "^16" }, "type": "module", "browserslist": [ @@ -18,6 +18,8 @@ "not ie < 11" ], "scripts": { + "pre-commit": "ts-node-esm scripts/preCommit/index.ts", + "build:yaml-to-dts": "ts-node-esm scripts/build-yaml-to-dts.ts", "postinstall": "node scripts/prepare.js", "start": "vite dev", "build": "NODE_OPTIONS='--max-old-space-size=6144'; vite build && yarn build:iframe-script", @@ -110,6 +112,7 @@ "@redux-devtools/extension": "^3.2.2", "@rollup/plugin-replace": "^4.0.0", "@rollup/plugin-yaml": "^3.1.0", + "@rushstack/package-deps-hash": "^3.2.20", "@storybook/addon-actions": "^6.5.0-alpha.49", "@storybook/addon-essentials": "^6.5.0-alpha.49", "@storybook/addon-interactions": "^6.5.0-alpha.49", @@ -139,8 +142,8 @@ "rollup-plugin-toml": "^1.0.0", "serve-static": "^1.14.2", "ts-morph": "^13.0.3", - "ts-node": "^10.5.0", - "typescript": "^4.3.2", + "ts-node": "^10.8.0", + "typescript": "^4.7.2", "vite": "^2.9.9", "vite-plugin-shim-react-pdf": "^1.0.5", "vitest": "^0.9.4", diff --git a/site/scripts/build-yaml-to-dts.ts b/site/scripts/build-yaml-to-dts.ts new file mode 100644 index 000000000..8db53dfb2 --- /dev/null +++ b/site/scripts/build-yaml-to-dts.ts @@ -0,0 +1,35 @@ +import { readFileSync } from 'fs' +import { join } from 'path' +import { Project } from 'ts-morph' +import yaml from 'yaml' + +const buildYamlToDts = [ + './source/pages/Simulateurs/EconomieCollaborative/activités.yaml', + './source/pages/Simulateurs/EconomieCollaborative/activités.en.yaml', +] + +const transform = (data: Record, filePath: string) => { + const relativePath = filePath.replace(join(import.meta.url, '/'), '') + console.log('Transform:', relativePath) + const source = JSON.stringify(data) + const defaultExportedJson = `const _default = ${source} as const\nexport default _default` + const project = new Project({ + compilerOptions: { + declaration: true, + emitDeclarationOnly: true, + }, + }) + project.createSourceFile(filePath + '.ts', defaultExportedJson, { + overwrite: true, + }) + project + .emit() + .then(() => console.log(' Done! :', relativePath + '.d.ts')) + .catch((err) => console.error(err)) +} + +buildYamlToDts.forEach((path) => { + const file = readFileSync(path, { encoding: 'utf8' }) + const data = yaml.parse(file, { merge: true }) as Record + transform(data, path) +}) diff --git a/site/scripts/preCommit/execOnFileChange.ts b/site/scripts/preCommit/execOnFileChange.ts new file mode 100644 index 000000000..cabff488f --- /dev/null +++ b/site/scripts/preCommit/execOnFileChange.ts @@ -0,0 +1,99 @@ +import { getPackageDeps } from '@rushstack/package-deps-hash' +import { exec as originalExec } from 'child_process' +import { existsSync, lstatSync, readFileSync, writeFileSync } from 'fs' +import { relative, resolve } from 'path' +import { promisify } from 'util' + +const exec = promisify(originalExec) + +type DirPath = string +type FilePath = string + +interface Option { + paths: (DirPath | FilePath)[] + run: string +} + +interface Config { + basePath: string + depsPath: string + options: Option[] +} + +type Deps = Record + +/** + * Execute a command when a file or a file in the directory changes + */ +export const execOnFileChange = async (config: Config) => { + const path = resolve(config.basePath, config.depsPath) + + const deps: Deps = Object.fromEntries(getPackageDeps(config.basePath)) + const depsEntries = Object.entries(deps) + + const existingDeps = existsSync(path) + ? (JSON.parse(readFileSync(path, { encoding: 'utf8' })) as Deps) + : {} + const existingDepsEntries = Object.entries(existingDeps) + + const promises = config.options.map(async (cfg) => { + let fileChanged: null | string = null + const index = cfg.paths + .map((val) => { + const isDir = lstatSync(resolve(config.basePath, val)).isDirectory() + const isFile = lstatSync(resolve(config.basePath, val)).isFile() + + return { + isDir, + isFile, + absolute: resolve(config.basePath, val), + relative: relative( + resolve(config.basePath), + resolve(config.basePath, val) + ), + } + }) + .findIndex(({ absolute, relative, isFile, isDir }) => { + if (isFile) { + if (deps[relative] !== existingDeps[relative]) { + fileChanged = relative + } + + return deps[relative] !== existingDeps[relative] + } else if (isDir) { + const index = depsEntries.findIndex( + ([a, b], i) => + (relative.length ? a.startsWith(relative + '/') : true) && + (existingDepsEntries?.[i]?.[0] !== a || + existingDepsEntries?.[i]?.[1] !== b) + ) + + if (index > -1) { + fileChanged = depsEntries[index][0] + } + + return index > -1 + } + throw new Error('Path is not a directory or a file: ' + absolute) + }) + + if (index > -1) { + const result = await exec(cfg.run) + + return { + path: cfg.paths[index], + fileChanged, + run: cfg.run, + result, + } + } + + return null + }) + + const res = await Promise.all(promises) + + writeFileSync(path, JSON.stringify(deps, null, 2)) + + return res +} diff --git a/site/scripts/preCommit/index.ts b/site/scripts/preCommit/index.ts new file mode 100644 index 000000000..64aa68269 --- /dev/null +++ b/site/scripts/preCommit/index.ts @@ -0,0 +1,34 @@ +import { execOnFileChange } from './execOnFileChange.js' + +console.log('Search for changed file.') +console.time('Done in') + +const results = await execOnFileChange({ + basePath: './', + depsPath: '.deps.json', + options: [ + { + paths: [ + './source/pages/Simulateurs/EconomieCollaborative/activités.yaml', + './source/pages/Simulateurs/EconomieCollaborative/activités.en.yaml', + ], + run: 'yarn build:yaml-to-dts', + }, + ], +}) + +results + .filter((x: null | T): x is T => !!x) + .forEach(({ fileChanged, run, result }) => { + console.log('Changed file detected:', fileChanged) + console.log('Execute:', run, '\n') + + if (result.stdout) { + console.log(result.stdout) + } + if (result.stderr) { + console.error(result.stderr) + } + }) + +console.timeEnd('Done in') diff --git a/site/tsconfig.json b/site/tsconfig.json index e894a4509..3c215f2e9 100644 --- a/site/tsconfig.json +++ b/site/tsconfig.json @@ -19,6 +19,9 @@ "noEmit": true, "strict": true }, + "ts-node": { + "transpileOnly": true + }, "include": [ "source", "scripts", diff --git a/site/vite.config.ts b/site/vite.config.ts index 4cdb9e913..3faaa9729 100644 --- a/site/vite.config.ts +++ b/site/vite.config.ts @@ -10,7 +10,6 @@ import toml from 'rollup-plugin-toml' import { defineConfig, Plugin } from 'vite' import shimReactPdf from 'vite-plugin-shim-react-pdf' import serveStatic from 'serve-static' -import { Project } from 'ts-morph' const buildYamlToDts = [ 'Simulateurs/EconomieCollaborative/activités.yaml', @@ -35,41 +34,7 @@ export default defineConfig(({ command }) => ({ react({ babel: { plugins: ['babel-plugin-styled-components'] }, }), - yaml({ - /** - * Build yaml to d.ts when vite build - */ - transform: (data, filePath): undefined => { - if ( - command === 'serve' || - !buildYamlToDts.some((p) => filePath.includes(p)) - ) { - return - } - - const relativePath = filePath.replace(path.join(__dirname, '/'), '') - console.log('Transform:', relativePath) - - const source = JSON.stringify(data) - const defaultExportedJson = `const _default = ${source} as const\nexport default _default` - - const project = new Project({ - compilerOptions: { - declaration: true, - emitDeclarationOnly: true, - }, - }) - - project.createSourceFile(filePath + '.ts', defaultExportedJson, { - overwrite: true, - }) - - project - .emit() - .then(() => console.log(' Done! :', relativePath + '.d.ts')) - .catch((err) => console.error(err)) - }, - }), + yaml(), toml, shimReactPdf(), multipleSPA({ diff --git a/yarn.lock b/yarn.lock index 404075b19..9b3a2e697 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1961,22 +1961,6 @@ __metadata: languageName: node linkType: hard -"@cspotcode/source-map-consumer@npm:0.8.0": - version: 0.8.0 - resolution: "@cspotcode/source-map-consumer@npm:0.8.0" - checksum: c0c16ca3d2f58898f1bd74c4f41a189dbcc202e642e60e489cbcc2e52419c4e89bdead02c886a12fb13ea37798ede9e562b2321df997ebc210ae9bd881561b4e - languageName: node - linkType: hard - -"@cspotcode/source-map-support@npm:0.7.0": - version: 0.7.0 - resolution: "@cspotcode/source-map-support@npm:0.7.0" - dependencies: - "@cspotcode/source-map-consumer": 0.8.0 - checksum: 9faddda7757cd778b5fd6812137b2cc265810043680d6399acc20441668fafcdc874053be9dccd0d9110087287bfad27eb3bf342f72bceca9aa9059f5d0c4be8 - languageName: node - linkType: hard - "@cspotcode/source-map-support@npm:^0.8.0": version: 0.8.1 resolution: "@cspotcode/source-map-support@npm:0.8.1" @@ -4334,6 +4318,32 @@ __metadata: languageName: node linkType: hard +"@rushstack/node-core-library@npm:3.45.5": + version: 3.45.5 + resolution: "@rushstack/node-core-library@npm:3.45.5" + dependencies: + "@types/node": 12.20.24 + colors: ~1.2.1 + fs-extra: ~7.0.1 + import-lazy: ~4.0.0 + jju: ~1.4.0 + resolve: ~1.17.0 + semver: ~7.3.0 + timsort: ~0.3.0 + z-schema: ~5.0.2 + checksum: 4533c809401827eca3f98863ef2adb1975a5c57bca3fef706a710dd90828d0468bcc3fce15bda483784d690573be1dfcf890abb99f368e9a3bff75aa88913997 + languageName: node + linkType: hard + +"@rushstack/package-deps-hash@npm:^3.2.20": + version: 3.2.20 + resolution: "@rushstack/package-deps-hash@npm:3.2.20" + dependencies: + "@rushstack/node-core-library": 3.45.5 + checksum: 0275237efdc316feb0baa04bb04c5bf2f7437f6d8e6289634f71a9ed56ca3d1bf0d0e6220e710ef84f3d85b5f36b105728543ac1b195b2fd54d6143356161c96 + languageName: node + linkType: hard + "@sentry/browser@npm:6.19.6": version: 6.19.6 resolution: "@sentry/browser@npm:6.19.6" @@ -6460,6 +6470,13 @@ __metadata: languageName: node linkType: hard +"@types/node@npm:12.20.24": + version: 12.20.24 + resolution: "@types/node@npm:12.20.24" + checksum: e7a13460e2f5b0b5a32c0f3af7daf1a05201552a66d542d3cc3b1ea8b52d4730250f9eb1961d755e31cfe5d03c78340911a6242657a0a9a17d6f7e341fc9f366 + languageName: node + linkType: hard + "@types/node@npm:^14.0.10 || ^16.0.0, @types/node@npm:^14.14.20 || ^16.0.0": version: 16.11.26 resolution: "@types/node@npm:16.11.26" @@ -9622,6 +9639,13 @@ __metadata: languageName: node linkType: hard +"colors@npm:~1.2.1": + version: 1.2.5 + resolution: "colors@npm:1.2.5" + checksum: b6e23de735f68b72d5cdf6fd854ca43d1b66d82dcf54bda0b788083b910164a040f2c4edf23c670d36a7a2d8f1b7d6e62e3292703e4642691e6ccaa1c62d8f74 + languageName: node + linkType: hard + "combined-stream@npm:^1.0.6, combined-stream@npm:^1.0.8, combined-stream@npm:~1.0.6": version: 1.0.8 resolution: "combined-stream@npm:1.0.8" @@ -12781,6 +12805,17 @@ __metadata: languageName: node linkType: hard +"fs-extra@npm:~7.0.1": + version: 7.0.1 + resolution: "fs-extra@npm:7.0.1" + dependencies: + graceful-fs: ^4.1.2 + jsonfile: ^4.0.0 + universalify: ^0.1.0 + checksum: 141b9dccb23b66a66cefdd81f4cda959ff89282b1d721b98cea19ba08db3dcbe6f862f28841f3cf24bb299e0b7e6c42303908f65093cb7e201708e86ea5a8dcf + languageName: node + linkType: hard + "fs-merger@npm:^3.2.1": version: 3.2.1 resolution: "fs-merger@npm:3.2.1" @@ -13824,6 +13859,15 @@ __metadata: languageName: node linkType: hard +"husky@npm:^8.0.0": + version: 8.0.1 + resolution: "husky@npm:8.0.1" + bin: + husky: lib/bin.js + checksum: 943a73a13d0201318fd30e83d299bb81d866bd245b69e6277804c3b462638dc1921694cb94c2b8c920a4a187060f7d6058d3365152865406352e934c5fff70dc + languageName: node + linkType: hard + "hyphen@npm:^1.6.4": version: 1.6.4 resolution: "hyphen@npm:1.6.4" @@ -13961,6 +14005,13 @@ __metadata: languageName: node linkType: hard +"import-lazy@npm:~4.0.0": + version: 4.0.0 + resolution: "import-lazy@npm:4.0.0" + checksum: 22f5e51702134aef78890156738454f620e5fe7044b204ebc057c614888a1dd6fdf2ede0fdcca44d5c173fd64f65c985f19a51775b06967ef58cc3d26898df07 + languageName: node + linkType: hard + "imurmurhash@npm:^0.1.4": version: 0.1.4 resolution: "imurmurhash@npm:0.1.4" @@ -14998,6 +15049,13 @@ __metadata: languageName: node linkType: hard +"jju@npm:~1.4.0": + version: 1.4.0 + resolution: "jju@npm:1.4.0" + checksum: 3790481bd2b7827dd6336e6e3dc2dcc6d425679ba7ebde7b679f61dceb4457ea0cda330972494de608571f4973c6dfb5f70fab6f3c5037dbab19ac449a60424f + languageName: node + linkType: hard + "joi@npm:^17.6.0": version: 17.6.0 resolution: "joi@npm:17.6.0" @@ -19366,6 +19424,15 @@ __metadata: languageName: node linkType: hard +"resolve@npm:~1.17.0": + version: 1.17.0 + resolution: "resolve@npm:1.17.0" + dependencies: + path-parse: ^1.0.6 + checksum: 9ceaf83b3429f2d7ff5d0281b8d8f18a1f05b6ca86efea7633e76b8f76547f33800799dfdd24434942dec4fbd9e651ed3aef577d9a6b5ec87ad89c1060e24759 + languageName: node + linkType: hard + "resolve@patch:resolve@1.1.7#~builtin": version: 1.1.7 resolution: "resolve@patch:resolve@npm%3A1.1.7#~builtin::version=1.1.7&hash=07638b" @@ -19396,6 +19463,15 @@ __metadata: languageName: node linkType: hard +"resolve@patch:resolve@~1.17.0#~builtin": + version: 1.17.0 + resolution: "resolve@patch:resolve@npm%3A1.17.0#~builtin::version=1.17.0&hash=07638b" + dependencies: + path-parse: ^1.0.6 + checksum: 6fd799f282ddf078c4bc20ce863e3af01fa8cb218f0658d9162c57161a2dbafe092b13015b9a4c58d0e1e801cf7aa7a4f13115fea9db98c3f9a0c43e429bad6f + languageName: node + linkType: hard + "responselike@npm:^1.0.2": version: 1.0.2 resolution: "responselike@npm:1.0.2" @@ -19533,6 +19609,7 @@ __metadata: eslint-plugin-promise: ^6.0.0 eslint-plugin-react: ^7.30.0 eslint-plugin-react-hooks: ^4.5.0 + husky: ^8.0.0 prettier: ^2.6.2 rimraf: ^3.0.2 languageName: unknown @@ -19753,7 +19830,7 @@ __metadata: languageName: node linkType: hard -"semver@npm:^7.3.7": +"semver@npm:^7.3.7, semver@npm:~7.3.0": version: 7.3.7 resolution: "semver@npm:7.3.7" dependencies: @@ -20046,6 +20123,7 @@ __metadata: "@redux-devtools/extension": ^3.2.2 "@rollup/plugin-replace": ^4.0.0 "@rollup/plugin-yaml": ^3.1.0 + "@rushstack/package-deps-hash": ^3.2.20 "@sentry/integrations": ^6.19.6 "@sentry/react": ^6.19.6 "@sentry/tracing": ^6.19.6 @@ -20104,8 +20182,8 @@ __metadata: serve-static: ^1.14.2 styled-components: ^5.3.1 ts-morph: ^13.0.3 - ts-node: ^10.5.0 - typescript: ^4.3.2 + ts-node: ^10.8.0 + typescript: ^4.7.2 vite: ^2.9.9 vite-plugin-shim-react-pdf: ^1.0.5 vitest: ^0.9.4 @@ -21053,6 +21131,13 @@ __metadata: languageName: node linkType: hard +"timsort@npm:~0.3.0": + version: 0.3.0 + resolution: "timsort@npm:0.3.0" + checksum: 1a66cb897dacabd7dd7c91b7e2301498ca9e224de2edb9e42d19f5b17c4b6dc62a8d4cbc64f28be82aaf1541cb5a78ab49aa818f42a2989ebe049a64af731e2a + languageName: node + linkType: hard + "tiny-inflate@npm:^1.0.0, tiny-inflate@npm:^1.0.2": version: 1.0.3 resolution: "tiny-inflate@npm:1.0.3" @@ -21301,44 +21386,6 @@ __metadata: languageName: node linkType: hard -"ts-node@npm:^10.5.0": - version: 10.7.0 - resolution: "ts-node@npm:10.7.0" - dependencies: - "@cspotcode/source-map-support": 0.7.0 - "@tsconfig/node10": ^1.0.7 - "@tsconfig/node12": ^1.0.7 - "@tsconfig/node14": ^1.0.0 - "@tsconfig/node16": ^1.0.2 - acorn: ^8.4.1 - acorn-walk: ^8.1.1 - arg: ^4.1.0 - create-require: ^1.1.0 - diff: ^4.0.1 - make-error: ^1.1.1 - v8-compile-cache-lib: ^3.0.0 - yn: 3.1.1 - peerDependencies: - "@swc/core": ">=1.2.50" - "@swc/wasm": ">=1.2.50" - "@types/node": "*" - typescript: ">=2.7" - peerDependenciesMeta: - "@swc/core": - optional: true - "@swc/wasm": - optional: true - bin: - ts-node: dist/bin.js - ts-node-cwd: dist/bin-cwd.js - ts-node-esm: dist/bin-esm.js - ts-node-script: dist/bin-script.js - ts-node-transpile-only: dist/bin-transpile.js - ts-script: dist/bin-script-deprecated.js - checksum: 2a379e43f7478d0b79e1e63af91fe222d83857727957df4bd3bdf3c0a884de5097b12feb9bbf530074526b8874c0338b0e6328cf334f3a5e2c49c71e837273f7 - languageName: node - linkType: hard - "ts-node@npm:^10.8.0": version: 10.8.0 resolution: "ts-node@npm:10.8.0" @@ -21533,7 +21580,7 @@ __metadata: languageName: node linkType: hard -"typescript@npm:^4.2.4, typescript@npm:^4.3.2": +"typescript@npm:^4.2.4": version: 4.6.3 resolution: "typescript@npm:4.6.3" bin: @@ -21553,7 +21600,7 @@ __metadata: languageName: node linkType: hard -"typescript@patch:typescript@^4.2.4#~builtin, typescript@patch:typescript@^4.3.2#~builtin": +"typescript@patch:typescript@^4.2.4#~builtin": version: 4.6.3 resolution: "typescript@patch:typescript@npm%3A4.6.3#~builtin::version=4.6.3&hash=bda367" bin: @@ -22064,13 +22111,6 @@ __metadata: languageName: node linkType: hard -"v8-compile-cache-lib@npm:^3.0.0": - version: 3.0.0 - resolution: "v8-compile-cache-lib@npm:3.0.0" - checksum: 674e312bbca796584b61dc915f33c7e7dc4e06d196e0048cb772c8964493a1ec723f1dd014d9419fd55c24a6eae148f60769da23f622e05cd13268063fa1ed6b - languageName: node - linkType: hard - "v8-compile-cache-lib@npm:^3.0.1": version: 3.0.1 resolution: "v8-compile-cache-lib@npm:3.0.1" @@ -22967,7 +23007,7 @@ __metadata: languageName: node linkType: hard -"z-schema@npm:^5.0.1": +"z-schema@npm:^5.0.1, z-schema@npm:~5.0.2": version: 5.0.3 resolution: "z-schema@npm:5.0.3" dependencies: