@sap-ux/app-config-writer 0.6.133 → 0.6.135

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.
@@ -13,6 +13,11 @@ export type EslintRcJson = {
13
13
  * Either a string that represents a single configuration or an array of strings that represents multiple configurations.
14
14
  */
15
15
  extends?: string | string[];
16
+ /**
17
+ * Glob patterns indicating the files the configuration applies to.
18
+ * Not a standard legacy eslintrc property, but some configs include it and `@eslint/migrate-config` preserves it.
19
+ */
20
+ files?: string | string[];
16
21
  };
17
22
  /**
18
23
  * Converts an eslint config to flat config format (eslint version 9).
@@ -18,6 +18,20 @@ const packageName = {
18
18
  ESLINT_PLUGIN_FIORI_TOOLS: '@sap-ux/eslint-plugin-fiori-tools',
19
19
  ESLINT_PLUGIN_FIORI_CUSTOM: 'eslint-plugin-fiori-custom'
20
20
  };
21
+ /**
22
+ * Extends entries that have a direct native ESLint 9 flat config equivalent and are also
23
+ * spread natively inside `@sap-ux/eslint-plugin-fiori-tools`. These must be stripped from
24
+ * the legacy config before migration to avoid the FlatCompat compat shim producing a different
25
+ * rule source identity than the native registration inside the fiori-tools plugin, which would
26
+ * cause ESLint to throw a rule source conflict error (e.g. "sources mismatch for no-irregular-whitespace").
27
+ */
28
+ const NATIVE_FLAT_CONFIG_EXTENDS = ['eslint:recommended'];
29
+ /**
30
+ * Legacy `plugin:@typescript-eslint/*` extends entries that are stripped before migration
31
+ * to prevent FlatCompat from wrapping them, which would cause rule source conflicts with
32
+ * the native registrations inside `@sap-ux/eslint-plugin-fiori-tools`.
33
+ */
34
+ const TYPESCRIPT_ESLINT_EXTENDS_PREFIX = 'plugin:@typescript-eslint/';
21
35
  const MIGRATION_ERROR_TEXT = `Migration to eslint version 9 failed. Check if there are error messages above. You can also delete the existing eslint \`devDependency\` and run \`create add eslint\` to create a eslint.config.mjs file with the flat config where you can transfer your old eslint config manually.\` For more information, see [https://eslint.org/docs/latest/use/migrate-to-9.0.0#flat-config](Migrate to v9.x).`;
