diff --git a/.eslintrc.js b/.eslintrc.js index d9331feb09..e44635f50d 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -60,7 +60,7 @@ module.exports = { ], 'rules': { '@o3r/json-dependency-versions-harmonize': ['error', { - ignoredPackages: ['@o3r/build-helpers'], + ignoredPackages: ['@o3r/build-helpers', '@o3r/workspace-helpers'], alignPeerDependencies: false, alignEngines: true }], @@ -81,7 +81,7 @@ module.exports = { ], 'rules': { '@o3r/json-dependency-versions-harmonize': ['error', { - ignoredPackages: ['@o3r/build-helpers'], + ignoredPackages: ['@o3r/build-helpers', '@o3r/workspace-helpers'], ignoredDependencies: ['npm'], alignPeerDependencies: false, alignEngines: true diff --git a/.github/.pr-labelrc.json b/.github/.pr-labelrc.json index 7d2992201d..70a7e02f5f 100644 --- a/.github/.pr-labelrc.json +++ b/.github/.pr-labelrc.json @@ -1,5 +1,5 @@ { - "$schema": "../tools/@o3r/build-helpers/schemas/pr-labels.configuration.schema.json", + "$schema": "../tools/@o3r/workspace-helpers/schemas/pr-labels.configuration.schema.json", "projectLabelPrefix": "project:", "ignoredProjects": [], "ignoreProjectForLabels": ["cascading"] diff --git a/apps/showcase/package.json b/apps/showcase/package.json index 7b839e9959..b436df57dd 100644 --- a/apps/showcase/package.json +++ b/apps/showcase/package.json @@ -97,6 +97,7 @@ "@angular/cli": "~18.2.0", "@angular/compiler-cli": "~18.2.0", "@nx/eslint-plugin": "~19.5.0", + "@o3r/build-helpers": "workspace:^", "@o3r/design": "workspace:^", "@o3r/eslint-config-otter": "workspace:^", "@o3r/eslint-plugin": "workspace:^", diff --git a/docs/components/PLACEHOLDERS.md b/docs/components/PLACEHOLDERS.md index 2a34eace25..0febab0502 100644 --- a/docs/components/PLACEHOLDERS.md +++ b/docs/components/PLACEHOLDERS.md @@ -14,10 +14,10 @@ The component only has 1 input and supports a *content value*. ## Supported features -* HTML limited to behaviour supported by Angular sanitizer -* URLs (relative ones will be processed to add the `dynamic-media-path`) -* Facts references -* Dynamic translation +- HTML limited to behavior supported by Angular sanitizer +- URLs (relative ones will be processed to add the `dynamic-media-path`) +- Facts references +- Dynamic translation ## How it works @@ -25,7 +25,6 @@ Based on the `id` provided to the placeholder component, it will register itself and will display the template corresponding to its ID in the store. > [!IMPORTANT] -> > It is **strongly encouraged** to use the placeholder mechanism in concert with the [Rules Engine](../rules-engine/README.md). ## How to define a placeholder template @@ -89,6 +88,7 @@ export class MyComponentModule { export class MyComponent { } ``` + The loading message is provided by projection. Feel free to provide a spinner if you need. ### How to generate placeholder metadata @@ -204,7 +204,7 @@ Then, let's create a new localization key for each of your supported languages: ```json { - "o3r-increment-key": "Cela fait {increment, plural, =1 {1 seconde}} other {{{increment} secondes} que tu as ouvert cette page" + "o3r-increment-key": "Cela fait {increment, plural, =1 {1 seconde} other {{{increment}} secondes}} que tu as ouvert cette page" } ``` @@ -298,7 +298,6 @@ Thanks to the parameters map you can use fact variables with JSONPath in localiz #### Variable support for localization variables (DEPRECATED) - Before, localization variables could reference facts via variables instead of parameters. This feature is currently deprecated and will be removed from Otter v12 as it is replaced by the parameters explained above. ``en-GB.json`` @@ -408,7 +407,6 @@ displayed in descending order of priority. The placeholder component waits for all the calls to be resolved (not pending) to display the content. The placeholder component ignores a template if the application failed to retrieve it. - ## Reference CSS classes from an external styling file You need to reference one or several CSS files from your application in the `cms.json` file: @@ -438,7 +436,6 @@ You can include this file in your application using the style loader service in this.styleLoader.asyncLoadStyleFromDynamicContent({id: 'placeholders-styling', href: 'assets/rules/placeholders.css'}); ``` - ## Investigate issues If the placeholder is not rendered properly, you can perform several checks to find out the root cause, simply looking diff --git a/migration-guides/11.0.md b/migration-guides/11.0.md index 8f8b4c7eda..c4780dc918 100644 --- a/migration-guides/11.0.md +++ b/migration-guides/11.0.md @@ -14,7 +14,7 @@ - `NodePackageNgAddTask` has been removed. `setupDependencies` should be used instead -- The [`stringifyDate` CLI option](https://www.npmjs.com/package/@ama-sdk/schematics#dates) is now enabled by default. If +- The [`stringifyDate` CLI option](https://www.npmjs.com/package/@ama-sdk/schematics#dates) is now enabled by default. If you want to use the `Date` format, you will need to set it to `false` via the command line: ```shell @@ -29,7 +29,7 @@ or by disabling it for your generator in your `openapitools.json` file: { "$schema": "https://raw.githubusercontent.com/OpenAPITools/openapi-generator-cli/master/apps/generator-cli/src/config.schema.json", "generator-cli": { - "version": "7.4.0", // Version of the Codegen downloaded by the cli - updated via the + "version": "7.4.0", // Version of the Codegen downloaded by the cli - updated via the "storageDir": ".openapi-generator", "generators": { "my-generator": { @@ -46,7 +46,7 @@ or by disabling it for your generator in your `openapitools.json` file: ``` - Prior to version 11, the default types for date and date-time objects were respectively `utils.Date` and `utils.DateTime`. -Those two types take the date from the API response and remove their timezone to consider the date as if it were in the +Those two types take the date from the API response and remove their timezone to consider the date as if it were in the timezone of the user's machine (on a computer on UTC, the 01/01/2000 12:00 in UTC+3 would become 01/01/2000 12:00 UTC+0). If a date had to be expressed in its original timezone, the date specification required an extra `x-date-timezone` vendor. As of version 11, the default behavior is now to keep the timezone of the API response for date-time objects. They @@ -54,8 +54,96 @@ would be revived as `Date` or kept as `string` depending on the value of the `st The removal the timezone is now an 'opt-in' mechanism triggered by the `x-local-timezone` vendor. > [!NOTE] -> This change only impacts `date-time` format. `Date` format will still be revived as `utils.Date` objects as the timezone +> This change only impacts `date-time` format. `Date` format will still be revived as `utils.Date` objects as the timezone > should always be ignored for date object (since there is no concept of time). > [!NOTE] > You can revert to the previous behavior thanks to the global property `useLegacyDateExtension` + +## Deprecated this version + +The following items are **deprecated** and **will be removed** in the version **12**: + +### From [@o3r/components](https://npmjs.com/package/@o3r/components) + +- `CapitalizePipe` is deprecated.
Note: *please use O3rCapitalizePipe* +- `CapitalizePipeModule` is deprecated.
Note: *please use O3rCapitalizePipe* +- `DurationPipe` is deprecated.
Note: *please use O3rDurationPipe* +- `DurationPipeModule` is deprecated.
Note: *please use O3rDurationPipe* +- `KeepWhiteSpacePipe` is deprecated.
Note: *please use O3rKeepWhiteSpacePipe* +- `KeepWhiteSpacePipeModule` is deprecated.
Note: *please use O3rKeepWhiteSpacePipe* +- `ReplaceWithBoldPipe` is deprecated.
Note: *please use O3rReplaceWithBoldPipe* +- `ReplaceWithBoldPipeModule` is deprecated.
Note: *please use O3rReplaceWithBoldPipe* + +### From [@o3r/configuration](https://npmjs.com/package/@o3r/configuration) + +- `computeConfigurationName` is deprecated.
Note: *use `computeItemIdentifier` from [@o3r/core](https://npmjs.com/package/@o3r/core).* +- `ConfigObserver` is deprecated.
Note: *please use O3rConfig* +- `configSignal` is deprecated.
Note: *please do not provide `configurationService`* +- `loadConfiguration` is deprecated.
Note: *please use `updateConfigurations` instead* + +### From [@o3r/dev-tools](https://npmjs.com/package/@o3r/dev-tools) + +- `checkoutBranch` is deprecated. +- `checkoutCrtRcBranch` is deprecated. +- `checkoutCurrentAlphaOrNextBranch` is deprecated. +- `commitChangeLogs` is deprecated. +- `createNextAlphaBranch` is deprecated. +- `createNextMajorBranch` is deprecated. +- `createRcBranch` is deprecated. +- `createReleaseBranch` is deprecated. +- `deleteBranch` is deprecated. +- `deleteCrtRcBranch` is deprecated. +- `deleteCurrentAlphaOrNextBranch` is deprecated. +- `deletePreviousReleaseBranch` is deprecated. +- `GavcResponse` is deprecated. +- `getCrtRcBranch` is deprecated. +- `getCurrentAlphaOrNextBranch` is deprecated. +- `getJestModuleNameMapper` is deprecated.
Note: *Please use `pathsToModuleNameMapper` from `ts-jest`* +- `getJestProjects` is deprecated.
Note: *Please use the one exposed in `@o3r/workspace`* +- `getPackageManager` is deprecated. +- `getPackagesToInstallOrUpdate` is deprecated.
Note: *You can use the one exposed in `@o3r/schematics`* +- `isPackageInstalled` is deprecated.
Note: *You can use the one exposed in `@o3r/schematics`* +- `PackageVersion` is deprecated.
Note: *You can use the one exposed in `@o3r/schematics`* +- `pad` is deprecated.
Note: *You can use the one exposed in `@ama-sdk/core`* +- `PullRequestService` is deprecated.
Note: *Please use `PullRequestService` from `@o3r/azure-tools`* +- `updatePeerDependencies` is deprecated. +- `updateRenovateBaseBranch` is deprecated. + +### From [@o3r/dynamic-content](https://npmjs.com/package/@o3r/dynamic-content) + +- `DynamicContentPipe` is deprecated.
Note: *please use O3rDynamicContentPipe* + +### From [@o3r/localization](https://npmjs.com/package/@o3r/localization) + +- `LocalizationTranslatePipe` is deprecated.
Note: *please use O3rLocalizationTranslatePipe* + +### From [@o3r/rules-engine](https://npmjs.com/package/@o3r/rules-engine) + +- `ActionOverrideBlock` is deprecated. +- `ActionUpdateAssetBlock` is deprecated.
Note: *use the one exposed by `@o3r/dynamic-content` module.* +- `ActionUpdateConfigBlock` is deprecated.
Note: *use the one exposed by `@o3r/configuration` module.* +- `ActionUpdateLocalisationBlock` is deprecated.
Note: *use the one exposed by `@o3r/localization` module.* +- `ActionUpdatePlaceholderBlock` is deprecated.
Note: *use the one exposed by `@o3r/components` module.* +- `FallbackToPipe` is deprecated.
Note: *please use O3rFallbackToPipe* +- `inputFacts` is deprecated.
Note: *Facts that are needed for the rule execution (sent by the CMS)* +- `linkedComponent` is deprecated.
Note: *use `linkedComponents` instead* +- `linkedComponent` is deprecated.
Note: *use `linkedComponents` instead* +- `linkRulesetToComponent` is deprecated.
Note: *It will be replaced by the selector using it* +- `selectRuleSetLinkComponents` is deprecated.
Note: *use `selectComponentsLinkedToRuleset` instead.* + +### From [@o3r/schematics](https://npmjs.com/package/@o3r/schematics) + +- `AddDevInstall` is deprecated.
Note: *use `setupDependencies` instead, will be removed in V11* +- `getProjectNewDependenciesType` is deprecated.
Note: *use `getProjectNewDependenciesTypes instead`, will be removed in V11* +- `install` is deprecated.
Note: *use `setupDependencies` instead, will be removed in V11* +- `isStandaloneRepository` is deprecated.
Note: *no longer in use.* +- `setupSchematicsDefaultParams` is deprecated.
Note: *Use `setupSchematicsParamsForProject`* + +### From [@o3r/styling](https://npmjs.com/package/@o3r/styling) + +- `deviceBreakpoints` is deprecated.
Note: *use Breakpoints exported by [@angular/cdk](https://npmjs.com/package/@angular/cdk) instead* +- `StyleLazyLoader` is deprecated.
Note: *use StyleLazyLoader exported by [@o3r/dynamic-content](https://npmjs.com/package/@o3r/dynamic-content) instead* +- `StyleLazyLoaderModule` is deprecated.
Note: *use StyleLazyLoaderModule exported by [@o3r/dynamic-content](https://npmjs.com/package/@o3r/dynamic-content) instead* +- `StyleURL` is deprecated.
Note: *use StyleURL exported by [@o3r/dynamic-content](https://npmjs.com/package/@o3r/dynamic-content) instead* + diff --git a/package.json b/package.json index 9fc54c3247..b88a970ed5 100644 --- a/package.json +++ b/package.json @@ -198,6 +198,7 @@ "@o3r/eslint-plugin": "workspace:^", "@o3r/telemetry": "workspace:^", "@o3r/workspace": "workspace:^", + "@o3r/workspace-helpers": "workspace:^", "@playwright/test": "~1.48.0", "@popperjs/core": "^2.11.5", "@schematics/angular": "~18.2.0", diff --git a/packages/@ama-sdk/create/.eslintrc.js b/packages/@ama-sdk/create/.eslintrc.js index 4a5eef7ed1..ddfa032ba5 100644 --- a/packages/@ama-sdk/create/.eslintrc.js +++ b/packages/@ama-sdk/create/.eslintrc.js @@ -20,7 +20,7 @@ module.exports = { 'files': ['package.json'], 'rules': { '@o3r/json-dependency-versions-harmonize': ['error', { - 'ignoredPackages': ['@o3r/build-helpers'], + 'ignoredPackages': ['@o3r/build-helpers', '@o3r/workspace-helpers'], ignoredDependencies: ['yarn'], 'alignPeerDependencies': false }] diff --git a/packages/@o3r/create/.eslintrc.js b/packages/@o3r/create/.eslintrc.js index 4a5eef7ed1..ddfa032ba5 100644 --- a/packages/@o3r/create/.eslintrc.js +++ b/packages/@o3r/create/.eslintrc.js @@ -20,7 +20,7 @@ module.exports = { 'files': ['package.json'], 'rules': { '@o3r/json-dependency-versions-harmonize': ['error', { - 'ignoredPackages': ['@o3r/build-helpers'], + 'ignoredPackages': ['@o3r/build-helpers', '@o3r/workspace-helpers'], ignoredDependencies: ['yarn'], 'alignPeerDependencies': false }] diff --git a/packages/@o3r/rules-engine/src/interfaces/action.interfaces.ts b/packages/@o3r/rules-engine/src/interfaces/action.interfaces.ts index 9a83be40a3..044dac3faa 100644 --- a/packages/@o3r/rules-engine/src/interfaces/action.interfaces.ts +++ b/packages/@o3r/rules-engine/src/interfaces/action.interfaces.ts @@ -2,7 +2,7 @@ import type { ActionBlock } from '../engine/index'; /** * Content of action that updates the configuration - * @deprecated use the one exposer by `@o3r/configuration` module. Will be removed in Otter v12. + * @deprecated use the one exposed by `@o3r/configuration` module. Will be removed in Otter v12. */ export interface ActionUpdateConfigBlock extends ActionBlock { actionType: 'UPDATE_CONFIG'; @@ -13,7 +13,7 @@ export interface ActionUpdateConfigBlock extends ActionBlock { /** * Content of action that updates an asset - * @deprecated use the one exposer by `@o3r/dynamic-content` module. Will be removed in Otter v12. + * @deprecated use the one exposed by `@o3r/dynamic-content` module. Will be removed in Otter v12. */ export interface ActionUpdateAssetBlock extends ActionBlock { actionType: 'UPDATE_ASSET'; @@ -23,7 +23,7 @@ export interface ActionUpdateAssetBlock extends ActionBlock { /** * Content of action that updates localization - * @deprecated use the one exposer by `@o3r/localization` module. Will be removed in Otter v12. + * @deprecated use the one exposed by `@o3r/localization` module. Will be removed in Otter v12. */ export interface ActionUpdateLocalisationBlock extends ActionBlock { actionType: 'UPDATE_LOCALISATION'; @@ -33,7 +33,7 @@ export interface ActionUpdateLocalisationBlock extends ActionBlock { /** * Content of action that updates a placeholder - * @deprecated use the one exposer by `@o3r/components` module. Will be removed in Otter v12. + * @deprecated use the one exposed by `@o3r/components` module. Will be removed in Otter v12. */ export interface ActionUpdatePlaceholderBlock extends ActionBlock { actionType: 'UPDATE_PLACEHOLDER'; diff --git a/packages/@o3r/rules-engine/src/stores/rulesets/rulesets.selectors.ts b/packages/@o3r/rules-engine/src/stores/rulesets/rulesets.selectors.ts index 26745ece9b..b4725ea807 100644 --- a/packages/@o3r/rules-engine/src/stores/rulesets/rulesets.selectors.ts +++ b/packages/@o3r/rules-engine/src/stores/rulesets/rulesets.selectors.ts @@ -66,9 +66,13 @@ export const selectActiveRuleSets = createSelector( return to && to.getTime() >= time; }).map((ruleSet: Ruleset) => ruleSet.id)); -/* +/** * Assign rulesetId to a component - * @deprecated; It will be rmeoved in v12 with the selector using it + * @param compName + * @param library + * @param ruleSetId + * @param acc + * @deprecated It will be replaced by the selector using it, will be removed in v12. */ function linkRulesetToComponent(compName: string, library: string, ruleSetId: string, acc: Record = {}) { const configName = computeItemIdentifier(compName, library); @@ -76,7 +80,13 @@ function linkRulesetToComponent(compName: string, library: string, ruleSetId: st acc[configName].push(ruleSetId); } -/* Assign component to RulesetIds Map */ +/** + * Assign component to RulesetIds Map + * @param compName + * @param library + * @param ruleSetId + * @param acc + */ function linkComponentToRuleset(compName: string, library: string, ruleSetId: string, acc: Record = {}) { const configName = computeItemIdentifier(compName, library); acc[ruleSetId] ||= []; diff --git a/packages/@o3r/telemetry/package.json b/packages/@o3r/telemetry/package.json index cd059dd7a4..d92162158a 100644 --- a/packages/@o3r/telemetry/package.json +++ b/packages/@o3r/telemetry/package.json @@ -47,6 +47,7 @@ "@nx/eslint-plugin": "~19.5.0", "@nx/jest": "~19.5.0", "@nx/js": "~19.5.0", + "@o3r/build-helpers": "workspace:^", "@o3r/eslint-plugin": "workspace:^", "@stylistic/eslint-plugin-ts": "~2.4.0", "@types/jest": "~29.5.2", diff --git a/packages/@o3r/test-helpers/package.json b/packages/@o3r/test-helpers/package.json index 8d1055ddeb..06986c3599 100644 --- a/packages/@o3r/test-helpers/package.json +++ b/packages/@o3r/test-helpers/package.json @@ -46,6 +46,7 @@ "@jest/environment": "~29.7.0", "@jest/types": "~29.6.3", "@nx/eslint-plugin": "~19.5.0", + "@o3r/build-helpers": "workspace:^", "@o3r/eslint-plugin": "workspace:^", "@o3r/schematics": "workspace:^", "@schematics/angular": "~18.2.0", diff --git a/tools/@o3r/build-helpers/package.json b/tools/@o3r/build-helpers/package.json index d589484122..2a9141f468 100644 --- a/tools/@o3r/build-helpers/package.json +++ b/tools/@o3r/build-helpers/package.json @@ -52,12 +52,5 @@ "eslint-plugin-unicorn": "^54.0.0", "nx": "~19.5.0", "typescript": "~5.5.4" - }, - "otter": { - "versionHarmonize": { - "ignore": [ - "globby" - ] - } } } diff --git a/tools/@o3r/workspace-helpers/.eslintrc.cjs b/tools/@o3r/workspace-helpers/.eslintrc.cjs new file mode 100644 index 0000000000..abfad56e5f --- /dev/null +++ b/tools/@o3r/workspace-helpers/.eslintrc.cjs @@ -0,0 +1,16 @@ +/* eslint-disable @typescript-eslint/naming-convention */ +/* eslint-disable quote-props */ + +module.exports = { + 'root': true, + 'parserOptions': { + 'tsconfigRootDir': __dirname, + 'sourceType': 'module', + 'project': [ + 'tsconfig.eslint.json' + ], + }, + 'extends': [ + '../../../.eslintrc.js' + ] +}; diff --git a/tools/@o3r/workspace-helpers/.gitignore b/tools/@o3r/workspace-helpers/.gitignore new file mode 100644 index 0000000000..dfefc61dd2 --- /dev/null +++ b/tools/@o3r/workspace-helpers/.gitignore @@ -0,0 +1,2 @@ +/index.* +.tsbuildinfo diff --git a/tools/@o3r/workspace-helpers/package.json b/tools/@o3r/workspace-helpers/package.json new file mode 100644 index 0000000000..ff0f403d2e --- /dev/null +++ b/tools/@o3r/workspace-helpers/package.json @@ -0,0 +1,48 @@ +{ + "name": "@o3r/workspace-helpers", + "version": "0.0.0-placeholder", + "description": "Workspace helpers", + "type": "module", + "private": true, + "keywords": [ + "otter", + "amadeus", + "typescript" + ], + "files": [ + "scripts/*.mjs" + ], + "bin": { + "create-monorepo-scope": "./scripts/create-monorepo-scope.mjs", + "doc-links": "./scripts/doc-links.mjs", + "pr-labels": "./scripts/pr-labels.mjs", + "prepare-doc-root-menu-template": "./scripts/prepare-doc-root-menu-template.mjs", + "report-deprecates": "./scripts/report-deprecates.mjs", + "update-doc-summary": "./scripts/update-doc-summary.mjs" + }, + "dependencies": { + "globby": "^14.0.0", + "minimist": "^1.2.6" + }, + "peerDependencies": { + "typescript": "~5.5.4" + }, + "devDependencies": { + "@angular-eslint/eslint-plugin": "~18.3.0", + "@nx/eslint-plugin": "~19.5.0", + "@o3r/eslint-plugin": "workspace:^", + "@stylistic/eslint-plugin-ts": "~2.4.0", + "@types/node": "^20.0.0", + "@typescript-eslint/eslint-plugin": "^7.14.1", + "@typescript-eslint/parser": "^7.14.1", + "@typescript-eslint/utils": "^7.14.1", + "eslint": "^8.57.0", + "eslint-import-resolver-node": "^0.3.9", + "eslint-plugin-jest": "~28.8.0", + "eslint-plugin-jsdoc": "~48.11.0", + "eslint-plugin-prefer-arrow": "~1.2.3", + "eslint-plugin-unicorn": "^54.0.0", + "nx": "~19.5.0", + "typescript": "~5.5.4" + } +} diff --git a/tools/@o3r/workspace-helpers/project.json b/tools/@o3r/workspace-helpers/project.json new file mode 100644 index 0000000000..5fa0a1ac3f --- /dev/null +++ b/tools/@o3r/workspace-helpers/project.json @@ -0,0 +1,7 @@ +{ + "name": "workspace-helpers", + "$schema": "https://raw.githubusercontent.com/nrwl/nx/master/packages/nx/schemas/project-schema.json", + "projectType": "library", + "sourceRoot": "packages/@o3r/workspace-helpers/scripts", + "tags": [] +} diff --git a/tools/@o3r/workspace-helpers/readme.md b/tools/@o3r/workspace-helpers/readme.md new file mode 100644 index 0000000000..eee38d2ba6 --- /dev/null +++ b/tools/@o3r/workspace-helpers/readme.md @@ -0,0 +1,43 @@ +# @o3r/workspace-builder + +This package exposes a set of scripts to be used in the Otter Workspace to help task automation. + +## Scripts + +Find below the list of scripts and their descriptions: + +### [create-monorepo-scope](./scripts/create-monorepo-scope.mjs) + +Create a new scope in the Otter monorepo. + +### [doc-links](./scripts/doc-links.mjs) + +Check the broken links within the documentation files. + +### [pr-labels](./scripts/pr-labelss.mjs) + +Determine Github Labels based on PR commit messages. + +### [prepare-doc-root-menu-template](./scripts/prepare-doc-root-menu-template.mjs) + +The purpose of this script is to prepare the root menu template with the list of packages inside.\ +Parameters: + +* **compodocGlobFiles**: Glob to identify all compodoc configurations for packages +* **menuTemplateFile**: File path for the handlebars template menu +* **generatedDocOutputRegExp**: RegExp to remove to have the relative path of the output documentation compared to the root one +* **packagesVariableValueIdentifier**: Identifier to be replaced by the package value + +### [report-deprecates](./scripts/report-deprecates.mjs) + +The purpose of this script is to generate a report of the deprecated items in the repository code.\ +Parameters: + +* **root**: Root folder from which the script is executed +* **output**: Output path to the migration file +* **ignore**: List of ignore file patterns (comma separated) +* **versionPattern**: RegExp to find the version in the deprecated message + +### [update-doc-summary](./scripts/update-doc-summary.mjs) + +Update the documentation summary for generated documentation website. diff --git a/tools/@o3r/build-helpers/schemas/pr-labels.configuration.schema.json b/tools/@o3r/workspace-helpers/schemas/pr-labels.configuration.schema.json similarity index 100% rename from tools/@o3r/build-helpers/schemas/pr-labels.configuration.schema.json rename to tools/@o3r/workspace-helpers/schemas/pr-labels.configuration.schema.json diff --git a/tools/@o3r/build-helpers/scripts/create-monorepo-scope.mjs b/tools/@o3r/workspace-helpers/scripts/create-monorepo-scope.mjs similarity index 100% rename from tools/@o3r/build-helpers/scripts/create-monorepo-scope.mjs rename to tools/@o3r/workspace-helpers/scripts/create-monorepo-scope.mjs diff --git a/tools/@o3r/build-helpers/scripts/doc-links.mjs b/tools/@o3r/workspace-helpers/scripts/doc-links.mjs similarity index 100% rename from tools/@o3r/build-helpers/scripts/doc-links.mjs rename to tools/@o3r/workspace-helpers/scripts/doc-links.mjs diff --git a/tools/@o3r/build-helpers/scripts/pr-labels.mjs b/tools/@o3r/workspace-helpers/scripts/pr-labels.mjs similarity index 100% rename from tools/@o3r/build-helpers/scripts/pr-labels.mjs rename to tools/@o3r/workspace-helpers/scripts/pr-labels.mjs diff --git a/tools/@o3r/build-helpers/scripts/prepare-doc-root-menu-template.mjs b/tools/@o3r/workspace-helpers/scripts/prepare-doc-root-menu-template.mjs similarity index 100% rename from tools/@o3r/build-helpers/scripts/prepare-doc-root-menu-template.mjs rename to tools/@o3r/workspace-helpers/scripts/prepare-doc-root-menu-template.mjs diff --git a/tools/@o3r/workspace-helpers/scripts/report-deprecates.mjs b/tools/@o3r/workspace-helpers/scripts/report-deprecates.mjs new file mode 100644 index 0000000000..38b0ef2ae4 --- /dev/null +++ b/tools/@o3r/workspace-helpers/scripts/report-deprecates.mjs @@ -0,0 +1,195 @@ +/* + * The purpose of this script is to generate a report of the deprecated items in the repository code + * @param root Root folder from which the script is executed + * @param output Output path to the migration file + * @param ignore List of ignore file patterns (comma separated) + * @param versionPattern RegExp to find the version in the deprecated message + */ + +import { readFile, writeFile } from 'node:fs/promises'; +import { globby as glob } from 'globby'; +import { resolve, relative, sep } from 'node:path'; +import minimist from 'minimist'; +import { createSourceFile, ScriptTarget, isJSDoc, isIdentifier, isVariableDeclarationList } from 'typescript'; +import { existsSync } from 'node:fs'; + +const argv = minimist(process.argv.slice(2)); +const root = argv.root ? resolve(process.cwd(), argv.root) : process.cwd(); +const version = argv.version || argv._.at(0) || '0'; +const output = resolve(process.cwd(), argv.output || argv.o || 'migration-guides/{VERSION}.0.md').replaceAll('{VERSION}', version); +const ignore = argv.ignore ? argv.ignore.split(',') : [ + '**/dist/**' +]; +const versionPattern = argv.versionPattern ? new RegExp(argv.versionPattern) : /[vV]([0-9]+(?:[.][0-9]+)?)/; +const removalTargetVersion = +version + 1; +/** + * Work through the TS Node to find the deprecated node + * @param {import("typescript").SourceFile} sourceFile + * @param {import("typescript").Node} node + * @returns {import("typescript").Node} + */ +const workThroughTypescript = (sourceFile, node, index) => { + const children = node.getChildren(sourceFile) + .filter((n) => !isJSDoc(n) && n.getStart(sourceFile, true) <= index && n.getEnd() > index) + + return children.reduce((acc, n) => workThroughTypescript(sourceFile, n, index) || acc, node) +}; + +/** Get deprecated items in TS files */ +const getTypescriptDeprecations = async () => { + const deprecateRegExp = /@deprecated/g; + const deprecateLineRegExp = /@deprecated(.*?)(?: *\*\/)?$/mg; + const files = await glob('**/*.{c,m,}ts', {cwd: root, ignore, gitignore: true}); + const reports = []; + for (let file of files) { + file = resolve(root, file); + const content = await readFile(file, { encoding: 'utf8' }); + const match = [...content.matchAll(deprecateRegExp)]; + if (!match.length) { + continue; + } + + const sourceFile = createSourceFile( + file, + content, + ScriptTarget.ESNext, + true + ); + reports.push(...match + .map(({ index }) => workThroughTypescript(sourceFile, sourceFile, index)) + .map((node) => { + const deprecationInfo = [ + ...node + .getFullText(sourceFile) + .matchAll(deprecateLineRegExp) + ].map(([, description]) => description.trim()).join('\n') + + let nodeLabel = node.getText(sourceFile); + if (typeof node.name !== 'undefined' && isIdentifier(node.name)) { + nodeLabel = node.name.getText(); + } else if (typeof node.declarationList !== 'undefined' && isVariableDeclarationList(node.declarationList)) { + nodeLabel = node.declarationList.declarations.map(({name}) => name.getText()).join(', ') + } + return { + file, + report: { + node: nodeLabel, + deprecationInfo, + version: deprecationInfo.match(versionPattern)?.[1] + } + }; + }) + ); + } + return reports; +}; + +/** + * Work through the JSON fields do find the deprecated item + * @param {Object} json + * @param {RegExp} nodeNameToDetect + */ +const workThroughJson = (json, nodeNameToDetect) => { + const memory = []; + const rec = (node, ancestors, mem) => { + if (Array.isArray(node)) { + return node.reduce((acc, n) => rec(n, ancestors, acc), mem); + } else if (node === null || typeof node !== 'object') { + return mem; + } + + const entries = Object.entries(node); + entries + .map(([key]) => key) + .filter((key) => nodeNameToDetect.test(key)) + .forEach((key) => { + const deprecationInfo = node[key]; + mem.push({ + node: ancestors, + deprecationInfo, + version: deprecationInfo.match(versionPattern)?.[1] + }); + }); + + return entries.reduce((acc, [key, value]) => rec(value, `${ancestors}.${key}`, acc), mem); + } + + return rec(json, '', memory); +} + +/** Get deprecated items in JSON files */ +const getJsonDeprecations = async () => { + const deprecateNodeRegExp = /"[$]?deprecated"/; + const files = await glob('**/*.json', { cwd: root, ignore, gitignore: true }); + const contents = await Promise.all(files + .map((file) => resolve(root, file)) + .map(async (file) => ({ file, content: await readFile(file, { encoding: 'utf8' }) })) + ); + + return contents + .filter(({ content }) => !!content.match(deprecateNodeRegExp)) + .map(({ file, content }) => ({ + file, + content: JSON.parse(content) + })) + .map(({ file, content }) => ({ + file, + report: workThroughJson(content, deprecateNodeRegExp) + })) + .filter(({report}) => !!report.length); +}; + +/** + * Format the note message + * @param {string} message + * @returns {string} + */ +const formatNoteMessage = (message) => { + return message + .replace(/\{@link ([^\}]+)\}/g, '`$1`') + .replace(/(^|\s+)@([\w-]+)\/([\w-]+)/g, '$1[@$2/$3](https://npmjs.com/package/@$2/$3)'); +}; + +// Executed at CLI call +void (async() => { + const startTag = ''; + const endTag = ''; + let template = `${startTag} +## Deprecated this version + +The following items are **deprecated** and **will be removed** in the version **${removalTargetVersion}**: +`; + const changeMap = (await Promise.all([getJsonDeprecations(), getTypescriptDeprecations()])) + .flat() + .filter(({ report }) => +report.version <= removalTargetVersion) + .reduce((acc, { file, report }) => { + const relativeFile = relative(root, file) + const pck = /@[^/\\]+[/\\][^/\\]+/.exec(relativeFile)?.[0] || relativeFile; + (acc[pck] ||= []).push(report); + return acc; + },{}); + + Object.entries(changeMap) + .sort(([pck1], [pck2]) => pck1.localeCompare(pck2)) + .forEach(([pck, reports]) => { + template += `\n### From [${pck}](https://npmjs.com/package/${pck})\n\n`; + reports + .sort(({ node }, report) => node.localeCompare(report.node)) + .forEach(({ node, deprecationInfo }) => { + const message = deprecationInfo.replace(new RegExp(`[, ]*(?:it )?will be removed in (:?otter ?)?v${removalTargetVersion}[,.\\s]*`, 'i'), '').trim(); + template += `- \`${node}\` is deprecated.` + (message ? `
Note: *${formatNoteMessage(message)}*` : '') + '\n'; + }); + }); + + template += endTag; + + let outputFileContent = existsSync(output) ? await readFile(output, {encoding: 'utf8'}) : ''; + const startIdx = outputFileContent.indexOf(startTag); + const endIdx = outputFileContent.indexOf(endTag); + if (startIdx > -1 && endIdx > -1) { + outputFileContent = outputFileContent.slice(0, startIdx) + template + outputFileContent.slice(endIdx + endTag.length); + } else { + outputFileContent += template; + } + writeFile(output, outputFileContent); +})(); diff --git a/tools/@o3r/build-helpers/scripts/update-doc-summary.mjs b/tools/@o3r/workspace-helpers/scripts/update-doc-summary.mjs similarity index 100% rename from tools/@o3r/build-helpers/scripts/update-doc-summary.mjs rename to tools/@o3r/workspace-helpers/scripts/update-doc-summary.mjs diff --git a/tools/@o3r/workspace-helpers/tsconfig.eslint.json b/tools/@o3r/workspace-helpers/tsconfig.eslint.json new file mode 100644 index 0000000000..7abdbdaeb4 --- /dev/null +++ b/tools/@o3r/workspace-helpers/tsconfig.eslint.json @@ -0,0 +1,9 @@ +{ + "extends": "../../../tsconfig.build.json", + "compilerOptions": { + "allowJs": true + }, + "include": [ + "./scripts/*.mjs" + ] +} diff --git a/yarn.lock b/yarn.lock index f057a8b420..d7bc02a71a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8616,6 +8616,7 @@ __metadata: "@o3r/eslint-plugin": "workspace:^" "@o3r/telemetry": "workspace:^" "@o3r/workspace": "workspace:^" + "@o3r/workspace-helpers": "workspace:^" "@playwright/test": "npm:~1.48.0" "@popperjs/core": "npm:^2.11.5" "@schematics/angular": "npm:~18.2.0" @@ -9458,6 +9459,7 @@ __metadata: "@nx/eslint-plugin": "npm:~19.5.0" "@nx/jest": "npm:~19.5.0" "@o3r/application": "workspace:^" + "@o3r/build-helpers": "workspace:^" "@o3r/components": "workspace:^" "@o3r/configuration": "workspace:^" "@o3r/core": "workspace:^" @@ -9903,6 +9905,7 @@ __metadata: "@nx/eslint-plugin": "npm:~19.5.0" "@nx/jest": "npm:~19.5.0" "@nx/js": "npm:~19.5.0" + "@o3r/build-helpers": "workspace:^" "@o3r/eslint-plugin": "workspace:^" "@stylistic/eslint-plugin-ts": "npm:~2.4.0" "@types/jest": "npm:~29.5.2" @@ -9954,6 +9957,7 @@ __metadata: "@jest/environment": "npm:~29.7.0" "@jest/types": "npm:~29.6.3" "@nx/eslint-plugin": "npm:~19.5.0" + "@o3r/build-helpers": "workspace:^" "@o3r/eslint-plugin": "workspace:^" "@o3r/schematics": "workspace:^" "@schematics/angular": "npm:~18.2.0" @@ -10290,6 +10294,40 @@ __metadata: languageName: unknown linkType: soft +"@o3r/workspace-helpers@workspace:^, @o3r/workspace-helpers@workspace:tools/@o3r/workspace-helpers": + version: 0.0.0-use.local + resolution: "@o3r/workspace-helpers@workspace:tools/@o3r/workspace-helpers" + dependencies: + "@angular-eslint/eslint-plugin": "npm:~18.3.0" + "@nx/eslint-plugin": "npm:~19.5.0" + "@o3r/eslint-plugin": "workspace:^" + "@stylistic/eslint-plugin-ts": "npm:~2.4.0" + "@types/node": "npm:^20.0.0" + "@typescript-eslint/eslint-plugin": "npm:^7.14.1" + "@typescript-eslint/parser": "npm:^7.14.1" + "@typescript-eslint/utils": "npm:^7.14.1" + eslint: "npm:^8.57.0" + eslint-import-resolver-node: "npm:^0.3.9" + eslint-plugin-jest: "npm:~28.8.0" + eslint-plugin-jsdoc: "npm:~48.11.0" + eslint-plugin-prefer-arrow: "npm:~1.2.3" + eslint-plugin-unicorn: "npm:^54.0.0" + globby: "npm:^14.0.0" + minimist: "npm:^1.2.6" + nx: "npm:~19.5.0" + typescript: "npm:~5.5.4" + peerDependencies: + typescript: ~5.5.4 + bin: + create-monorepo-scope: ./scripts/create-monorepo-scope.mjs + doc-links: ./scripts/doc-links.mjs + pr-labels: ./scripts/pr-labels.mjs + prepare-doc-root-menu-template: ./scripts/prepare-doc-root-menu-template.mjs + report-deprecates: ./scripts/report-deprecates.mjs + update-doc-summary: ./scripts/update-doc-summary.mjs + languageName: unknown + linkType: soft + "@o3r/workspace@workspace:^, @o3r/workspace@workspace:packages/@o3r/workspace": version: 0.0.0-use.local resolution: "@o3r/workspace@workspace:packages/@o3r/workspace"