Skip to content

Commit

Permalink
refactor(typescript): add foundation for incremential TS migration (#…
Browse files Browse the repository at this point in the history
…13569)

* refactor(typescript): add foundation for incremential TS migration

Converts the logger interface to TypeScript.
Adds eslint rules and TypeScript configuration to allow for a gradual migration to TS.
Adds a build script to transpile both TS and JS code while keeping the same API for package usage.
Changes imports from test files to use "absolute" paths that point to the directory of the compiled code.

* use || instead of ??

* fix source maps breaking tests

* fix build script for older versions of node

* make some small fixes + add better docs to logger.ts

* add ts support to tests

* update yarn.lock

* disable no-loss-of-percesion rule

* fix & cleanup a lil

* test.js -> test.[tj]s

Co-authored-by: Sascha Depold <sdepold@users.noreply.github.com>
  • Loading branch information
wbourne0 and sdepold committed Nov 18, 2021
1 parent 41876f1 commit 51bc05a
Show file tree
Hide file tree
Showing 194 changed files with 1,157 additions and 633 deletions.
44 changes: 33 additions & 11 deletions .eslintrc.json
@@ -1,12 +1,18 @@
{
"extends": "eslint:recommended",
"parser": "@typescript-eslint/parser",
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/recommended"
],
"rules": {
"@typescript-eslint/no-loss-of-precision": "off",
"mocha/no-exclusive-tests": "error",
"mocha/no-skipped-tests": "warn",

"jsdoc/check-param-names": "error",
"jsdoc/check-tag-names": "error",
"jsdoc/check-types": "error",
"jsdoc/check-types": "off",
"jsdoc/newline-after-description": "error",
"jsdoc/no-undefined-types": "off",
"jsdoc/require-description-complete-sentence": "off",
Expand All @@ -15,9 +21,9 @@
"jsdoc/require-param": "error",
"jsdoc/require-param-description": "off",
"jsdoc/require-param-name": "error",
"jsdoc/require-param-type": "error",
"jsdoc/require-param-type": "off",
"jsdoc/require-returns-description": "off",
"jsdoc/require-returns-type": "error",
"jsdoc/require-returns-type": "off",
"jsdoc/valid-types": "error",

// style
Expand All @@ -34,11 +40,14 @@
}
],
"semi": ["error", "always"],
"space-before-function-paren": ["error", {
"named": "never",
"anonymous": "never",
"asyncArrow": "always"
}],
"space-before-function-paren": [
"error",
{
"named": "never",
"anonymous": "never",
"asyncArrow": "always"
}
],
"space-before-blocks": "error",
"space-infix-ops": "error",
"no-multi-spaces": "error",
Expand Down Expand Up @@ -66,7 +75,6 @@