22
36
  /**
23
37
  * Converts an eslint config to flat config format (eslint version 9).
@@ -39,8 +53,8 @@ async function convertEslintConfig(basePath, options) {
39
53
  if (!(await checkPrerequisites(basePath, fs, logger))) {
40
54
  throw new Error('The prerequisites are not met. For more information, see the log messages above.');
41
55
  }
42
- await removeFioriToolsFromExistingConfig(basePath, fs, logger);
43
- await runMigrationCommand(basePath, fs);
56
+ const strippedConfig = await removeFioriToolsFromExistingConfig(basePath, fs, logger);
57
+ await runMigrationCommand(basePath, fs, strippedConfig);
44
58
  await injectFioriToolsIntoMigratedConfig(basePath, fs, options.config, logger);
45
59
  await updatePackageJson(basePath, fs, logger);
46
60
  return fs;
@@ -79,12 +93,89 @@ async function checkPrerequisites(basePath, fs, logger) {
79
93
  return true;
80
94
  }
81
95
  /**
82
- * Removes all traces of the SAP Fiori tools plugin from the existing legacy eslint configuration,
83
- * so that the migration tool does not attempt to translate it and produce broken output.
96
+ * Strips `eslint:recommended`, `plugin:@typescript-eslint/*`, and Fiori Tools plugin entries
97
+ * from the `extends` field of a legacy eslint config object (mutates in place).
98
+ * Other extends entries (e.g. third-party plugins) are left untouched for `@eslint/migrate-config`.
99
+ *
100
+ * @param eslintConfig - the legacy eslint config object to modify
101
+ * @returns flags indicating which known entries were stripped (used to warn when a `files` scope is dropped)
102
+ */
103
+ function stripNativeExtendsFromConfig(eslintConfig) {
104
+ const extendsArray = typeof eslintConfig.extends === 'string' ? [eslintConfig.extends] : (eslintConfig.extends ?? []);
105
+ let eslintRecommended = false;
106
+ let tsStripped = false;
107
+ const remaining = [];
108
+ for (const ext of extendsArray) {
109
+ if (ext.includes(packageName.ESLINT_PLUGIN_FIORI_TOOLS)) {
110
+ // drop — covered by @sap-ux/eslint-plugin-fiori-tools
111
+ }
112
+ else if (ext.startsWith(TYPESCRIPT_ESLINT_EXTENDS_PREFIX)) {
113
+ tsStripped = true;
114
+ }
115
+ else if (NATIVE_FLAT_CONFIG_EXTENDS.includes(ext)) {
116
+ eslintRecommended = true;
117
+ }
118
+ else {
119
+ remaining.push(ext);
120
+ }
121
+ }
122
+ if (extendsArray.length > 0) {
123
+ if (remaining.length === 0) {
124
+ delete eslintConfig.extends;
125
+ }
126
+ else if (typeof eslintConfig.extends === 'string') {
127
+ eslintConfig.extends = remaining[0];
128
+ }
129
+ else {
130
+ eslintConfig.extends = remaining;
131
+ }
132
+ }
133
+ return { eslintRecommended, tsStripped };
134
+ }
135
+ /**
136
+ * Logs a warning when native extends entries were stripped from the legacy config,
137
+ * and additionally notes when a `files` scope cannot be automatically preserved.
138
+ *
139
+ * @param files - the `files` property from the legacy config, if any
140
+ * @param eslintRecommended - whether `eslint:recommended` was stripped
141
+ * @param tsStripped - whether any `plugin:@typescript-eslint/*` entries were stripped
142
+ * @param logger - logger to report info to the user
143
+ */
144
+ function warnIfFileScopeDropped(files, eslintRecommended, tsStripped, logger) {
145
+ if (!eslintRecommended && !tsStripped) {
146
+ return;
147
+ }
148
+ const removed = [];
149
+ if (eslintRecommended) {
150
+ removed.push("'eslint:recommended'");
151
+ }
152
+ if (tsStripped) {
153
+ removed.push("'plugin:@typescript-eslint/*'");
154
+ }
155
+ const baseMessage = `${removed.join(' and ')} ${removed.length > 1 ? 'were' : 'was'} removed from the legacy config and will not be re-injected. Its rules are already covered by '@sap-ux/eslint-plugin-fiori-tools', so no manual re-addition is needed.`;
156
+ const fileScopeMessage = files
157
+ ? ` The legacy config had a 'files' scope (${JSON.stringify(files)}) that cannot be automatically preserved.`
158
+ : '';
159
+ logger?.warn(baseMessage + fileScopeMessage);
160
+ }
161
+ /**
162
+ * Removes all traces of the SAP Fiori tools plugin
163
+ * (e.g. `eslint:recommended`, `plugin:@typescript-eslint/recommended`) from the existing legacy
164
+ * eslint configuration, so that the migration tool does not wrap them in a FlatCompat compat shim
165
+ * that would conflict with the native rule registrations inside `@sap-ux/eslint-plugin-fiori-tools`.
166
+ *
167
+ * If the legacy config had a `files` property together with `eslint:recommended` or
168
+ * `plugin:@typescript-eslint/*` entries, a warning is logged because that file scope cannot be
169
+ * automatically preserved — the converted project uses `@sap-ux/eslint-plugin-fiori-tools` which
170
+ * already applies the equivalent rules scoped to the webapp directory.
171
+ *
172
+ * The modified config is returned as a serialized JSON string and is not written back to
173
+ * mem-fs, so the original legacy config file is never staged for a disk write.
84
174
  *
85
175
  * @param basePath - base path to be used for the conversion
86
176
  * @param fs - file system reference
87
177
  * @param logger - logger to report info to the user
178
+ * @returns the stripped config serialized as a JSON string, ready to be passed to the migration command
88
179
  * @throws {Error} if the existing .eslintrc.json file is not a valid JSON object
89
180
  */
90
181
  async function removeFioriToolsFromExistingConfig(basePath, fs, logger) {
@@ -102,27 +193,17 @@ async function removeFioriToolsFromExistingConfig(basePath, fs, logger) {
102
193
  delete eslintConfig.plugins;
103
194
  }
104
195
  }
105
- // Remove fiori-tools entries from extends
106
- if (typeof eslintConfig.extends === 'string') {
107
- if (eslintConfig.extends.includes(packageName.ESLINT_PLUGIN_FIORI_TOOLS)) {
108
- delete eslintConfig.extends;
109
- }
110
- }
111
- else if (Array.isArray(eslintConfig.extends)) {
112
- eslintConfig.extends = eslintConfig.extends.filter((ext) => !ext.includes(packageName.ESLINT_PLUGIN_FIORI_TOOLS));
113
- if (eslintConfig.extends.length === 0) {
114
- delete eslintConfig.extends;
115
- }
116
- }
117
- fs.writeJSON(configPath, eslintConfig);
196
+ const { eslintRecommended, tsStripped } = stripNativeExtendsFromConfig(eslintConfig);
197
+ warnIfFileScopeDropped(eslintConfig.files, eslintRecommended, tsStripped, logger);
118
198
  logger?.debug(`Removed SAP Fiori tools plugin references from ${configPath}`);
199
+ return JSON.stringify(eslintConfig, null, 2);
119
200
  }
