@elliemae/ds-monorepo-devops 3.50.1-next.9 → 3.51.0-next.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/bin/cli.mjs ADDED
@@ -0,0 +1,20 @@
1
+ import arg from 'arg';
2
+ import { checkCommandOrInquire, executeCommandsMap } from './execute-commands-map.mjs';
3
+
4
+ function parseArgumentsIntoOptions(rawArgs) {
5
+ const args = arg(
6
+ {},
7
+ {
8
+ argv: rawArgs.slice(2),
9
+ },
10
+ );
11
+ return {
12
+ command: args._[0],
13
+ };
14
+ }
15
+
16
+ export async function cli(args) {
17
+ let options = parseArgumentsIntoOptions(args);
18
+ options = await checkCommandOrInquire(options);
19
+ executeCommandsMap(args, options);
20
+ }
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env node
2
+ import { cli } from './cli.mjs';
3
+
4
+ cli(process.argv);
@@ -0,0 +1,104 @@
1
+ /* eslint-disable complexity, no-console, max-statements */
2
+ import inquirer from 'inquirer';
3
+ import defGlob from 'glob';
4
+ import path from 'node:path';
5
+ import fs from 'node:fs';
6
+ const { glob } = defGlob;
7
+
8
+ export async function promptForCommandOptions(options) {
9
+ const questions = [];
10
+ if (!options.hello) {
11
+ questions.push({
12
+ type: 'list',
13
+ name: 'dryRun',
14
+ message: 'dry-run?',
15
+ default: 'n',
16
+ choices: ['y', 'n'],
17
+ });
18
+ }
19
+ const answers = await inquirer.prompt(questions);
20
+
21
+ return {
22
+ ...answers,
23
+ };
24
+ }
25
+
26
+ /**
27
+ * check all subfolders under cwd + packages/ for a package.json file
28
+ * - if it exists, check for project.json file in the same folder
29
+ * - if it doesn't exist, continue to the next folder
30
+ * - if both exist, check the "tags" array in the project.json file to
31
+ * - package.json `typesafety`
32
+ * - true
33
+ * - tag ensure "strict-eslint" exists in the tags array
34
+ * - false
35
+ * - tag remove "strict-eslint" from the tags array if it exists
36
+ * - `"status:eol"`
37
+ * - yes
38
+ * - remove the taxonomy tag from the tags array
39
+ * - no
40
+ * - add the taxonomy tag to the tags array if it doesn't exist or prompt the user to add it(in dry-run mode)
41
+ * (E.G. packages/layout/... -> "layout", packages/atom/... -> "atom")
42
+ * - if it doesn't exist, continue to the next folder
43
+ * @param options
44
+ * @param {string} [options.dryRun='n'] - Indicates whether to perform a dry run ('y' or 'n').
45
+ * @returns {Promise<void>}
46
+ */
47
+ const fixMissingTags = async (options) => {
48
+ const { dryRun } = options;
49
+ const globPatternPackage = 'packages/**/*/package.json';
50
+ const packageJsonFilesPaths = glob(globPatternPackage, { sync: true, ignore: ['**/node_modules/**', '**/dist/**'] });
51
+ for (let i = 0; i < packageJsonFilesPaths.length; i += 1) {
52
+ const packageJsonFilePath = packageJsonFilesPaths[i];
53
+ const finalPath = path.resolve(process.cwd(), packageJsonFilePath);
54
+ const packageJson = JSON.parse(fs.readFileSync(finalPath, 'utf8'));
55
+ const { publishConfig: { typeSafety = false } = {} } = packageJson;
56
+ const taxonomy = finalPath.split('/').reverse()[2];
57
+
58
+ const projectJsonFilePath = path.resolve(finalPath, '../project.json');
59
+ if (!fs.existsSync(projectJsonFilePath)) continue;
60
+ const projectJson = JSON.parse(fs.readFileSync(projectJsonFilePath, 'utf8'));
61
+ const missingTags = [];
62
+ const extraTags = [];
63
+
64
+ const isMarkedAsStrict = projectJson.tags.includes('strict-eslint');
65
+ if (typeSafety && !isMarkedAsStrict) missingTags.push('strict-eslint');
66
+ if (!typeSafety && isMarkedAsStrict) extraTags.push('strict-eslint');
67
+
68
+ const isEol = projectJson.tags.includes('status:eol');
69
+ const hasTaxonomy = projectJson.tags.includes(taxonomy);
70
+ if (!isEol && !hasTaxonomy) missingTags.push(taxonomy);
71
+ if (isEol && hasTaxonomy) extraTags.push(taxonomy);
72
+
73
+ const shouldRemoveTags = extraTags.length !== 0;
74
+ const shouldAddTags = missingTags.length !== 0;
75
+ const shouldDoNothing = !shouldAddTags && !shouldRemoveTags;
76
+ if (shouldDoNothing) continue;
77
+
78
+ // mutate projectJson.tags
79
+ if (shouldAddTags) {
80
+ projectJson.tags.push(...missingTags);
81
+ }
82
+ // mutate projectJson.tags
83
+ if (shouldRemoveTags) {
84
+ projectJson.tags = projectJson.tags.filter((tag) => !extraTags.includes(tag));
85
+ }
86
+
87
+ if (dryRun === 'n') {
88
+ projectJson.tags.sort();
89
+ fs.writeFileSync(projectJsonFilePath, JSON.stringify(projectJson, null, 2));
90
+ if (shouldAddTags) console.log(`Added ${missingTags.join(', ')} tag to ${projectJsonFilePath}`);
91
+ if (shouldRemoveTags) console.log(`Removed ${taxonomy} tag from ${projectJsonFilePath}`);
92
+ continue;
93
+ }
94
+ if (dryRun === 'y') {
95
+ if (shouldAddTags) console.log(`Would have added ${missingTags.join(', ')} to ${projectJsonFilePath}`);
96
+ if (shouldRemoveTags) console.log(`Would have removed ${taxonomy} from ${projectJsonFilePath}`);
97
+ }
98
+ }
99
+ };
100
+
101
+ export const execSyncNxTags = async (options) => {
102
+ const commandOptions = await promptForCommandOptions(options);
103
+ await fixMissingTags(commandOptions);
104
+ };
@@ -0,0 +1,33 @@
1
+ import inquirer from 'inquirer';
2
+ import { execSyncNxTags } from './execSyncNxTags/index.mjs';
3
+
4
+ const COMMANDS = {
5
+ SYNC_NX_TAGS: 'sync-nx-tags',
6
+ EXIT: 'exit',
7
+ };
8
+ export const checkCommandOrInquire = async (options) => {
9
+ const questions = [];
10
+ if (!options.command) {
11
+ questions.push({
12
+ type: 'list',
13
+ name: 'command',
14
+ message: 'Please choose which command to run',
15
+ choices: Object.values(COMMANDS),
16
+ });
17
+ }
18
+ const answers = await inquirer.prompt(questions);
19
+ return {
20
+ ...options,
21
+ ...answers,
22
+ };
23
+ };
24
+
25
+ export async function executeCommandsMap(args, options) {
26
+ switch (options.command) {
27
+ case COMMANDS.SYNC_NX_TAGS:
28
+ execSyncNxTags(options);
29
+ break;
30
+ default:
31
+ break;
32
+ }
33
+ }
@@ -1,14 +1,70 @@
1
1
  import { jestConfig } from '@elliemae/pui-cli';