// functional
"valid-jsdoc": "off",
"strict": ["error", "global"],
"no-var": "error",
"prefer-const": "error",
"prefer-arrow-callback": "error",
Expand Down Expand Up @@ -97,6 +105,19 @@
"no-case-declarations": "off",
"prefer-object-spread": "error"
},
"overrides": [
{
"files": ["**/*.js"],
"rules": {
"@typescript-eslint/no-var-requires": "off",
"@typescript-eslint/no-empty-function": "off",
"@typescript-eslint/no-this-alias": "off",
"jsdoc/require-param-type": "error",
"jsdoc/check-types": "error",
"jsdoc/require-returns-type": "error"
}
}
],
"settings": {
"jsdoc": {
"tagNamePreference": {
Expand All @@ -108,7 +129,8 @@
"ecmaVersion": 2020,
"sourceType": "script"
},
"plugins": ["mocha", "jsdoc"],
"ignorePatterns": ["dist/**/*", "types/**/*"],
"plugins": ["mocha", "jsdoc", "@typescript-eslint"],
"env": {
"node": true,
"mocha": true,
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -14,3 +14,4 @@ test/binary/tmp/*
.vscode/
esdoc
node_modules
dist/*
87 changes: 87 additions & 0 deletions build.js
@@ -0,0 +1,87 @@
'use strict';

const glob = require('fast-glob');
const { promisify } = require('util');
const { build } = require('esbuild');
const fs = require('fs');
const copyFiles = promisify( require('copyfiles'));
const path = require('path');
const exec = promisify(require('child_process').exec);

const rmdir = promisify(fs.rmdir);
const stat = promisify(fs.stat);

// if this script is moved, this will need to be adjusted
const rootDir = __dirname;
const outdir = path.join(rootDir, 'dist');

const nodeMajorVersion = Number(process.version.match(/(?<=^v)\d+/));

async function rmDistDir() {
try {
await stat(outdir);
if (nodeMajorVersion >= 12) {
await rmdir(outdir, { recursive: true });
} else {
await rmdir(outdir);
}
} catch {
/* no-op */
}
}

async function main() {
console.log('Compiling sequelize...');
const [declarationFiles, filesToCompile] = await Promise.all([
// Find all .d.ts files from types/
glob('./types/**/*.d.ts', { onlyFiles: true, absolute: false }),
// Find all .js and .ts files from lib/
glob('./lib/**/*.[tj]s', { onlyFiles: true, absolute: false }),
// Delete dist/ for a full rebuild.
rmDistDir()
]);

// copy .d.ts files prior to generating them from the .ts files
// so the .ts files in lib/ will take priority..
await copyFiles(
// The last path in the list is the output directory
declarationFiles.concat(outdir),
{ up: 1 }
);

await Promise.all([
build({
// Adds source mapping
sourcemap: true,
// The compiled code should be usable in node v10
target: 'node10',
// The source code's format is commonjs.
format: 'cjs',

outdir,
entryPoints: filesToCompile
.concat('./index.js')
.map(file => path.resolve(file)),

// minify the compiled code
minify: true,
// Keep `constructor.name` the same (used for associations)
keepNames: true
}),

exec('tsc', {
env: {
// binaries installed from modules have symlinks in
// <pkg root>/node_modules/.bin.
PATH: `${process.env.PATH || ''}:${path.join(
rootDir,
'node_modules/.bin'
)}`
},
cwd: rootDir
})
]);
}

main().catch(console.error).finally(process.exit);

10 changes: 9 additions & 1 deletion lib/sequelize.js
Expand Up @@ -1267,7 +1267,15 @@ Sequelize.prototype.validate = Sequelize.prototype.authenticate;
/**
* Sequelize version number.
*/
Sequelize.version = require('../package.json').version;
// To avoid any errors on startup when this field is unused, only resolve it as needed.
// this is to prevent any potential issues on startup with unusual environments (eg, bundled code)
// where relative paths may fail that are unnecessary.
Object.defineProperty(Sequelize, 'version', {
enumerable: true,
get() {
return require('../../package.json').version;
}
});

Sequelize.options = { hooks: {} };

Expand Down
40 changes: 0 additions & 40 deletions lib/utils/logger.js

This file was deleted.

68 changes: 68 additions & 0 deletions lib/utils/logger.ts
@@ -0,0 +1,68 @@
/**
* @file Sequelize module for debug and deprecation messages.
* It require a `context` for which messages will be printed.
*
* @module logging
* @access package
*/
import nodeDebug from 'debug';
import util from 'util';

/**
* The configuration for sequelize's logging interface.
*
* @access package
*/
export interface LoggerConfig {
/**
* The context which the logger should log in.
*
* @default 'sequelize'
*/
context?: string;
}

export class Logger {
protected config: LoggerConfig;

constructor({ context = 'sequelize', ...rest }: Partial<LoggerConfig> = {}) {
this.config = {
context,
...rest
};
}

/**
* Logs a warning in the logger's context.
*
* @param message The message of the warning.
*/
warn(message: string): void {
console.warn(`(${this.config.context}) Warning: ${message}`);
}

/**
* Uses node's util.inspect to stringify a value.
*
* @param value The value which should be inspected.
* @returns The string of the inspected value.
*/
inspect(value: unknown): string {
return util.inspect(value, {
showHidden: false,
depth: 1
});
}

/**
* Gets a debugger for a context.
*
* @param name The name of the context.
* @returns A debugger interace which can be used to debug.
*/
debugContext(name: string): nodeDebug.Debugger {
return nodeDebug(`${this.config.context}:${name}`);
}
}

export const logger = new Logger();

0 comments on commit 51bc05a

Please sign in to comment.