diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000..46ce99b --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,12 @@ +module.exports = { + extends: ['./node_modules/@balena/lint/config/.eslintrc.js'], + parserOptions: { + project: 'tsconfig.js.json', + sourceType: 'module', + }, + env: { + // TODO: Drop this once we convert all .js tests to .ts + mocha: true, + }, + root: true, +}; diff --git a/package.json b/package.json index 460fdde..79230c2 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ }, "devDependencies": { "@balena/lf-to-abstract-sql": "^5.0.0", - "@balena/lint": "^6.2.2", + "@balena/lint": "^8.0.0", "@balena/odata-parser": "^3.0.0", "@balena/odata-to-abstract-sql": "^6.0.1", "@balena/sbvr-parser": "^1.4.3", diff --git a/src/AbstractSQLCompiler.ts b/src/AbstractSQLCompiler.ts index 4dc3281..46b6e18 100644 --- a/src/AbstractSQLCompiler.ts +++ b/src/AbstractSQLCompiler.ts @@ -1,27 +1,28 @@ export const enum Engines { + /* eslint-disable @typescript-eslint/no-shadow -- this is fine since we only assign plain string values to the enum items */ postgres = 'postgres', mysql = 'mysql', websql = 'websql', + /* eslint-enable @typescript-eslint/no-shadow */ } import { AbstractSQLOptimiser } from './AbstractSQLOptimiser'; -import { - AbstractSQLRules2SQL, - Binding, - SqlResult, -} from './AbstractSQLRules2SQL'; +import type { Binding, SqlResult } from './AbstractSQLRules2SQL'; +import { AbstractSQLRules2SQL } from './AbstractSQLRules2SQL'; export { Binding, SqlResult } from './AbstractSQLRules2SQL'; import type { SbvrType } from '@balena/sbvr-types'; import sbvrTypes from '@balena/sbvr-types'; import * as _ from 'lodash'; import { optimizeSchema, generateRuleSlug } from './AbstractSQLSchemaOptimiser'; +import type { + ReferencedFields, + RuleReferencedFields, + ModifiedFields, +} from './referenced-fields'; import { getReferencedFields, getRuleReferencedFields, getModifiedFields, - ReferencedFields, - RuleReferencedFields, - ModifiedFields, insertAffectedIdsBinds, } from './referenced-fields'; @@ -328,7 +329,7 @@ export type SelectQueryStatementNode = export type SelectQueryNode = ['SelectQuery', ...SelectQueryStatementNode[]]; export type UnionQueryNode = [ 'UnionQuery', - // tslint:disable-next-line:array-type typescript fails on a circular reference when `Array` form + // eslint-disable-next-line @typescript-eslint/array-type -- Typescript fails on a circular reference when prettier changes this to an `Array` form ...(UnionQueryNode | SelectQueryNode)[], ]; export type InsertQueryNode = [ @@ -987,7 +988,7 @@ CREATE TABLE ${ifNotExistsStr}"${table.name}" ( // Self-dependencies are ok. if ( dependency !== resourceName && - schemaDependencyMap.hasOwnProperty(dependency) + Object.prototype.hasOwnProperty.call(schemaDependencyMap, dependency) ) { unsolvedDependency = true; break; diff --git a/src/AbstractSQLOptimiser.ts b/src/AbstractSQLOptimiser.ts index f32058d..d51387b 100644 --- a/src/AbstractSQLOptimiser.ts +++ b/src/AbstractSQLOptimiser.ts @@ -1,7 +1,7 @@ import * as _ from 'lodash'; -import { Dictionary } from 'lodash'; -import { +import type { Dictionary } from 'lodash'; +import type { AbstractSqlQuery, AbstractSqlType, AddDateDurationNode, @@ -424,7 +424,7 @@ const Value = (arg: string | AbstractSqlQuery): ValuesNodeTypes => { switch (arg) { case 'Default': return arg; - default: + default: { const [type, ...rest] = arg; switch (type) { case 'Null': @@ -445,6 +445,7 @@ const Value = (arg: string | AbstractSqlQuery): ValuesNodeTypes => { default: throw new SyntaxError(`Invalid type for Value ${type}`); } + } } }; @@ -501,6 +502,7 @@ const JoinMatch = const ruleBody = BooleanValue(getAbstractSqlQuery(rest, 0)); return [joinType, from, ['On', ruleBody]] as unknown as T; } + // eslint-disable-next-line no-fallthrough default: throw new SyntaxError( `'${joinType}' clause does not support '${type}' clause`, @@ -706,9 +708,11 @@ const typeRules = { _.identity, ), Cast: matchArgs('Cast', AnyValue, _.identity), + // eslint-disable-next-line id-denylist Number: NumberMatch('Number'), Real: NumberMatch('Real'), Integer: NumberMatch('Integer'), + // eslint-disable-next-line id-denylist Boolean: matchArgs('Boolean', _.identity), EmbeddedText: matchArgs('EmbeddedText', _.identity), Null: matchArgs('Null'), @@ -916,11 +920,12 @@ const typeRules = { } const [type, ...rest] = arg; switch (type) { - case 'When': + case 'When': { checkArgs('When', rest, 2); const matches = BooleanValue(getAbstractSqlQuery(rest, 0)); const resultValue = AnyValue(getAbstractSqlQuery(rest, 1)); return ['When', matches, resultValue]; + } case 'Else': if (index !== args.length - 1) { throw new SyntaxError('Else must be the last element of a Case'); @@ -1346,7 +1351,7 @@ const typeRules = { checkMinArgs('Update fields', rest, 1); fields = [arg as FieldsNode]; break; - case 'Values': + case 'Values': { if (values.length !== 0) { throw new SyntaxError( `'InsertQuery' can only accept one '${type}'`, @@ -1372,6 +1377,7 @@ const typeRules = { } } break; + } case 'From': tables.push(typeRules[type](rest)); break; @@ -1425,7 +1431,7 @@ const typeRules = { checkMinArgs('Update fields', rest, 1); fields = [arg as FieldsNode]; break; - case 'Values': + case 'Values': { if (values.length !== 0) { throw new SyntaxError( `'UpdateQuery' can only accept one '${type}'`, @@ -1436,6 +1442,7 @@ const typeRules = { checkMinArgs('Update values array', valuesArray, 1); values = [['Values', valuesArray.map(Value)]]; break; + } case 'From': tables.push(typeRules[type](rest)); break; @@ -1596,7 +1603,7 @@ export const AbstractSQLOptimiser = ( case 'DeleteQuery': abstractSQL = typeRules[type](rest); break; - case 'UpsertQuery': + case 'UpsertQuery': { checkArgs('UpsertQuery', rest, 2); const insertQuery = getAbstractSqlQuery(rest, 0); const updateQuery = getAbstractSqlQuery(rest, 1); @@ -1614,6 +1621,7 @@ export const AbstractSQLOptimiser = ( typeRules.UpdateQuery(updateQuery.slice(1)), ]; break; + } default: abstractSQL = AnyValue(abstractSQL) as AbstractSqlQuery; } diff --git a/src/AbstractSQLRules2SQL.ts b/src/AbstractSQLRules2SQL.ts index 4fd4fd0..5e8aa90 100644 --- a/src/AbstractSQLRules2SQL.ts +++ b/src/AbstractSQLRules2SQL.ts @@ -2,11 +2,10 @@ import * as _ from 'lodash'; import sbvrTypes from '@balena/sbvr-types'; -import { Dictionary } from 'lodash'; -import { +import type { Dictionary } from 'lodash'; +import type { AbstractSqlQuery, AbstractSqlType, - Engines, InsertQueryNode, SelectQueryNode, UnionQueryNode, @@ -23,6 +22,7 @@ import { StrictTextArrayTypeNodes, StrictJSONTypeNodes, } from './AbstractSQLCompiler'; +import { Engines } from './AbstractSQLCompiler'; export type Binding = | [string, any] @@ -90,10 +90,11 @@ const UnknownValue: MetaMatchFn = (args, indent) => { case 'TextArray': return typeRules[type](rest, indent); case 'SelectQuery': - case 'UnionQuery': + case 'UnionQuery': { const nestedIndent = NestedIndent(indent); const query = typeRules[type](rest, nestedIndent); return '(' + nestedIndent + query + indent + ')'; + } default: throw new Error(`Invalid "UnknownValue" type: ${type}`); } @@ -361,13 +362,14 @@ const JoinMatch = (joinType: string): MatchFn => { } const [type, ...rest] = getAbstractSqlQuery(args, 1); switch (type) { - case 'On': + case 'On': { checkArgs('On', rest, 1); const ruleBody = BooleanValue( getAbstractSqlQuery(rest, 0), NestedIndent(indent), ); return sqlJoinType + from + ' ON ' + ruleBody; + } default: throw new SyntaxError( `'${joinType}' clause does not support '${type}' clause`, @@ -553,7 +555,7 @@ const Value = (arg: any, indent: string): string => { switch (arg) { case 'Default': return 'DEFAULT'; - default: + default: { const [type, ...rest] = arg; switch (type) { case 'Null': @@ -568,6 +570,7 @@ const Value = (arg: any, indent: string): string => { default: throw new SyntaxError(`Invalid type for Value ${type}`); } + } } }; @@ -584,17 +587,19 @@ const FromMatch: MetaMatchFn = (args, indent) => { const [type, ...rest] = args; switch (type) { case 'SelectQuery': - case 'UnionQuery': + case 'UnionQuery': { const nestedindent = NestedIndent(indent); const query = typeRules[type](rest, nestedindent); return '(' + nestedindent + query + indent + ')'; - case 'Table': + } + case 'Table': { checkArgs('Table', rest, 1); const [table] = rest; if (typeof table !== 'string') { throw new SyntaxError('`Table` table must be a string'); } return escapeField(table); + } default: throw new SyntaxError(`From does not support ${type}`); } @@ -607,10 +612,11 @@ const MaybeAlias = ( ): string => { const [type, ...rest] = args; switch (type) { - case 'Alias': + case 'Alias': { checkArgs('Alias', rest, 2); const field = matchFn(getAbstractSqlQuery(rest, 0), indent); return `${field} AS "${rest[1]}"`; + } default: return matchFn(args, indent); } @@ -879,9 +885,11 @@ const typeRules: Dictionary = { } return `CAST(${value} AS ${type})`; }, + // eslint-disable-next-line id-denylist Number: NumberMatch('Number'), Real: NumberMatch('Real'), Integer: NumberMatch('Integer'), + // eslint-disable-next-line id-denylist Boolean: (args) => { checkArgs('Boolean', args, 1); const b = args[0]; @@ -1194,7 +1202,7 @@ const typeRules: Dictionary = { } const [type, ...rest] = arg; switch (type) { - case 'When': + case 'When': { checkArgs('When', rest, 2); const matches = BooleanValue( getAbstractSqlQuery(rest, 0), @@ -1205,6 +1213,7 @@ const typeRules: Dictionary = { nestedIndent, ); return 'WHEN ' + matches + ' THEN ' + resultValue; + } case 'Else': if (index !== args.length - 1) { throw new SyntaxError('Else must be the last element of a Case'); @@ -1309,10 +1318,11 @@ const typeRules: Dictionary = { const [type, ...rest] = arg; switch (type) { case 'SelectQuery': - case 'UnionQuery': + case 'UnionQuery': { const nestedIndent = NestedIndent(indent); const query = typeRules[type](rest, nestedIndent); return 'EXISTS (' + nestedIndent + query + indent + ')'; + } default: return AnyValue(arg, indent) + ' IS NOT NULL'; } @@ -1323,10 +1333,11 @@ const typeRules: Dictionary = { const [type, ...rest] = arg; switch (type) { case 'SelectQuery': - case 'UnionQuery': + case 'UnionQuery': { const nestedIndent = NestedIndent(indent); const query = typeRules[type](rest, nestedIndent); return 'NOT EXISTS (' + nestedIndent + query + indent + ')'; + } default: return AnyValue(arg, indent) + ' IS NULL'; } @@ -1382,7 +1393,7 @@ const typeRules: Dictionary = { checkMinArgs('Update fields', rest, 1); fields = getAbstractSqlQuery(rest, 0).map(escapeField); break; - case 'Values': + case 'Values': { if (values.length !== 0) { throw new SyntaxError( `'InsertQuery' can only accept one '${type}'`, @@ -1401,6 +1412,7 @@ const typeRules: Dictionary = { } } break; + } case 'From': tables.push(typeRules[type](rest, indent)); break; @@ -1451,7 +1463,7 @@ const typeRules: Dictionary = { checkMinArgs('Update fields', rest, 1); fields = getAbstractSqlQuery(rest, 0).map(escapeField); break; - case 'Values': + case 'Values': { if (values.length !== 0) { throw new SyntaxError( `'UpdateQuery' can only accept one '${type}'`, @@ -1462,6 +1474,7 @@ const typeRules: Dictionary = { checkMinArgs('Update values array', valuesArray, 1); values = valuesArray.map((v) => Value(v, indent)); break; + } case 'From': tables.push(typeRules[type](rest, indent)); break; @@ -1604,10 +1617,11 @@ export function AbstractSQLRules2SQL( case 'UnionQuery': case 'InsertQuery': case 'UpdateQuery': - case 'DeleteQuery': + case 'DeleteQuery': { const query = typeRules[type](rest, indent); return toSqlResult(query); - case 'UpsertQuery': + } + case 'UpsertQuery': { checkArgs('UpsertQuery', rest, 2); const insertQuery = getAbstractSqlQuery(rest, 0); const updateQuery = getAbstractSqlQuery(rest, 1); @@ -1627,7 +1641,8 @@ export function AbstractSQLRules2SQL( const updateSql = typeRules.UpdateQuery(updateQuery.slice(1), indent); const update = toSqlResult(updateSql); return [insert, update] as [string, string] | [SqlResult, SqlResult]; - default: + } + default: { const value = AnyValue(abstractSQL, indent); if (noBinds) { return value; @@ -1636,5 +1651,6 @@ export function AbstractSQLRules2SQL( query: `SELECT ${value} AS "result";`, bindings: fieldOrderings, }; + } } } diff --git a/src/AbstractSQLSchemaOptimiser.ts b/src/AbstractSQLSchemaOptimiser.ts index 192f849..9072128 100644 --- a/src/AbstractSQLSchemaOptimiser.ts +++ b/src/AbstractSQLSchemaOptimiser.ts @@ -8,15 +8,14 @@ import { AbstractSQLOptimiser } from './AbstractSQLOptimiser'; export { Binding, SqlResult } from './AbstractSQLRules2SQL'; import sbvrTypes from '@balena/sbvr-types'; import * as _ from 'lodash'; -import { +import type { AbstractSqlModel, AbstractSqlQuery, AbstractSqlType, BooleanTypeNodes, WhereNode, - isFromNode, - isSelectQueryNode, } from './AbstractSQLCompiler'; +import { isFromNode, isSelectQueryNode } from './AbstractSQLCompiler'; const countFroms = (n: AbstractSqlType[]) => { let count = 0; diff --git a/src/referenced-fields.ts b/src/referenced-fields.ts index 8f4093a..8a2cacb 100644 --- a/src/referenced-fields.ts +++ b/src/referenced-fields.ts @@ -1,5 +1,5 @@ import * as _ from 'lodash'; -import { +import type { AbstractSqlQuery, AbstractSqlType, AddDateDurationNode, @@ -26,14 +26,8 @@ import { HavingNode, InnerJoinNode, InNode, - isAliasNode, IsDistinctFromNode, - isFromNode, IsNotDistinctFromNode, - isSelectNode, - isSelectQueryNode, - isTableNode, - isWhereNode, LeftJoinNode, LessThanNode, LessThanOrEqualNode, @@ -56,6 +50,14 @@ import { UnionQueryNode, WhereNode, } from './AbstractSQLCompiler'; +import { + isAliasNode, + isFromNode, + isSelectNode, + isSelectQueryNode, + isTableNode, + isWhereNode, +} from './AbstractSQLCompiler'; import { AbstractSQLOptimiser } from './AbstractSQLOptimiser'; import { isAbstractSqlQuery } from './AbstractSQLRules2SQL'; @@ -214,7 +216,7 @@ const $getRuleReferencedFields = ( } else if (isSafe === IsSafe.Delete) { isSafe = IsSafe.Insert; } - // Fallthrough + // eslint-disable-next-line no-fallthrough -- Fallthrough case 'Where': case 'And': case 'Exists': @@ -374,7 +376,7 @@ const countTableSelects = ( case 'NotExists': case 'Sum': case 'ToJSON': - case 'Where': + case 'Where': { const unaryOperation = abstractSql as | AliasNode | AnyNode @@ -393,16 +395,16 @@ const countTableSelects = ( assertAbstractSqlIsNotLegacy(unaryOperation[1]); return countTableSelects(unaryOperation[1], table); - + } // `COUNT` is an unary function but we only support the `COUNT(*)` form - case 'Count': + case 'Count': { const countNode = abstractSql as CountNode; if (countNode[1] !== '*') { throw new Error('Only COUNT(*) is supported'); } return 0; - + } // Binary nodes case 'AddDateDuration': case 'AddDateNumber': @@ -418,7 +420,7 @@ const countTableSelects = ( case 'NotEquals': case 'SubtractDateDate': case 'SubtractDateDuration': - case 'SubtractDateNumber': + case 'SubtractDateNumber': { const binaryOperation = abstractSql as | AddDateDurationNode | AddDateNumberNode @@ -444,12 +446,12 @@ const countTableSelects = ( countTableSelects(leftOperand, table) + countTableSelects(rightOperand, table) ); - + } // Binary nodes with optional `ON` second argument case 'FullJoin': case 'Join': case 'LeftJoin': - case 'RightJoin': + case 'RightJoin': { const joinNode = abstractSql as | FullJoinNode | InnerJoinNode @@ -462,13 +464,13 @@ const countTableSelects = ( } return sum + countTableSelects(joinNode[1], table); - + } // n-ary nodes case 'And': case 'Or': case 'SelectQuery': case 'TextArray': - case 'UnionQuery': + case 'UnionQuery': { const selectQueryNode = abstractSql as | AndNode | OrNode @@ -481,10 +483,10 @@ const countTableSelects = ( } return sum; - + } // n-ary nodes but the slice starts at the third argument case 'In': - case 'NotIn': + case 'NotIn': { const inNode = abstractSql as InNode | NotInNode; for (const arg of inNode.slice(2)) { assertAbstractSqlIsNotLegacy(arg); @@ -492,9 +494,9 @@ const countTableSelects = ( } return sum; - + } // n-ary-like node - case 'Select': + case 'Select': { const selectNode = abstractSql as SelectNode; for (const arg of selectNode[1]) { assertAbstractSqlIsNotLegacy(arg); @@ -502,7 +504,7 @@ const countTableSelects = ( } return sum; - + } // Uninteresting atomic nodes case 'Boolean': case 'Date': @@ -517,7 +519,7 @@ const countTableSelects = ( return 0; // The atomic node we're looking for: a table selection - case 'Table': + case 'Table': { const tableNode = abstractSql as TableNode; if (tableNode[1] === table) { @@ -525,7 +527,7 @@ const countTableSelects = ( } else { return 0; } - + } default: throw new Error(`unknown abstract sql type: ${abstractSql[0]}`); } diff --git a/test/abstract-sql/aggregate-json.ts b/test/abstract-sql/aggregate-json.ts index abbf97f..fbff27b 100644 --- a/test/abstract-sql/aggregate-json.ts +++ b/test/abstract-sql/aggregate-json.ts @@ -1,11 +1,11 @@ -import { AnyTypeNodes } from '../../src/AbstractSQLCompiler'; +import type { AnyTypeNodes } from '../../src/AbstractSQLCompiler'; type TestCb = ( result: { query: string }, sqlEquals: (a: string, b: string) => void, ) => void; -// tslint:disable-next-line no-var-requires -const test = require('./test') as ( +import $test from './test'; +const test = $test as ( query: AnyTypeNodes, binds: any[][] | TestCb, cb?: TestCb, diff --git a/test/abstract-sql/aggregate.ts b/test/abstract-sql/aggregate.ts index 82d3bbf..1a7a931 100644 --- a/test/abstract-sql/aggregate.ts +++ b/test/abstract-sql/aggregate.ts @@ -1,12 +1,12 @@ import { expect } from 'chai'; -import { AnyTypeNodes } from '../../src/AbstractSQLCompiler'; +import type { AnyTypeNodes } from '../../src/AbstractSQLCompiler'; type TestCb = ( result: { query: string }, sqlEquals: (a: string, b: string) => void, ) => void; -// tslint:disable-next-line no-var-requires -const test = require('./test') as ( +import $test from './test'; +const test = $test as ( query: AnyTypeNodes, binds: any[][] | TestCb, cb?: TestCb, diff --git a/test/abstract-sql/and-or-boolean-optimisations.ts b/test/abstract-sql/and-or-boolean-optimisations.ts index fb42e98..d3dcdb0 100644 --- a/test/abstract-sql/and-or-boolean-optimisations.ts +++ b/test/abstract-sql/and-or-boolean-optimisations.ts @@ -1,12 +1,12 @@ import { stripIndent } from 'common-tags'; -import { AnyTypeNodes } from '../../src/AbstractSQLCompiler'; +import type { AnyTypeNodes } from '../../src/AbstractSQLCompiler'; type TestCb = ( result: { query: string }, sqlEquals: (a: string, b: string) => void, ) => void; -// tslint:disable-next-line no-var-requires -const test = require('./test') as ( +import $test from './test'; +const test = $test as ( query: AnyTypeNodes, binds: any[][] | TestCb, cb?: TestCb, diff --git a/test/abstract-sql/case-when-else.js b/test/abstract-sql/case-when-else.js index 87fcfcd..3a1c8bc 100644 --- a/test/abstract-sql/case-when-else.js +++ b/test/abstract-sql/case-when-else.js @@ -1,4 +1,4 @@ -const test = require('./test'); +import test from './test'; const buildSelect = (withElse) => [ 'SelectQuery', diff --git a/test/abstract-sql/cast.ts b/test/abstract-sql/cast.ts index 46d285d..704f5cf 100644 --- a/test/abstract-sql/cast.ts +++ b/test/abstract-sql/cast.ts @@ -1,11 +1,11 @@ -import { AnyTypeNodes } from '../../src/AbstractSQLCompiler'; +import type { AnyTypeNodes } from '../../src/AbstractSQLCompiler'; type TestCb = ( result: { query: string }, sqlEquals: (a: string, b: string) => void, ) => void; -// tslint:disable-next-line no-var-requires -const test = require('./test') as ( +import $test from './test'; +const test = $test as ( query: AnyTypeNodes, binds: any[][] | TestCb, cb?: TestCb, diff --git a/test/abstract-sql/coalesce.ts b/test/abstract-sql/coalesce.ts index 0295325..03b62f2 100644 --- a/test/abstract-sql/coalesce.ts +++ b/test/abstract-sql/coalesce.ts @@ -1,11 +1,11 @@ -import { AnyTypeNodes } from '../../src/AbstractSQLCompiler'; +import type { AnyTypeNodes } from '../../src/AbstractSQLCompiler'; type TestCb = ( result: { query: string }, sqlEquals: (a: string, b: string) => void, ) => void; -// tslint:disable-next-line no-var-requires -const test = require('./test') as ( +import $test from './test'; +const test = $test as ( query: AnyTypeNodes, binds: any[][] | TestCb, cb?: TestCb, diff --git a/test/abstract-sql/comparisons.ts b/test/abstract-sql/comparisons.ts index 8a9f81b..679d4e3 100644 --- a/test/abstract-sql/comparisons.ts +++ b/test/abstract-sql/comparisons.ts @@ -1,11 +1,11 @@ -import { AnyTypeNodes } from '../../src/AbstractSQLCompiler'; +import type { AnyTypeNodes } from '../../src/AbstractSQLCompiler'; type TestCb = ( result: { query: string }, sqlEquals: (a: string, b: string) => void, ) => void; -// tslint:disable-next-line no-var-requires -const test = require('./test') as ( +import $test from './test'; +const test = $test as ( query: AnyTypeNodes, binds: any[][] | TestCb, cb?: TestCb, diff --git a/test/abstract-sql/dates.ts b/test/abstract-sql/dates.ts index d70967b..c870708 100644 --- a/test/abstract-sql/dates.ts +++ b/test/abstract-sql/dates.ts @@ -1,11 +1,11 @@ -import { AnyTypeNodes } from '../../src/AbstractSQLCompiler'; +import type { AnyTypeNodes } from '../../src/AbstractSQLCompiler'; type TestCb = ( result: { query: string }, sqlEquals: (a: string, b: string) => void, ) => void; -// tslint:disable-next-line no-var-requires -const test = require('./test') as ( +import $test from './test'; +const test = $test as ( query: AnyTypeNodes, binds: any[][] | TestCb, cb?: TestCb, diff --git a/test/abstract-sql/duration.ts b/test/abstract-sql/duration.ts index ff5cbd3..42af78c 100644 --- a/test/abstract-sql/duration.ts +++ b/test/abstract-sql/duration.ts @@ -1,11 +1,11 @@ -import { AnyTypeNodes } from '../../src/AbstractSQLCompiler'; +import type { AnyTypeNodes } from '../../src/AbstractSQLCompiler'; type TestCb = ( result: { query: string }, sqlEquals: (a: string, b: string) => void, ) => void; -// tslint:disable-next-line no-var-requires -const test = require('./test') as ( +import $test from './test'; +const test = $test as ( query: AnyTypeNodes, binds: any[][] | TestCb, cb?: TestCb, diff --git a/test/abstract-sql/empty-query-optimisations.ts b/test/abstract-sql/empty-query-optimisations.ts index 168ac39..666b1b2 100644 --- a/test/abstract-sql/empty-query-optimisations.ts +++ b/test/abstract-sql/empty-query-optimisations.ts @@ -1,12 +1,15 @@ import { stripIndent } from 'common-tags'; -import { AnyTypeNodes, SelectQueryNode } from '../../src/AbstractSQLCompiler'; +import type { + AnyTypeNodes, + SelectQueryNode, +} from '../../src/AbstractSQLCompiler'; type TestCb = ( result: { query: string }, sqlEquals: (a: string, b: string) => void, ) => void; -// tslint:disable-next-line no-var-requires -const test = require('./test') as ( +import $test from './test'; +const test = $test as ( query: AnyTypeNodes, binds: any[][] | TestCb, cb?: TestCb, diff --git a/test/abstract-sql/functions_wrapper.ts b/test/abstract-sql/functions_wrapper.ts index 8133136..42d13cf 100644 --- a/test/abstract-sql/functions_wrapper.ts +++ b/test/abstract-sql/functions_wrapper.ts @@ -1,12 +1,12 @@ import { stripIndent } from 'common-tags'; -import { AnyTypeNodes } from '../../src/AbstractSQLCompiler'; +import type { AnyTypeNodes } from '../../src/AbstractSQLCompiler'; type TestCb = ( result: { query: string }, sqlEquals: (a: string, b: string) => void, ) => void; -// tslint:disable-next-line no-var-requires -const test = require('./test') as (( +import $test from './test'; +const test = $test as (( query: AnyTypeNodes, binds: any[][] | TestCb, cb?: TestCb, diff --git a/test/abstract-sql/insert-query.ts b/test/abstract-sql/insert-query.ts index ccd56dd..11a3ad8 100644 --- a/test/abstract-sql/insert-query.ts +++ b/test/abstract-sql/insert-query.ts @@ -1,11 +1,11 @@ -import { AnyTypeNodes } from '../../src/AbstractSQLCompiler'; +import type { AnyTypeNodes } from '../../src/AbstractSQLCompiler'; type TestCb = ( result: { query: string }, sqlEquals: (a: string, b: string) => void, ) => void; -// tslint:disable-next-line no-var-requires -const test = require('./test') as ( +import $test from './test'; +const test = $test as ( query: AnyTypeNodes, binds: any[][] | TestCb, cb?: TestCb, diff --git a/test/abstract-sql/is-distinct.ts b/test/abstract-sql/is-distinct.ts index de3382f..2725b16 100644 --- a/test/abstract-sql/is-distinct.ts +++ b/test/abstract-sql/is-distinct.ts @@ -1,11 +1,11 @@ -import { AnyTypeNodes } from '../../src/AbstractSQLCompiler'; +import type { AnyTypeNodes } from '../../src/AbstractSQLCompiler'; type TestCb = ( result: { query: string }, sqlEquals: (a: string, b: string) => void, ) => void; -// tslint:disable-next-line no-var-requires -const test = require('./test') as ( +import $test from './test'; +const test = $test as ( query: AnyTypeNodes, binds: any[][] | TestCb, cb?: TestCb, diff --git a/test/abstract-sql/joins.ts b/test/abstract-sql/joins.ts index 7a8a924..da00a1a 100644 --- a/test/abstract-sql/joins.ts +++ b/test/abstract-sql/joins.ts @@ -1,12 +1,12 @@ import { stripIndent } from 'common-tags'; -import { AnyTypeNodes } from '../../src/AbstractSQLCompiler'; +import type { AnyTypeNodes } from '../../src/AbstractSQLCompiler'; type TestCb = ( result: { query: string }, sqlEquals: (a: string, b: string) => void, ) => void; -// tslint:disable-next-line no-var-requires -const test = require('./test') as ( +import $test from './test'; +const test = $test as ( query: AnyTypeNodes, binds: any[][] | TestCb, cb?: TestCb, diff --git a/test/abstract-sql/json.ts b/test/abstract-sql/json.ts index f07594d..0b2295e 100644 --- a/test/abstract-sql/json.ts +++ b/test/abstract-sql/json.ts @@ -1,11 +1,11 @@ -import { AnyTypeNodes } from '../../src/AbstractSQLCompiler'; +import type { AnyTypeNodes } from '../../src/AbstractSQLCompiler'; type TestCb = ( result: { query: string }, sqlEquals: (a: string, b: string) => void, ) => void; -// tslint:disable-next-line no-var-requires -const test = require('./test') as ( +import $test from './test'; +const test = $test as ( query: AnyTypeNodes, binds: any[][] | TestCb, cb?: TestCb, diff --git a/test/abstract-sql/math.ts b/test/abstract-sql/math.ts index 8f9fcfe..8d230c6 100644 --- a/test/abstract-sql/math.ts +++ b/test/abstract-sql/math.ts @@ -1,11 +1,11 @@ -import { AnyTypeNodes } from '../../src/AbstractSQLCompiler'; +import type { AnyTypeNodes } from '../../src/AbstractSQLCompiler'; type TestCb = ( result: { query: string }, sqlEquals: (a: string, b: string) => void, ) => void; -// tslint:disable-next-line no-var-requires -const test = require('./test') as ( +import $test from './test'; +const test = $test as ( query: AnyTypeNodes, binds: any[][] | TestCb, cb?: TestCb, diff --git a/test/abstract-sql/nested-in-optimisations.ts b/test/abstract-sql/nested-in-optimisations.ts index 7a00b25..bc524ea 100644 --- a/test/abstract-sql/nested-in-optimisations.ts +++ b/test/abstract-sql/nested-in-optimisations.ts @@ -1,12 +1,12 @@ import { stripIndent } from 'common-tags'; -import { AnyTypeNodes } from '../../src/AbstractSQLCompiler'; +import type { AnyTypeNodes } from '../../src/AbstractSQLCompiler'; type TestCb = ( result: { query: string }, sqlEquals: (a: string, b: string) => void, ) => void; -// tslint:disable-next-line no-var-requires -const test = require('./test') as ( +import $test from './test'; +const test = $test as ( query: AnyTypeNodes, binds: any[][] | TestCb, cb?: TestCb, diff --git a/test/abstract-sql/not-not-optimisations.ts b/test/abstract-sql/not-not-optimisations.ts index 0f9347a..366dad0 100644 --- a/test/abstract-sql/not-not-optimisations.ts +++ b/test/abstract-sql/not-not-optimisations.ts @@ -1,12 +1,12 @@ import { stripIndent } from 'common-tags'; -import { AnyTypeNodes } from '../../src/AbstractSQLCompiler'; +import type { AnyTypeNodes } from '../../src/AbstractSQLCompiler'; type TestCb = ( result: { query: string }, sqlEquals: (a: string, b: string) => void, ) => void; -// tslint:disable-next-line no-var-requires -const test = require('./test') as ( +import $test from './test'; +const test = $test as ( query: AnyTypeNodes, binds: any[][] | TestCb, cb?: TestCb, diff --git a/test/abstract-sql/schema-rule-to-check.ts b/test/abstract-sql/schema-rule-to-check.ts index ba76f95..09d2651 100644 --- a/test/abstract-sql/schema-rule-to-check.ts +++ b/test/abstract-sql/schema-rule-to-check.ts @@ -148,7 +148,7 @@ it('should convert a basic rule to a check using COUNT(*) = 0', () => { CREATE TABLE IF NOT EXISTS "test" ( "id" INTEGER NULL PRIMARY KEY , -- It is necessary that each test has an id that is greater than 0. -CONSTRAINT "test$qEORqfvLM2D8/gu0ZEVfvrnt19+uBo55ipVGKTdmu0k=\" CHECK (0 < "id" +CONSTRAINT "test$qEORqfvLM2D8/gu0ZEVfvrnt19+uBo55ipVGKTdmu0k=" CHECK (0 < "id" AND "id" IS NOT NULL) );`, ]); diff --git a/test/abstract-sql/test.js b/test/abstract-sql/test.js index a0f23ae..068ca83 100644 --- a/test/abstract-sql/test.js +++ b/test/abstract-sql/test.js @@ -1,7 +1,7 @@ -const AbstractSQLCompiler = require('../..'); +import * as AbstractSQLCompiler from '../..'; -const { expect } = require('chai'); -const _ = require('lodash'); +import { expect } from 'chai'; +import * as _ from 'lodash'; const bindingsTest = function (actualBindings, expectedBindings) { if (expectedBindings == null) { @@ -79,11 +79,14 @@ const runExpectation = function ( const bindRunExpectation = function (engine) { const bound = runExpectation.bind(null, describe, engine); bound.skip = runExpectation.bind(null, describe.skip, engine); + // eslint-disable-next-line no-only-tests/no-only-tests -- this is a false positive bound.only = runExpectation.bind(null, describe.only, engine); return bound; }; -module.exports = bindRunExpectation('postgres'); -module.exports.postgres = bindRunExpectation('postgres'); -module.exports.mysql = bindRunExpectation('mysql'); -module.exports.websql = bindRunExpectation('websql'); +const testFn = bindRunExpectation('postgres'); +testFn.postgres = bindRunExpectation('postgres'); +testFn.mysql = bindRunExpectation('mysql'); +testFn.websql = bindRunExpectation('websql'); + +export default testFn; diff --git a/test/abstract-sql/text.ts b/test/abstract-sql/text.ts index e20640c..8810c79 100644 --- a/test/abstract-sql/text.ts +++ b/test/abstract-sql/text.ts @@ -1,11 +1,11 @@ -import { AnyTypeNodes } from '../../src/AbstractSQLCompiler'; +import type { AnyTypeNodes } from '../../src/AbstractSQLCompiler'; type TestCb = ( result: { query: string }, sqlEquals: (a: string, b: string) => void, ) => void; -// tslint:disable-next-line no-var-requires -const test = require('./test') as ( +import $test from './test'; +const test = $test as ( query: AnyTypeNodes, binds: any[][] | TestCb, cb?: TestCb, diff --git a/test/odata/expand.js b/test/odata/expand.js index 233cfb2..80ff4f3 100644 --- a/test/odata/expand.js +++ b/test/odata/expand.js @@ -1,12 +1,12 @@ -const test = require('./test'); -const { +import test from './test'; +import { pilotFields, aliasFields, aliasLicenceFields, aliasPlaneFields, aliasPilotCanFlyPlaneFields, -} = require('./fields'); -const _ = require('lodash'); +} from './fields'; +import * as _ from 'lodash'; const postgresAgg = (field) => 'COALESCE(JSON_AGG(' + field + "), '[]')"; const mysqlAgg = (field) => "'[' || group_concat(" + field + ", ',') || ']'"; @@ -73,7 +73,7 @@ FROM "pilot"`, }); }; - for (let url of [ + for (const url of [ '/pilot?$expand=can_fly__plane/plane', '/pilot?$expand=can_fly__plane($expand=plane)', ]) { @@ -124,7 +124,7 @@ FROM "pilot"`, }); }; - for (let url of [ + for (const url of [ '/pilot?$expand=can_fly__plane/plane,licence', '/pilot?$expand=can_fly__plane($expand=plane),licence', ]) { @@ -188,7 +188,7 @@ FROM "pilot"`, }); }; - for (let url of [ + for (const url of [ '/pilot?$select=id&$expand=can_fly__plane/plane', '/pilot?$select=id&$expand=can_fly__plane($expand=plane)', ]) { @@ -235,7 +235,7 @@ FROM "pilot"`, }); }; - for (let url of [ + for (const url of [ '/pilot?$select=id,licence&$expand=can_fly__plane/plane,licence', '/pilot?$select=id,licence&$expand=can_fly__plane($expand=plane),licence', ]) { diff --git a/test/odata/filterby.js b/test/odata/filterby.js index a2c3eae..bbe3417 100644 --- a/test/odata/filterby.js +++ b/test/odata/filterby.js @@ -3,16 +3,11 @@ * DS205: Consider reworking code to avoid use of IIFEs * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md */ -const { expect } = require('chai'); -const test = require('./test'); -const { clientModel } = test; -const _ = require('lodash'); -const { odataNameToSqlName } = require('@balena/odata-to-abstract-sql'); -const { - pilotFields, - teamFields, - aliasPilotCanFlyPlaneFields, -} = require('./fields'); +import { expect } from 'chai'; +import test, { clientModel } from './test'; +import * as _ from 'lodash'; +import { odataNameToSqlName } from '@balena/odata-to-abstract-sql'; +import { pilotFields, teamFields, aliasPilotCanFlyPlaneFields } from './fields'; const pilotFieldsStr = pilotFields.join(', '); const aliasPilotCanFlyPlaneFieldsStr = aliasPilotCanFlyPlaneFields.join(', '); @@ -107,7 +102,7 @@ let parseOperandFactory = function (defaultResource) { if (fieldParts.length > 1) { let alias = resource; let previousResource = resource; - for (let resourceName of fieldParts.slice(0, -1)) { + for (const resourceName of fieldParts.slice(0, -1)) { const sqlName = odataNameToSqlName(resourceName); const sqlNameParts = sqlName.split('-'); mapping = _.get( @@ -334,8 +329,8 @@ const createMethodCall = function (method, ...args) { bindings: args[0].bindings, odata, }; - default: - if (methodMaps.hasOwnProperty(method)) { + default: { + if (Object.prototype.hasOwnProperty.call(methodMaps, method)) { method = methodMaps[method]; } switch (method) { @@ -343,12 +338,13 @@ const createMethodCall = function (method, ...args) { args[1].sql += ' + 1'; break; } - var sql = method + '(' + args.map((arg) => arg.sql).join(', ') + ')'; + const sql = method + '(' + args.map((arg) => arg.sql).join(', ') + ')'; return { sql, bindings: _.flatten(args.map((arg) => arg.bindings)), odata, }; + } } }; diff --git a/test/odata/orderby.js b/test/odata/orderby.js index 292aa42..fe211b9 100644 --- a/test/odata/orderby.js +++ b/test/odata/orderby.js @@ -1,5 +1,5 @@ -const test = require('./test'); -const { pilotFields } = require('./fields'); +import test from './test'; +import { pilotFields } from './fields'; const pilotFieldsStr = pilotFields.join(', '); test('/pilot?$orderby=name', (result, sqlEquals) => { diff --git a/test/odata/paging.js b/test/odata/paging.js index f391836..0359781 100644 --- a/test/odata/paging.js +++ b/test/odata/paging.js @@ -1,5 +1,5 @@ -const test = require('./test'); -const { pilotFields } = require('./fields'); +import test from './test'; +import { pilotFields } from './fields'; const pilotFieldsStr = pilotFields.join(', '); test('/pilot?$top=5', (result, sqlEquals) => { diff --git a/test/odata/resource_parsing.js b/test/odata/resource_parsing.js index e299bdc..da9be1d 100644 --- a/test/odata/resource_parsing.js +++ b/test/odata/resource_parsing.js @@ -1,14 +1,14 @@ -const { expect } = require('chai'); -const test = require('./test'); -const ODataParser = require('@balena/odata-parser'); -let { +import { expect } from 'chai'; +import test from './test'; +import * as ODataParser from '@balena/odata-parser'; +import { pilotFields, teamFields, aliasFields, aliasPlaneFields, aliasPilotLicenceFields, aliasLicenceFields, -} = require('./fields'); +} from './fields'; const aliasPilotFields = aliasFields( 'plane.pilot-can fly-plane.pilot', pilotFields, diff --git a/test/odata/select.js b/test/odata/select.js index 76c6279..af3e721 100644 --- a/test/odata/select.js +++ b/test/odata/select.js @@ -1,5 +1,5 @@ -const test = require('./test'); -const { pilotFields } = require('./fields'); +import test from './test'; +import { pilotFields } from './fields'; const pilotFieldsStr = pilotFields.join(', '); test('/pilot?$select=name', (result, sqlEquals) => { diff --git a/test/odata/stress.js b/test/odata/stress.js index dd33504..6288fe3 100644 --- a/test/odata/stress.js +++ b/test/odata/stress.js @@ -1,6 +1,6 @@ -const test = require('./test'); -const _ = require('lodash'); -const { pilotFields } = require('./fields'); +import test from './test'; +import * as _ from 'lodash'; +import { pilotFields } from './fields'; const pilotFieldsStr = pilotFields.join(', '); const filterIDs = _.range(1, 5000); diff --git a/test/odata/test.js b/test/odata/test.js index 4b73976..24c46c8 100644 --- a/test/odata/test.js +++ b/test/odata/test.js @@ -1,26 +1,29 @@ -const fs = require('fs'); -const ODataParser = require('@balena/odata-parser'); -const { OData2AbstractSQL } = require('@balena/odata-to-abstract-sql'); +import * as fs from 'node:fs'; +import * as ODataParser from '@balena/odata-parser'; +import { OData2AbstractSQL } from '@balena/odata-to-abstract-sql'; const sbvrModel = fs.readFileSync(require.resolve('../model.sbvr'), 'utf8'); -const AbstractSQLCompiler = require('../..'); +import * as AbstractSQLCompiler from '../..'; -const { expect } = require('chai'); -const _ = require('lodash'); +import { expect } from 'chai'; +import * as _ from 'lodash'; const generateClientModel = function (input) { + // eslint-disable-next-line @typescript-eslint/no-var-requires const sbvrTypes = require('@balena/sbvr-types').default; const typeVocab = fs.readFileSync( require.resolve('@balena/sbvr-types/Type.sbvr'), 'utf8', ); + // eslint-disable-next-line @typescript-eslint/no-var-requires const SBVRParser = require('@balena/sbvr-parser').SBVRParser.createInstance(); SBVRParser.enableReusingMemoizations(SBVRParser._sideEffectingRules); SBVRParser.AddCustomAttribute('Database ID Field:'); SBVRParser.AddCustomAttribute('Database Table Name:'); SBVRParser.AddBuiltInVocab(typeVocab); + // eslint-disable-next-line @typescript-eslint/no-var-requires const LF2AbstractSQL = require('@balena/lf-to-abstract-sql'); const LF2AbstractSQLTranslator = LF2AbstractSQL.createTranslator(sbvrTypes); @@ -29,7 +32,7 @@ const generateClientModel = function (input) { return abstractSql; }; -const clientModel = generateClientModel(sbvrModel); +export const clientModel = generateClientModel(sbvrModel); const odata2AbstractSQL = new OData2AbstractSQL(clientModel); const bindingsTest = function (actualBindings, expectedBindings) { @@ -125,12 +128,14 @@ const runExpectation = function ( const bindRunExpectation = function (engine) { const bound = runExpectation.bind(null, describe, engine); bound.skip = runExpectation.bind(null, describe.skip, engine); + // eslint-disable-next-line no-only-tests/no-only-tests -- this is a false positive bound.only = runExpectation.bind(null, describe.only, engine); return bound; }; -module.exports = bindRunExpectation('postgres'); -module.exports.clientModel = clientModel; -module.exports.postgres = bindRunExpectation('postgres'); -module.exports.mysql = bindRunExpectation('mysql'); -module.exports.websql = bindRunExpectation('websql'); +const testFn = bindRunExpectation('postgres'); +testFn.postgres = bindRunExpectation('postgres'); +testFn.mysql = bindRunExpectation('mysql'); +testFn.websql = bindRunExpectation('websql'); + +export default testFn; diff --git a/test/sbvr/pilots.js b/test/sbvr/pilots.js index 23676b2..7c733c0 100644 --- a/test/sbvr/pilots.js +++ b/test/sbvr/pilots.js @@ -1,7 +1,9 @@ -const typeVocab = require('fs').readFileSync( +import * as fs from 'node:fs'; +const typeVocab = fs.readFileSync( require.resolve('@balena/sbvr-types/Type.sbvr'), ); -const test = require('./test')(typeVocab); +import { getTestHelpers } from './test'; +const test = getTestHelpers(typeVocab); const modifiedAtTrigger = (tableName) => `\ DO diff --git a/test/sbvr/reference-type.js b/test/sbvr/reference-type.js index c57b0c8..73cd4b2 100644 --- a/test/sbvr/reference-type.js +++ b/test/sbvr/reference-type.js @@ -1,6 +1,10 @@ -const typeVocab = require('fs').readFileSync( +import * as fs from 'node:fs'; +import { getTestHelpers } from './test'; + +const typeVocab = fs.readFileSync( require.resolve('@balena/sbvr-types/Type.sbvr'), ); + const modifiedAtTrigger = (tableName) => `\ DO $$ @@ -22,7 +26,7 @@ $$`; describe('reference type', function () { let test; beforeEach(() => { - test = require('./test')(typeVocab); + test = getTestHelpers(typeVocab); }); it('informative - no foreignKey for reference field', async () => { diff --git a/test/sbvr/test.js b/test/sbvr/test.js index bebfe70..f09e526 100644 --- a/test/sbvr/test.js +++ b/test/sbvr/test.js @@ -1,16 +1,18 @@ -const _ = require('lodash'); -const sbvrTypes = require('@balena/sbvr-types').default; +import * as _ from 'lodash'; +import sbvrTypes from '@balena/sbvr-types'; -const { expect } = require('chai'); -const AbstractSQLCompiler = require('../..'); +import { expect } from 'chai'; +import * as AbstractSQLCompiler from '../..'; -module.exports = function (builtInVocab) { +export function getTestHelpers(builtInVocab) { if (builtInVocab == null) { builtInVocab = false; } + // eslint-disable-next-line @typescript-eslint/no-var-requires const SBVRParser = require('@balena/sbvr-parser').SBVRParser.createInstance(); SBVRParser.enableReusingMemoizations(SBVRParser._sideEffectingRules); + // eslint-disable-next-line @typescript-eslint/no-var-requires const LF2AbstractSQL = require('@balena/lf-to-abstract-sql'); const LF2AbstractSQLTranslator = LF2AbstractSQL.createTranslator(sbvrTypes); @@ -74,9 +76,11 @@ module.exports = function (builtInVocab) { const ret = runSchema.bind(null, it); ret.skip = runSchema.bind(null, it.skip); + // eslint-disable-next-line no-only-tests/no-only-tests -- this is a false positive ret.only = runSchema.bind(null, it.only); ret.rule = runRule.bind(null, it); ret.rule.skip = runRule.bind(null, it.skip); + // eslint-disable-next-line no-only-tests/no-only-tests -- this is a false positive ret.rule.only = runRule.bind(null, it.only); return ret; -}; +} diff --git a/tsconfig.js.json b/tsconfig.js.json index 1833bff..bc215d0 100644 --- a/tsconfig.js.json +++ b/tsconfig.js.json @@ -4,4 +4,9 @@ "noImplicitAny": false, "checkJs": true }, + "include": [ + "src/**/*", + "test/**/*", + ".eslintrc.js" + ], }