diff --git a/README.md b/README.md index e8cf2f9..232e0af 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com) -[![Node.js CI](https://github.com/juanelas/bigint-crypto-utils/workflows/build/badge.svg)](https://github.com/juanelas/bigint-crypto-utils/actions?query=workflow%3A%22build%22) +[![Node.js CI](https://github.com/juanelas/bigint-crypto-utils/actions/workflows/build-and-test.yml/badge.svg)](https://github.com/juanelas/bigint-crypto-utils/actions/workflows/build-and-test.yml) [![Coverage Status](https://coveralls.io/repos/github/juanelas/bigint-crypto-utils/badge.svg?branch=master)](https://coveralls.io/github/juanelas/bigint-crypto-utils?branch=master) # bigint-crypto-utils diff --git a/build/bin/mocha-ts.cjs b/build/bin/mocha-ts.cjs new file mode 100644 index 0000000..2a96f20 --- /dev/null +++ b/build/bin/mocha-ts.cjs @@ -0,0 +1,166 @@ +#! /usr/bin/env node +const fs = require('fs') +const path = require('path') +const glob = require('glob') +const minimatch = require('minimatch') +const rimraf = require('rimraf') +const runScript = require('../run-script.cjs') + +const rootDir = path.join(__dirname, '../..') + +const pkgJson = require(path.join(rootDir, 'package.json')) + +const mochaTsRelativeDir = pkgJson.directories['mocha-ts'] +const mochaTsDir = path.join(rootDir, mochaTsRelativeDir) + +// clean .mocha-ts directory +rimraf.sync(mochaTsDir) + +const semaphorePath = `${mochaTsRelativeDir}/semaphore` + +const tempDir = mochaTsDir +fs.mkdirSync(tempDir, { recursive: true }) + +const usage = `Usage: mocha-ts [options] [spec] + +mocha against ts tests and modules + +Arguments: + spec One or more files, directories, or globs to test (default: + "{src/ts/**/*.spec.ts,test/**/*.ts}") + +Options: + -w, --watch run in watch mode. Since mocha only supports CJS in watch + mode. This option implies -cjs as well (default: false) + -cjs, --commonjs run tests against the CJS bundle instead of the ESM one + (default: false) + -h, --help display help for command + +` + +function parse () { + const args = process.argv.slice(2) + + const help = getBooleanOption(args, '--help', '-h') + if (help) { + console.log(usage) + process.exit() + } + + const requiredFile = getOption(args, '--require') + + const watch = getBooleanOption(args, '--watch', '-w') + + const commonjs = getBooleanOption(args, '--commonjs', '-cjs') + if (commonjs === false && watch === true) { + console.log('ERROR: mocha in watch mode only supports commonjs') + console.log(usage) + process.exit(1) + } + + let testsGlob = (args.pop() ?? '').replace(/^['"]/, '').replace(/['"]$/, '') // Let us remove surrounding quotes in string (it gives issues in windows) + if (testsGlob === '') { + testsGlob = '{src/ts/**/*.spec.ts,test/**/*.ts}' + } + + const mochaArgs = [] + + if (requiredFile !== '') { + mochaArgs.push('--require') + mochaArgs.push(requiredFile) + } + mochaArgs.push('--require') + mochaArgs.push('build/testing/mocha/mocha-init.cjs') + + if (watch) { + mochaArgs.push('-w') + mochaArgs.push('--watch-files') + mochaArgs.push(semaphorePath) + } + + if (testsGlob.substring(0, 1) === '-') { + console.log(usage) + process.exit(9) + } + let filenames = [] + try { + filenames = glob.sync(testsGlob, { cwd: rootDir, matchBase: true }) + } catch (error) {} + if (filenames.length === 0) { + console.error('invalid or empty glob pattern: ' + testsGlob) + console.log() + console.log(usage) + process.exit(9) + } + + const testFiles = [] + const jsTestFiles = [] + + if (filenames.length > 0) { + filenames.forEach(file => { + const isTsTestFile = minimatch(file, '{test/**/*.ts,src/**/*.spec.ts}', { matchBase: true }) + if (isTsTestFile) { + testFiles.push(file) + const extension = commonjs ? 'cjs' : 'js' + jsTestFiles.push(`${mochaTsRelativeDir}/${file.slice(0, -3)}.${extension}`) + } + }) + } + mochaArgs.push(...jsTestFiles) + + return { + mochaArgs, + testFiles, + commonjs + } +} + +const processedArgs = parse() +const commonjs = processedArgs.commonjs +const testFiles = processedArgs.testFiles +const mochaArgs = processedArgs.mochaArgs + +// prepare setup for mocha (it should be written to a JSON file that will be loaded by the mocha-init.cjs) +const mochaSetup = { + testFiles, + commonjs +} +fs.writeFileSync(path.join(tempDir, 'testSetup.json'), JSON.stringify(mochaSetup, undefined, 2), { encoding: 'utf-8' }) + +if (commonjs) { + console.log('\x1b[33mℹ [mocha-ts] Running tests against the CommonJS module \x1b[0m\n') +} else { + console.log('\x1b[33mℹ [mocha-ts] Running tests against the ESM module \x1b[0m\n') +} + +const rollupBuilder = require('../testing/mocha/builders/RollupBuilder.cjs').rollupBuilder + +rollupBuilder.start({ commonjs, watch: false }).then(() => { + rollupBuilder.close() + const testsBuilder = require('../testing/mocha/builders/TestsBuilder.cjs').testBuilder + testsBuilder.start({ commonjs, testFiles }).then(() => { + testsBuilder.close() + // Now run mocha + runScript(path.join(rootDir, 'node_modules/mocha/bin/mocha'), mochaArgs) + }) +}) + +function getBooleanOption (args, ...optionNames) { + let found = false + optionNames.forEach((option) => { + const index = args.indexOf(option) + if (index > -1) { + found = true + args.splice(index, 1) + } + }) + return found +} + +function getOption (args, option) { + const index = args.indexOf(option) + if (index > -1 && index < args.length - 2) { + return args.splice(index, 2)[1] + } + return '' +} diff --git a/build/bin/mocha-ts.js b/build/bin/mocha-ts.js deleted file mode 100644 index c6961eb..0000000 --- a/build/bin/mocha-ts.js +++ /dev/null @@ -1,79 +0,0 @@ -#! /usr/bin/env node -import { join, resolve } from 'path' -import { fork } from 'child_process' -import minimatch from 'minimatch' -import glob from 'glob' -import { fileURLToPath } from 'url' -const { sync } = glob - -const __dirname = resolve(fileURLToPath(import.meta.url), '../') -const rootDir = join(__dirname, '../..') - -const mochaTsRelativeDir = '.mocha-ts' - -// First let us prepare the args to pass to mocha. -// ts.files will be replaced by their js-transpiled counterparts -// a watch file to our semaphore will be added -const processedArgs = processArgs(process.argv.slice(2)) - -// Now we can run a script and invoke a callback when complete, e.g. -runScript(join(rootDir, 'node_modules/mocha/bin/mocha'), processedArgs) - -function processArgs (args) { - args = process.argv.slice(2).map(arg => { - // Let us first remove surrounding quotes in string (it gives issues in windows) - arg = arg.replace(/^['"]/, '').replace(/['"]$/, '') - const filenames = sync(arg, { cwd: rootDir, matchBase: true }) - if (filenames.length > 0) { - return filenames.map(file => { - const isTsTestFile = minimatch(file, '{test/**/*.ts,src/**/*.spec.ts}', { matchBase: true }) - if (isTsTestFile) { - return `${mochaTsRelativeDir}/${file.slice(0, -3)}.js` - } - return file - }) - } - return arg - }) - - const processedArgs = [] - - let addSemaphore = false - let semaphoreAdded = false - for (const arg of args) { - if (Array.isArray(arg)) { - processedArgs.push(...arg) - } else { - processedArgs.push(arg) - if (arg === '--watch' || arg === '-w') { - addSemaphore = true - } else if (arg === '--watch-files') { - processedArgs.push(`${mochaTsRelativeDir}/semaphore`) - semaphoreAdded = true - } - } - } - if (addSemaphore === true || semaphoreAdded === false) { - processedArgs.push('--watch-files') - processedArgs.push(`${mochaTsRelativeDir}/semaphore`) - } - - return processedArgs -} - -function runScript (scriptPath, args) { - const mochaCmd = fork(scriptPath, args, { - cwd: rootDir - }) - - mochaCmd.on('error', (error) => { - throw error - }) - - // execute the callback once the process has finished running - mochaCmd.on('exit', function (code) { - if (code !== 0) { - throw new Error('exit code ' + code) - } - }) -} diff --git a/build/build.docs.cjs b/build/build.docs.cjs index 197fde9..5db44d1 100644 --- a/build/build.docs.cjs +++ b/build/build.docs.cjs @@ -3,7 +3,9 @@ const fs = require('fs') const TypeDoc = require('typedoc') const path = require('path') +const json5 = require('json5') const pkgJson = require('../package.json') +const rimraf = require('rimraf') const rootDir = path.join(__dirname, '..') @@ -14,15 +16,25 @@ function camelise (str) { }) } +const tsConfigPath = path.join(rootDir, 'tsconfig.json') +const tempTsConfigPath = path.join(rootDir, '.tsconfig.json') + async function typedoc () { const app = new TypeDoc.Application() + // prepare tsconfig + const tsConfig = json5.parse(fs.readFileSync(tsConfigPath, 'utf8')) + tsConfig.include = ['src/ts/**/*', 'build/typings/**/*.d.ts'] + tsConfig.exclude = ['src/**/*.spec.ts'] + fs.writeFileSync(tempTsConfigPath, JSON.stringify(tsConfig, undefined, 2)) + // If you want TypeDoc to load tsconfig.json / typedoc.json files app.options.addReader(new TypeDoc.TSConfigReader()) app.options.addReader(new TypeDoc.TypeDocReader()) app.bootstrap({ // typedoc options here + tsconfig: tempTsConfigPath, entryPoints: ['src/ts/index.ts'], plugin: ['typedoc-plugin-markdown'], includeVersion: true, @@ -84,7 +96,7 @@ if (repoProvider) { iifeBundle = `[IIFE bundle](https://raw.githubusercontent.com/${repoUsername}/${repoName}/master/${iifeBundlePath})` esmBundle = `[ESM bundle](https://raw.githubusercontent.com/${repoUsername}/${repoName}/master/${esmBundlePath})` umdBundle = `[UMD bundle](https://raw.githubusercontent.com/${repoUsername}/${repoName}/master/${umdBundlePath})` - workflowBadget = `[![Node.js CI](https://github.com/${repoUsername}/${repoName}/workflows/build/badge.svg)](https://github.com/${repoUsername}/${repoName}/actions?query=workflow%3A%22build%22)` + workflowBadget = `[![Node.js CI](https://github.com/${repoUsername}/${repoName}/actions/workflows/build-and-test.yml/badge.svg)](https://github.com/${repoUsername}/${repoName}/actions/workflows/build-and-test.yml)` coverallsBadge = `[![Coverage Status](https://coveralls.io/repos/github/${repoUsername}/${repoName}/badge.svg?branch=master)](https://coveralls.io/github/${repoUsername}/${repoName}?branch=master)` break @@ -117,3 +129,5 @@ const readmeFile = path.join(rootDir, 'README.md') fs.writeFileSync(readmeFile, template) typedoc() + +rimraf.sync(tempTsConfigPath) diff --git a/build/rollup.config.js b/build/rollup.config.js index ee22fe5..77fa866 100644 --- a/build/rollup.config.js +++ b/build/rollup.config.js @@ -52,7 +52,7 @@ function compileDts () { } export default [ - { // ESM for browsers and declarations + { // Browser ESM bundle input: input, output: [ { @@ -102,11 +102,6 @@ export default [ } ], plugins: [ - replace({ - 'await import(': 'require(', - delimiters: ['', ''], - preventAssignment: true - }), replace({ IS_BROWSER: true, preventAssignment: true @@ -150,7 +145,7 @@ export default [ json() ] }, - { // Node ESM + { // Node ESM and type declarations input: input, output: [ { diff --git a/build/run-script.cjs b/build/run-script.cjs new file mode 100644 index 0000000..a09e482 --- /dev/null +++ b/build/run-script.cjs @@ -0,0 +1,26 @@ +const childProcess = require('child_process') + +const rootDir = require('path').join(__dirname, '../') + +function runScript (scriptPath, args) { + return new Promise((resolve, reject) => { + const cmd = childProcess.fork(scriptPath, args, { + cwd: rootDir + }) + + cmd.on('error', (error) => { + reject(error) + }) + + // execute the callback once the process has finished running + cmd.on('exit', function (code) { + if (code !== 0) { + const error = new Error('exit code ' + code) + reject(error) + } + resolve() + }) + }) +} + +module.exports = runScript diff --git a/build/testing/browser/index.cjs b/build/testing/browser/index.cjs index 3ad5a5f..6453247 100644 --- a/build/testing/browser/index.cjs +++ b/build/testing/browser/index.cjs @@ -29,11 +29,11 @@ const browserTests = async ( } if (ignore) return - let text = (message.args().length > 0) ? message.args()[0]._remoteObject.value : message.text() + let text = (message.args().length > 0) ? message.args()[0].remoteObject().value : message.text() const args = [] if (message.args() !== undefined && message.args().length > 1) { for (let i = 1; i < message.args().length; i++) { - args.push(message.args()[i]._remoteObject.value) + args.push(message.args()[i].remoteObject().value) } } diff --git a/build/testing/browser/server.cjs b/build/testing/browser/server.cjs index d777eeb..a0ca662 100644 --- a/build/testing/browser/server.cjs +++ b/build/testing/browser/server.cjs @@ -13,6 +13,7 @@ const multi = require('@rollup/plugin-multi-entry') const typescriptPlugin = require('@rollup/plugin-typescript') const commonjs = require('@rollup/plugin-commonjs') const json = require('@rollup/plugin-json') +const runScript = require('../../run-script.cjs') const rootDir = path.join(__dirname, '..', '..', '..') @@ -40,10 +41,6 @@ const indexHtml = ` timeout: 90000 }) -