UNPKG

eslint-plugin-sql

Version:
233 lines (232 loc) 9.5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.rule = void 0; const createRule_1 = require("../factories/createRule"); const dropBaseIndent_1 = require("../utilities/dropBaseIndent"); const isSqlQuery_1 = require("../utilities/isSqlQuery"); const utils_1 = require("@typescript-eslint/utils"); const sql_formatter_1 = require("sql-formatter"); const padIndent = (subject, spaces) => { return subject .split('\n') .map((line) => { return line.length > 0 ? ' '.repeat(spaces) + line : line; }) .join('\n'); }; const findFirstMeaningfulIndent = (subject) => { for (const line of subject.split('\n')) { if (line.trim().length > 0) { return line.search(/\S/u); } } return 0; }; exports.rule = (0, createRule_1.createRule)({ create: (context) => { var _a, _b, _c, _d, _e, _f; // @ts-expect-error I am ont clear how to type this const placeholderRule = (_b = (_a = context.settings) === null || _a === void 0 ? void 0 : _a.sql) === null || _b === void 0 ? void 0 : _b.placeholderRule; const pluginOptions = ((_c = context.options) === null || _c === void 0 ? void 0 : _c[0]) || { ignoreExpressions: false, ignoreInline: true, ignoreStartWithNewLine: true, ignoreTagless: true, retainBaseIndent: true, sqlTag: 'sql', }; const { ignoreExpressions, ignoreInline, ignoreStartWithNewLine, ignoreTagless, retainBaseIndent, sqlTag, } = pluginOptions; const tabWidth = (_f = (_e = (_d = context.options) === null || _d === void 0 ? void 0 : _d[1]) === null || _e === void 0 ? void 0 : _e.tabWidth) !== null && _f !== void 0 ? _f : 2; return { TemplateLiteral(node) { var _a, _b, _c, _d, _e, _f, _g, _h; const tagName = // @ts-expect-error TODO (_e = (_b = (_a = node.parent.tag) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : // @ts-expect-error TODO (_d = (_c = node.parent.tag) === null || _c === void 0 ? void 0 : _c.object) === null || _d === void 0 ? void 0 : _d.name) !== null && _e !== void 0 ? _e : // @ts-expect-error TODO (_h = (_g = (_f = node.parent.tag) === null || _f === void 0 ? void 0 : _f.callee) === null || _g === void 0 ? void 0 : _g.object) === null || _h === void 0 ? void 0 : _h.name; const sqlTagIsPresent = tagName === sqlTag; if (ignoreTagless && !sqlTagIsPresent) { return; } if (ignoreExpressions && node.quasis.length !== 1) { return; } const templateElement = node.quasis.find((quasi) => { return quasi.type === utils_1.AST_NODE_TYPES.TemplateElement; }); if (!templateElement) { return; } let indentAnchorOffset = findFirstMeaningfulIndent(templateElement.value.raw); if (templateElement.value.raw.search(/\S/u) === -1) { const lines = templateElement.value.raw.split('\n'); const lastLine = lines[lines.length - 1]; if (lastLine) { indentAnchorOffset = lastLine.length; } else { indentAnchorOffset = 0; } } else if (templateElement.value.raw.search(/\S/u) === 0) { indentAnchorOffset = tabWidth; } const magic = '"gajus-eslint-plugin-sql"'; const literal = node.quasis .map((quasi) => { return quasi.value.raw; }) .join(magic); if (!sqlTagIsPresent && !(0, isSqlQuery_1.isSqlQuery)(literal, placeholderRule)) { return; } if (ignoreInline && !literal.includes('\n')) { return; } let formatted = (0, sql_formatter_1.format)(literal, { ...context.options[1], tabWidth, }); if (ignoreStartWithNewLine && literal.startsWith('\n') && !formatted.startsWith('\n')) { formatted = '\n' + formatted; } if (formatted.endsWith('\n\n')) { formatted = formatted.replace(/\n\n$/u, '\n'); } if (retainBaseIndent) { formatted = padIndent(formatted, indentAnchorOffset); } else { formatted = (0, dropBaseIndent_1.dropBaseIndent)(literal); } formatted += '\n' + ' '.repeat(Math.max(indentAnchorOffset - tabWidth, 0)); if (formatted !== literal) { context.report({ fix: (fixer) => { let final = formatted; const expressionCount = node.expressions.length; let index = 0; while (index <= expressionCount - 1) { final = final.replace(magic, '${' + context.sourceCode.getText(node.expressions[index]) + '}'); index++; } return fixer.replaceTextRange([ node.quasis[0].range[0], node.quasis[node.quasis.length - 1].range[1], ], '`' + (final.startsWith('\n') ? final : '\n' + final) + '`'); }, messageId: 'format', node, }); } }, }; }, defaultOptions: [ { ignoreExpressions: false, ignoreInline: true, ignoreStartWithNewLine: true, ignoreTagless: true, retainBaseIndent: true, sqlTag: 'sql', }, { tabWidth: 2, }, ], meta: { docs: { description: 'Matches queries in template literals. Warns when query formatting does not match the configured format (see Options).', url: 'https://github.com/gajus/eslint-plugin-sql#eslint-plugin-sql-rules-format', }, fixable: 'code', messages: { format: 'Format the query', }, schema: [ { additionalProperties: false, properties: { ignoreExpressions: { default: false, type: 'boolean', }, ignoreInline: { default: true, type: 'boolean', }, ignoreStartWithNewLine: { default: true, type: 'boolean', }, ignoreTagless: { default: true, type: 'boolean', }, retainBaseIndent: { default: true, type: 'boolean', }, sqlTag: { default: 'sql', type: 'string', }, }, type: 'object', }, { additionalProperties: false, properties: { dataTypeCase: { default: 'preserve', enum: ['lower', 'upper', 'preserve'], type: 'string', }, denseOperators: { default: false, type: 'boolean', }, functionCase: { default: 'preserve', enum: ['lower', 'upper', 'preserve'], type: 'string', }, identifierCase: { default: 'preserve', enum: ['lower', 'upper', 'preserve'], type: 'string', }, keywordCase: { default: 'preserve', enum: ['lower', 'upper', 'preserve'], type: 'string', }, language: { default: 'sql', type: 'string', }, tabWidth: { default: 2, type: 'number', }, useTabs: { default: false, type: 'boolean', }, }, type: 'object', }, ], type: 'suggestion', }, name: 'format', });