120
201
  /**
121
202
  * Injects the SAP Fiori tools plugin import and config spread into the migrated flat-config file.
122
203
  *
123
204
  * After the migration tool produces `eslint.config.mjs`, this function:
124
205
  * 1. Prepends `import fioriTools from '@sap-ux/eslint-plugin-fiori-tools';` to the imports section.
125
- * 2. Inserts `...fioriTools.configs.recommended` (or the requested config variant) as the last
206
+ * 2. Inserts `...fioriTools.configs['recommended']` (or the requested config variant) as the last
126
207
  * element of the exported config array, right before the closing `]);`.
127
208
  *
128
209
  * @param basePath - base path of the project
@@ -141,12 +222,10 @@ async function injectFioriToolsIntoMigratedConfig(basePath, fs, config = 'recomm
141
222
  if (lastBracketIndex === -1) {
142
223
  throw new Error('Unexpected format of migrated eslint config. Could not inject the SAP Fiori tools plugin configuration.');
143
224
  }
144
- else {
145
- content =
146
- content.slice(0, lastBracketIndex) +
147
- `,\n ...fioriTools.configs['${config}'],\n` +
148
- content.slice(lastBracketIndex);
149
- }
225
+ content =
226
+ content.slice(0, lastBracketIndex) +
227
+ `,\n ...fioriTools.configs['${config}'],\n` +
228
+ content.slice(lastBracketIndex);
150
229
  fs.write(migratedConfigPath, content);
151
230
  logger?.debug(`Injected SAP Fiori tools plugin into ${migratedConfigPath}`);
152
231
  }
@@ -156,19 +235,17 @@ async function injectFioriToolsIntoMigratedConfig(basePath, fs, config = 'recomm
156
235
  *
157
236
  * @param basePath - base path to be used for the conversion
158
237
  * @param fs - file system reference
238
+ * @param strippedConfigContent - the stripped legacy eslint config content as a JSON string
159
239
  * @returns a promise that resolves when the migration command finishes successfully, or rejects if the command fails
160
240
  */
161
- async function runMigrationCommand(basePath, fs) {
241
+ async function runMigrationCommand(basePath, fs, strippedConfigContent) {
162
242
  const tempDir = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'eslint-migration-'));
163
243
  try {
164
244
  // 1. Copy necessary files to temp directory
165
245
  const eslintrcJsonPath = (0, node_path_1.join)(basePath, '.eslintrc.json');
166
- const eslintrcPath = (0, node_path_1.join)(basePath, '.eslintrc');
167
- const configPath = fs.exists(eslintrcJsonPath) ? eslintrcJsonPath : eslintrcPath;
168
246
  const configFileName = fs.exists(eslintrcJsonPath) ? '.eslintrc.json' : '.eslintrc';
169
- // Read from mem-fs (which has the modified content) and write to temp directory
170
- const eslintrcContent = fs.read(configPath);
171
- (0, node_fs_1.writeFileSync)((0, node_path_1.join)(tempDir, configFileName), eslintrcContent, 'utf-8');
247
+ // Write the already-stripped config content (never staged in mem-fs) to temp directory
248
+ (0, node_fs_1.writeFileSync)((0, node_path_1.join)(tempDir, configFileName), strippedConfigContent, 'utf-8');
172
249
  const eslintignorePath = (0, node_path_1.join)(basePath, '.eslintignore');
173
250
  if ((0, node_fs_1.existsSync)(eslintignorePath)) {
174
251
  (0, node_fs_1.writeFileSync)((0, node_path_1.join)(tempDir, '.eslintignore'), (0, node_fs_1.readFileSync)(eslintignorePath, 'utf-8'), 'utf-8');
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@sap-ux/app-config-writer",
3
3
  "description": "Add or update configuration for SAP Fiori tools application",
4
- "version": "0.6.133",
4
+ "version": "0.6.135",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "https://github.com/SAP/open-ux-tools.git",
@@ -28,13 +28,13 @@
28
28
  "prompts": "2.4.2",
29
29
  "semver": "7.7.4",
30
30
  "cross-spawn": "7.0.6",
31
- "@sap-ux/axios-extension": "1.25.29",
32
- "@sap-ux/ui5-application-writer": "1.8.4",
33
- "@sap-ux/btp-utils": "1.1.12",
31
+ "@sap-ux/axios-extension": "1.25.30",
32
+ "@sap-ux/ui5-application-writer": "1.8.5",
33
+ "@sap-ux/btp-utils": "1.1.13",
34
34
  "@sap-ux/logger": "0.8.5",
35
- "@sap-ux/project-access": "1.35.19",
35
+ "@sap-ux/project-access": "1.35.20",
36
36
  "@sap-ux/store": "1.5.13",
37
- "@sap-ux/ui5-config": "0.30.2"
37
+ "@sap-ux/ui5-config": "0.30.3"
38
38
  },
39
39
  "devDependencies": {
40
40
  "@types/ejs": "3.1.5",
@@ -43,9 +43,9 @@
43
43
  "@types/prompts": "2.4.9",
44
44
  "@types/semver": "7.7.1",
45
45
  "@types/cross-spawn": "6.0.6",
46
- "axios": "1.13.6",
46
+ "axios": "1.15.0",
47
47
  "nock": "14.0.11",
48
- "@sap-ux/preview-middleware": "0.25.19"
48
+ "@sap-ux/preview-middleware": "0.25.23"
49
49
  },
50
50
  "engines": {
51
51
  "node": ">=20.x"