UNPKG

@sap/cds-dk

Version:

Command line client and development toolkit for the SAP Cloud Application Programming Model

159 lines (142 loc) 5.37 kB
const { write, exists } = require('../cds').utils const cds = require('../cds') const { readJSONC } = require('../util/fs') const path = require('node:path') const term = require('../util/term') const { pathToFileURL } = require('node:url') const { COMMAND_INIT } = require('../init/constants') const installationHint = (logger, configFile, importStatement) => logger.log( `${term.warn( `\n\nPlease add the following to your '${configFile}':` + '\n\n 1. At the top of your file, import the following:')}` + `\n\n ${term.bold(importStatement)}` + `${term.warn( '\n\n 2. In your export, add the following to the front of the array:')}` + `\n\n ${term.bold('cdsPlugin.configs.recommended')}` ) module.exports = { /** * Reads ESLint config contents from file * @param {import('fs').PathLike} configPath config file path to read from * @returns {Promise<object>} config file contents */ async readEslintConfig(configPath) { let config switch (path.basename(configPath)) { case 'eslint.config.mjs': // pathToFileURL is used to convert the path to a file URL on Windows try { config = (await import (pathToFileURL(configPath))).default } catch { config = null } break case 'eslint.config.js': case 'eslint.config.cjs': try { config = require (configPath) } catch { config = null } } return config }, /** * Checks ESLint config file contents for locally installed * plugin with: * (1) All CDS recommended rules 'on' * (2) Add's custom rule example 'no-entity-moo' if requested * @param {object | string} configIn - ESLint config file or path * @param {import('console').Console} logger - logger to use * @returns {Promise<object>} ESLint config contents (also writes to file if path provided) */ async sanitizeEslintConfig(configIn, logger = console) { let configContents const isFilePath = typeof configIn === 'string' if (isFilePath) { configContents = await this.readEslintConfig(configIn) } configContents ??= { ...configIn } if (isFilePath) { await this.writeEslintConfig(configIn, cds.cli?.command === COMMAND_INIT, logger) } return configContents }, /** * Suggest ESLint config contents to file * @param {import('node:fs').PathLike} configPath config file path to write to * @param {boolean} force whether to overwrite existing config file or not * @param {import('console').Console} logger logger to use for output * @returns {Promise<void>} */ async writeEslintConfig(configPath, force = false, logger = console) { let configFile = path.basename(configPath) switch (configFile) { case 'eslint.config.js': case 'eslint.config.cjs': if (!force && exists(configPath)) { installationHint(logger, configFile, 'const cdsPlugin = require(\'@sap/eslint-plugin-cds\')') } else { await write(configPath, ` const cds = require('@sap/eslint-plugin-cds') module.exports = [...cds.recommended, cdsPlugin.configs.recommended] `) } logger.log(term.warn('\nMake sure to also run npm i to install the newly added dependencies.')) break case 'eslint.config.mjs': if (!force && exists(configPath)) { installationHint(logger, configFile, 'import cdsPlugin from \'@sap/eslint-plugin-cds\'') } else { await write(configPath, ` import cds from '@sap/cds/eslint.config.mjs' import cdsPlugin from '@sap/eslint-plugin-cds' export default [...cds.recommended, cdsPlugin.configs.recommended] `) } logger.log(term.warn('\nMake sure to also run npm i to install the newly added dependencies.')) break } }, /** * Read VS Code settings from file * @param {*} settingsPath settings file path to read from * @returns settings file contents */ async readVscodeSettings(settingsPath) { let settings if (exists(settingsPath)) { try { settings = await readJSONC(settingsPath) } catch { settings = {} } } return settings }, /** * Merges two arrays into one * @param {*} array input array * @param {*} arrayToMerge array to merge with * @returns merged array (without duplicates) */ mergeArrays(array, arrayToMerge) { let arrayMerged = array.concat(arrayToMerge) if (typeof array === 'string') { array = [array] } if (typeof arrayToMerge === 'string') { arrayToMerge = [arrayToMerge] } arrayMerged = [...new Set([...array, ...arrayToMerge])] return arrayMerged }, /** * Add VS Code ESLint extension settings required for CDS linting: * (1) Extension file types: [cds, csn] * (2) 'Custom' case adds rulePaths and removes configFile * (3) 'Global' case adds configFile and removes rulePaths * @param {*} settingsPath VS Code settings file * @param {*} lintFileTypes array of file types to add to eslint.validate setting * @returns void */ async sanitizeVscodeSettings(settingsPath, lintFileTypes) { const settings = (await this.readVscodeSettings(settingsPath)) ?? {} settings['eslint.validate'] = settings['eslint.validate'] ? this.mergeArrays(settings['eslint.validate'], lintFileTypes) : lintFileTypes await write(settingsPath, settings, { spaces: 2 }) } }