2
+ import path from 'path';
3
+ import { fileURLToPath } from 'url';
4
+ const __filename = fileURLToPath(import.meta.url); // get the resolved path to the file
5
+ const __dirname = path.dirname(__filename); // get the name of the directory
6
+ const getFileFromCurrentFolder = (fileName) => path.normalize(path.resolve(__dirname, fileName));
7
+ /**
8
+ * Generates an array of setup files for Jest based on provided flags.
9
+ *
10
+ * @param {Object} options - The options object.
11
+ * @param {boolean} [options.silenceConsole=false] - Flag to determine if console output should be silenced.
12
+ * @returns {string[]} An array of setup files for Jest.
13
+ */
14
+ const getSetupFilesAfterEnvBasedOnFlags = ({ silenceConsole = false }) => {
15
+ const setupFilesAfterEnv = [];
2
16
 
3
- export const config = (specificFile = undefined, specialRules = {}) => ({
4
- ...jestConfig,
5
- collectCoverage: false,
6
- collectCoverageFrom: [],
7
- coverageDirectory: undefined,
8
- coverageReporters: undefined,
9
- ...specialRules,
10
- // testRegex: 'tests/.*\\.test\\.[jt]sx?$',
11
- testRegex: specificFile ? `.*/tests/${specificFile}$` : 'tests/.*\\.test\\.[jt]sx?$',
12
- testTimeout: 120000,
13
- });
17
+ if (silenceConsole) {
18
+ setupFilesAfterEnv.push(getFileFromCurrentFolder('noConsoleMode.mjs'));
19
+ }
20
+
21
+ return setupFilesAfterEnv;
22
+ };
23
+
24
+ /**
25
+ * Generates a Jest configuration object.
26
+ *
27
+ * @param {Object} options - Configuration options.
28
+ * @param {string} [options.relativePathAfterTestsFolder] - Relative path after the tests folder to match test files.
29
+ * @param {Object} [options.firstLevelSpread] - Configuration options to override defaults.
30
+ * @param {Object} options.flags - Flags for configuration.
31
+ * @param {boolean} [options.flags.silenceConsole=false] - Flag to silence the console during tests.
32
+ * @returns {import('jest').Config} Jest configuration object.
33
+ *
34
+ * @example
35
+ * config({
36
+ * // matches tests/GlobalHeader.keyboard.test.js
37
+ * relativePathAfterTestsFolder: 'GlobalHeader.keyboard.test.js',
38
+ * // overrides the default configuration for jest config 'verbose' to true
39
+ * firstLevelSpread: { verbose: true },
40
+ * // silences the console during tests via custom setup file
41
+ * flags: { silenceConsole: true }
42
+ * });
43
+ *
44
+ * @example
45
+ * // matches tests/GlobalHeader/a11y/test.keys.js
46
+ * config({
47
+ * relativePathAfterTestsFolder: 'GlobalHeader/a11y/test.keys.js',
48
+ * flags: { silenceConsole: true }
49
+ * });
50
+ */
51
+ export const config = ({ relativePathAfterTestsFolder = undefined, firstLevelSpread = {}, flags = {} } = {}) => {
52
+ const silenceConsole = flags.silenceConsole ?? process.env.JEST_FORCE_SILENT_CONSOLE ?? false;
53
+
54
+ /** @type {import('jest').Config} */
55
+ return {
56
+ ...jestConfig,
57
+ collectCoverage: false,
58
+ collectCoverageFrom: [],
59
+ coverageDirectory: undefined,
60
+ coverageReporters: undefined,
61
+ // testRegex: 'tests/.*\\.test\\.[jt]sx?$',
62
+ testRegex: relativePathAfterTestsFolder
63
+ ? `.*/tests/${relativePathAfterTestsFolder}$`
64
+ : 'tests/.*\\.test\\.[jt]sx?$',
65
+ testTimeout: 120000,
66
+ setupFilesAfterEnv: [...jestConfig.setupFilesAfterEnv, ...getSetupFilesAfterEnvBasedOnFlags({ silenceConsole })],
67
+ ...firstLevelSpread,
68
+ };
69
+ };
14
70
  export default config;
