diff --git a/.gitignore b/.gitignore index 3c3629e6..e359cde1 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ node_modules +cjs diff --git a/lib/backend.js b/lib/backend.js index c8c44ae5..9521199b 100644 --- a/lib/backend.js +++ b/lib/backend.js @@ -1,10 +1,10 @@ -const { errors } = require('./errors.js') - , { entries, errorFields } = require('./types.js') +import { errors } from './errors.js' +import { entries, errorFields } from './types.js' const char = (acc, [k, v]) => (acc[k.charCodeAt(0)] = v, acc) , N = '\u0000' -module.exports = Backend +export default Backend function Backend({ onparse, diff --git a/lib/bytes.js b/lib/bytes.js index c4ec3152..0a09887f 100644 --- a/lib/bytes.js +++ b/lib/bytes.js @@ -59,7 +59,7 @@ const b = Object.assign(messages, { } }) -module.exports = b +export default b function fit(x) { if (buffer.length - b.i < x) { diff --git a/lib/connection.js b/lib/connection.js index 5d284b72..fc16401a 100644 --- a/lib/connection.js +++ b/lib/connection.js @@ -1,12 +1,12 @@ -const net = require('net') -const tls = require('tls') -const frontend = require('./frontend.js') -const Backend = require('./backend.js') -const Queue = require('./queue.js') -const { END, retryRoutines } = require('./types.js') -const { errors } = require('./errors.js') - -module.exports = Connection +import net from 'net' +import tls from 'tls' +import frontend from './frontend.js' +import Backend from './backend.js' +import Queue from './queue.js' +import { END, retryRoutines } from './types.js' +import { errors } from './errors.js' + +export default Connection let count = 1 diff --git a/lib/errors.js b/lib/errors.js index 16732d44..cf6dbeb8 100644 --- a/lib/errors.js +++ b/lib/errors.js @@ -1,4 +1,4 @@ -class PostgresError extends Error { +export class PostgresError extends Error { constructor(x) { super(x.message) this.name = this.constructor.name @@ -6,9 +6,7 @@ class PostgresError extends Error { } } -module.exports.PostgresError = PostgresError - -module.exports.errors = { +export const errors = { connection, postgres, generic, diff --git a/lib/frontend.js b/lib/frontend.js index 72f8c463..35da6edd 100644 --- a/lib/frontend.js +++ b/lib/frontend.js @@ -1,7 +1,7 @@ -const crypto = require('crypto') -const bytes = require('./bytes.js') -const { entries } = require('./types.js') -const { errors } = require('./errors.js') +import crypto from 'crypto' +import bytes from './bytes.js' +import { entries } from './types.js' +import { errors } from './errors.js' const N = String.fromCharCode(0) const empty = Buffer.alloc(0) @@ -36,7 +36,7 @@ const auths = { 12: SASLFinal } -module.exports = { +export default { StartupMessage, SSLRequest, auth, diff --git a/lib/index.js b/lib/index.js index 358ece9e..795be586 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1,11 +1,12 @@ -const fs = require('fs') -const Url = require('url') -const Stream = require('stream') -const Connection = require('./connection.js') -const Queue = require('./queue.js') -const Subscribe = require('./subscribe.js') -const { errors, PostgresError } = require('./errors.js') -const { +import fs from 'fs' +import os from 'os' +import Url from 'url' +import Stream from 'stream' +import Connection from './connection.js' +import Queue from './queue.js' +import Subscribe from './subscribe.js' +import { errors, PostgresError } from './errors.js' +import { mergeUserTypes, arraySerializer, arrayParser, @@ -20,7 +21,7 @@ const { escape, types, END -} = require('./types.js') +} from './types.js' const notPromise = { P: {}, @@ -51,7 +52,7 @@ Object.assign(Postgres, { const originCache = new Map() -module.exports = Postgres +export default Postgres function Postgres(a, b) { if (arguments.length && !a) @@ -704,7 +705,7 @@ function warn(x) { function osUsername() { try { - return require('os').userInfo().username // eslint-disable-line + return os.userInfo().username // eslint-disable-line } catch (_) { return } diff --git a/lib/queue.js b/lib/queue.js index 7a6f2b46..e786ead6 100644 --- a/lib/queue.js +++ b/lib/queue.js @@ -1,4 +1,4 @@ -module.exports = Queue +export default Queue function Queue() { let xs = [] diff --git a/lib/subscribe.js b/lib/subscribe.js index 0a5b4899..79327c69 100644 --- a/lib/subscribe.js +++ b/lib/subscribe.js @@ -1,4 +1,4 @@ -module.exports = function(postgres, a, b) { +export default function Subscribe(postgres, a, b) { const listeners = new Map() let connection diff --git a/lib/types.js b/lib/types.js index eae74fe1..b7af59fc 100644 --- a/lib/types.js +++ b/lib/types.js @@ -1,8 +1,8 @@ -const char = module.exports.char = (acc, [k, v]) => (acc[k.charCodeAt(0)] = v, acc) -const entries = o => Object.keys(o).map(x => [x, o[x]]) +export const char = (acc, [k, v]) => (acc[k.charCodeAt(0)] = v, acc) +export const entries = o => Object.keys(o).map(x => [x, o[x]]) // These were the fastest ways to do it in Node.js v12.11.1 (add tests to revise if this changes) -const types = module.exports.types = { +export const types = { string: { to: 25, from: null, // defaults to string @@ -42,14 +42,12 @@ const types = module.exports.types = { const defaultHandlers = typeHandlers(types) -const serializers = module.exports.serializers = defaultHandlers.serializers -const parsers = module.exports.parsers = defaultHandlers.parsers +export const serializers = defaultHandlers.serializers +export const parsers = defaultHandlers.parsers -module.exports.entries = entries +export const END = {} -module.exports.END = {} - -module.exports.mergeUserTypes = function(types) { +export const mergeUserTypes = function(types) { const user = typeHandlers(types || {}) return { serializers: Object.assign({}, serializers, user.serializers), @@ -65,7 +63,7 @@ function typeHandlers(types) { }, { parsers: {}, serializers: {} }) } -module.exports.escape = function escape(str) { +export const escape = function escape(str) { return '"' + str.replace(/"/g, '""').replace(/\./g, '"."') + '"' } @@ -75,7 +73,7 @@ const type = { boolean: 16 } -module.exports.inferType = function inferType(x) { +export const inferType = function inferType(x) { return (x && x.type) || (x instanceof Date ? 1184 : Array.isArray(x) @@ -94,7 +92,7 @@ function arrayEscape(x) { .replace(escapeQuote, '\\"') } -module.exports.arraySerializer = function arraySerializer(xs, serializer) { +export const arraySerializer = function arraySerializer(xs, serializer) { if (!xs.length) return '{}' @@ -116,7 +114,7 @@ const arrayParserState = { last: 0 } -module.exports.arrayParser = function arrayParser(x, parser) { +export const arrayParser = function arrayParser(x, parser) { arrayParserState.i = arrayParserState.last = 0 return arrayParserLoop(arrayParserState, x, parser) } @@ -156,27 +154,27 @@ function arrayParserLoop(s, x, parser) { return xs } -module.exports.toCamel = x => { +export const toCamel = x => { let str = x[0] for (let i = 1; i < x.length; i++) str += x[i] === '_' ? x[++i].toUpperCase() : x[i] return str } -module.exports.toPascal = x => { +export const toPascal = x => { let str = x[0].toUpperCase() for (let i = 1; i < x.length; i++) str += x[i] === '_' ? x[++i].toUpperCase() : x[i] return str } -module.exports.toKebab = x => x.replace(/_/g, '-') +export const toKebab = x => x.replace(/_/g, '-') -module.exports.fromCamel = x => x.replace(/([A-Z])/g, '_$1').toLowerCase() -module.exports.fromPascal = x => (x.slice(0, 1) + x.slice(1).replace(/([A-Z])/g, '_$1')).toLowerCase() -module.exports.fromKebab = x => x.replace(/-/g, '_') +export const fromCamel = x => x.replace(/([A-Z])/g, '_$1').toLowerCase() +export const fromPascal = x => (x.slice(0, 1) + x.slice(1).replace(/([A-Z])/g, '_$1')).toLowerCase() +export const fromKebab = x => x.replace(/-/g, '_') -module.exports.errorFields = entries({ +export const errorFields = entries({ S: 'severity_local', V: 'severity', C: 'code', @@ -197,7 +195,7 @@ module.exports.errorFields = entries({ R: 'routine' }).reduce(char, {}) -module.exports.retryRoutines = { +export const retryRoutines = { FetchPreparedStatement: true, RevalidateCachedQuery: true, transformAssignedExpr: true diff --git a/package.json b/package.json index ff983ff1..3a84b956 100644 --- a/package.json +++ b/package.json @@ -2,16 +2,24 @@ "name": "postgres", "version": "2.0.0-beta.9", "description": "Fastest full featured PostgreSQL client for Node.js", - "main": "lib/index.js", + "type": "module", + "module": "lib/index.js", + "main": "cjs/index.js", + "exports": { + "import": "./lib/index.js", + "default": "./cjs/index.js" + }, "types": "types/index.d.ts", "typings": "types/index.d.ts", - "type": "commonjs", "scripts": { - "test": "node tests/index.js", + "build": "node transpile.cjs", + "test": "pushd tests && node index.js && popd && npm run build && pushd cjs/tests && node index.js", "lint": "eslint lib && eslint tests", - "prepublishOnly": "npm run lint && npm test" + "prepare": "npm run build", + "prepublishOnly": "npm run lint" }, "files": [ + "/cjs", "/lib", "/types" ], diff --git a/tests/bootstrap.js b/tests/bootstrap.js index e25cc862..78f96c15 100644 --- a/tests/bootstrap.js +++ b/tests/bootstrap.js @@ -1,4 +1,4 @@ -const cp = require('child_process') +import cp from 'child_process' exec('psql -c "create user postgres_js_test"') exec('psql -c "alter system set password_encryption=md5"') diff --git a/tests/index.js b/tests/index.js index 2762929b..984e9d40 100644 --- a/tests/index.js +++ b/tests/index.js @@ -1,15 +1,15 @@ /* eslint no-console: 0 */ -require('./bootstrap.js') +import './bootstrap.js' -const { t, not, ot } = require('./test.js') // eslint-disable-line -const cp = require('child_process') -const path = require('path') -const net = require('net') -const fs = require('fs') +import { t, not, ot } from './test.js' // eslint-disable-line +import cp from 'child_process' +import path from 'path' +import net from 'net' +import fs from 'fs' /** @type {import('../types')} */ -const postgres = require('../lib') +import postgres from '../lib/index.js' const delay = ms => new Promise(r => setTimeout(r, ms)) const login = { @@ -397,13 +397,13 @@ t('Point type array', async() => { }) t('sql file', async() => - [1, (await sql.file(path.join(__dirname, 'select.sql')))[0].x] + [1, (await sql.file(path.join('select.sql')))[0].x] ) t('sql file can stream', async() => { let result await sql - .file(path.join(__dirname, 'select.sql'), { cache: false }) + .file(path.join('select.sql'), { cache: false }) .stream(({ x }) => result = x) return [1, result] @@ -414,15 +414,15 @@ t('sql file throws', async() => ) t('sql file cached', async() => { - await sql.file(path.join(__dirname, 'select.sql')) + await sql.file(path.join('select.sql')) await delay(20) - return [1, (await sql.file(path.join(__dirname, 'select.sql')))[0].x] + return [1, (await sql.file(path.join('select.sql')))[0].x] }) t('Parameters in file', async() => { const result = await sql.file( - path.join(__dirname, 'select-param.sql'), + path.join('select-param.sql'), ['hello'] ) return ['hello', result[0].x] @@ -1091,8 +1091,8 @@ t('numeric is returned as string', async() => [ t('Async stack trace', async() => { const sql = postgres({ ...options, debug: false }) return [ - parseInt(new Error().stack.split('\n')[1].split(':')[1]) + 1, - parseInt(await sql`select.sql`.catch(x => x.stack.split('\n').pop().split(':')[1])) + parseInt(new Error().stack.split('\n')[1].match(':([0-9]+):')[1]) + 1, + parseInt(await sql`select.sql`.catch(x => x.stack.split('\n').pop().match(':([0-9]+):')[1])) ] }) @@ -1404,7 +1404,7 @@ t('Copy write as first works', async() => { t('Copy from file works', async() => { await sql`create table test (x int, y int, z int)` await new Promise(r => fs - .createReadStream(path.join(__dirname, 'copy.csv')) + .createReadStream(path.join('copy.csv')) .pipe(sql`copy test from stdin`.writable()) .on('finish', r) ) @@ -1432,7 +1432,7 @@ t('Copy from works in transaction', async() => { t('Copy from abort works', async() => { const sql = postgres(options) - const readable = fs.createReadStream(path.join(__dirname, 'copy.csv')) + const readable = fs.createReadStream(path.join('copy.csv')) await sql`create table test (x int, y int, z int)` await sql`TRUNCATE TABLE test` diff --git a/tests/test.js b/tests/test.js index 05583e61..98613efc 100644 --- a/tests/test.js +++ b/tests/test.js @@ -1,6 +1,6 @@ /* eslint no-console: 0 */ -const util = require('util') +import util from 'util' let done = 0 let only = false @@ -8,15 +8,15 @@ let ignored = 0 let promise = Promise.resolve() const tests = {} -module.exports.not = () => ignored++ -module.exports.ot = (...rest) => (only = true, test(true, ...rest)) +export const not = () => ignored++ +export const ot = (...rest) => (only = true, test(true, ...rest)) -const t = module.exports.t = (...rest) => test(false, ...rest) +export const t = (...rest) => test(false, ...rest) t.timeout = 500 async function test(o, name, options, fn) { typeof options !== 'object' && (fn = options, options = {}) - const line = new Error().stack.split('\n')[3].split(':')[1] + const line = new Error().stack.split('\n')[3].match(':([0-9]+):')[1] await 1 if (only && !o) diff --git a/transpile.cjs b/transpile.cjs new file mode 100644 index 00000000..61cb35da --- /dev/null +++ b/transpile.cjs @@ -0,0 +1,41 @@ +const fs = require('fs') + , path = require('path') + +const empty = x => fs.readdirSync(x).forEach(f => fs.unlinkSync(path.join(x, f))) + , ensureEmpty = x => !fs.existsSync(x) ? fs.mkdirSync(x) : empty(x) + , root = 'cjs' + , lib = path.join(root, 'lib') + , tests = path.join(root, 'tests') + +!fs.existsSync(root) && fs.mkdirSync(root) +ensureEmpty(lib) +ensureEmpty(tests) + +fs.readdirSync('lib').forEach(name => + fs.writeFileSync( + path.join(lib, name), + transpile(fs.readFileSync(path.join('lib', name), 'utf8')) + ) +) + +fs.readdirSync('tests').forEach(name => + fs.writeFileSync( + path.join(tests, name), + name.endsWith('.js') + ? transpile(fs.readFileSync(path.join('tests', name), 'utf8')) + : fs.readFileSync(path.join('tests', name), 'utf8') + ) +) + +fs.writeFileSync(path.join(root, 'package.json'), JSON.stringify({ type: 'commonjs' })) + +function transpile(x) { + return x.replace(/export default function ([^(]+)/, 'module.exports = $1;function $1') + .replace(/export class ([^ ]+) ([\s\S]+)/, 'class $1 $2;module.exports.$1 = $1') + .replace(/export default /, 'module.exports = ') + .replace(/export const ([a-z0-9_$]+)/gi, 'const $1 = module.exports.$1') + .replace(/export function ([a-z0-9_$]+)/gi, 'module.exports.$1 = function $1') + .replace(/import {([^{}]*?)} from (['"].*?['"])/gi, 'const {$1} = require($2)') + .replace(/import (.*?) from (['"].*?['"])/gi, 'const $1 = require($2)') + .replace(/import (['"].*?['"])/gi, 'require($1)') +}