@sap-ux/app-config-writer 0.6.132 → 0.6.134
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
|
-
*
|
|
83
|
-
*
|
|
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
|
-
|
|
106
|
-
|
|
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
|
|
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
|
-
|
|
145
|
-
content
|
|
146
|
-
|
|
147
|
-
|
|
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
|
-
//
|
|
170
|
-
|
|
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.
|
|
4
|
+
"version": "0.6.134",
|
|
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/
|
|
32
|
-
"@sap-ux/ui5-application-writer": "1.8.3",
|
|
31
|
+
"@sap-ux/ui5-application-writer": "1.8.4",
|
|
33
32
|
"@sap-ux/btp-utils": "1.1.12",
|
|
34
|
-
"@sap-ux/logger": "0.8.
|
|
35
|
-
"@sap-ux/
|
|
36
|
-
"@sap-ux/
|
|
37
|
-
"@sap-ux/
|
|
33
|
+
"@sap-ux/logger": "0.8.5",
|
|
34
|
+
"@sap-ux/axios-extension": "1.25.29",
|
|
35
|
+
"@sap-ux/project-access": "1.35.19",
|
|
36
|
+
"@sap-ux/store": "1.5.13",
|
|
37
|
+
"@sap-ux/ui5-config": "0.30.2"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@types/ejs": "3.1.5",
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"@types/cross-spawn": "6.0.6",
|
|
46
46
|
"axios": "1.13.6",
|
|
47
47
|
"nock": "14.0.11",
|
|
48
|
-
"@sap-ux/preview-middleware": "0.25.
|
|
48
|
+
"@sap-ux/preview-middleware": "0.25.21"
|
|
49
49
|
},
|
|
50
50
|
"engines": {
|
|
51
51
|
"node": ">=20.x"
|