@@ -0,0 +1 @@
1
+ global.console = { jestLog: console.log, error: jest.fn(), warn: jest.fn(), log: jest.fn() };
package/package.json CHANGED
@@ -1,11 +1,17 @@
1
1
  {
2
2
  "name": "@elliemae/ds-monorepo-devops",
3
- "version": "3.50.1-next.9",
3
+ "version": "3.51.0-next.0",
4
4
  "license": "MIT",
5
5
  "description": "ICE MT - Dimsum - Monorepo Devops",
6
+ "type": "module",
6
7
  "files": [
8
+ "bin",
7
9
  "configs"
8
10
  ],
11
+ "bin": {
12
+ "@elliemae/ds-monorepo-devops": "./bin/ds-monorepo-devops.mjs",
13
+ "ds-monorepo-devops": "./bin/ds-monorepo-devops.mjs"
14
+ },
9
15
  "exports": {
10
16
  "./configs/jest.config": {
11
17
  "import": "./configs/jest.config.mjs",
@@ -29,7 +35,11 @@
29
35
  "indent": 4
30
36
  },
31
37
  "peerDependencies": {
32
- "@elliemae/pui-cli": "9.0.0-next.31",
38
+ "@elliemae/pui-cli": "9.0.0-next.50",
39
+ "arg": "~5.0.2",
40
+ "glob": "~10.2.5",
41
+ "ignore": "^5.3.0",
42
+ "inquirer": "~12.0.0",
33
43
  "jest": "~29.7.0"
34
44
  },
35
45
  "publishConfig": {