diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index ed9f9cc1..00000000 --- a/.eslintignore +++ /dev/null @@ -1 +0,0 @@ -coverage \ No newline at end of file diff --git a/.eslintrc b/.eslintrc deleted file mode 100644 index 41b7cbeb..00000000 --- a/.eslintrc +++ /dev/null @@ -1,10 +0,0 @@ -{ - "extends": ["airbnb-base", "prettier"], - "plugins": ["prettier"], - "rules": { - "strict": [0, "global"], - "class-methods-use-this": [0], - "no-restricted-syntax": [0], - "default-param-last": [0] - } -} diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..6313b56c --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +* text=auto eol=lf diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 2af82353..f8f20f0f 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -1,4 +1,10 @@ -name: Release and Publish +name: Publish + +permissions: + contents: write # to be able to publish a GitHub release + issues: write # to be able to comment on released issues + pull-requests: write # to be able to comment on released pull requests + id-token: write # to enable use of OIDC for npm provenance on: push: @@ -9,28 +15,24 @@ on: - next jobs: - test: + publish: runs-on: ubuntu-latest steps: - - name: Checkout code - uses: actions/checkout@v4 + - uses: actions/checkout@v4 - - name: Setup Node.js - uses: actions/setup-node@v4 + - uses: actions/setup-node@v4 with: node-version: 20 - - name: Install dependencies - run: npm install + - run: npm install + + - run: npm run lint - - name: Lint files - run: npm run lint + - run: npm run types - - name: Run tests - run: npm run test:ci + - run: npm run test:ci - - name: Run semantic release - run: npx semantic-release + - run: npx semantic-release env: SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index fa652b00..f89c73f5 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,4 +1,4 @@ -name: Run Lint and Tests +name: Test on: push: @@ -9,7 +9,7 @@ on: - next jobs: - build: + test: strategy: matrix: os: [ubuntu-latest, macOS-latest] #, windows-latest] @@ -20,16 +20,14 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4 + - uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} - - name: Install dependencies - run: npm install + - run: npm install - - name: Lint files - run: npm run lint + - run: npm run lint - - name: Run tests - run: npm run test:ci + - run: npm run types + + - run: npm run test:ci diff --git a/.gitignore b/.gitignore index 70ef54df..036de040 100644 --- a/.gitignore +++ b/.gitignore @@ -14,4 +14,6 @@ coverage .vscode .eikrc test/.eik -test-read-json.json \ No newline at end of file +test-read-json.json +types/ +.tap \ No newline at end of file diff --git a/.npmrc b/.npmrc index 43c97e71..0ca8d2a0 100644 --- a/.npmrc +++ b/.npmrc @@ -1 +1,2 @@ package-lock=false +save-exact=true diff --git a/CHANGELOG.md b/CHANGELOG.md index 008f58ca..a7b2b956 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,166 @@ +# [3.0.0-next.1](https://github.com/eik-lib/cli/compare/v2.0.39...v3.0.0-next.1) (2024-08-06) + + +### Bug Fixes + +* add jsdoc for publish commands as well ([a2b51c8](https://github.com/eik-lib/cli/commit/a2b51c86fe10ab84aa21e07151007fdc723e36c4)) +* include type definitions for programatic API ([96d6079](https://github.com/eik-lib/cli/commit/96d6079145198f5df3cd353952e9bac4d530031d)) +* update boxen, chalk and ora ([73a200f](https://github.com/eik-lib/cli/commit/73a200f20a59edc69abc5fb3d8760fbf2630b0c1)) +* update date-fns ([0b32270](https://github.com/eik-lib/cli/commit/0b322700cd62e73052eef42016658931c27202c2)) +* update Eik common to v4.0.0 ([1078484](https://github.com/eik-lib/cli/commit/107848440a11eac4cc5b49a33fb172bffe43e1d9)) +* update gzip-size ([6075766](https://github.com/eik-lib/cli/commit/6075766b9a3c60f91b7d64374e9396b87fb9294c)) +* update make-dir ([8d9c939](https://github.com/eik-lib/cli/commit/8d9c939449e0adfd8bed33d517f8e219d6790a74)) +* update rimraf ([3e40b11](https://github.com/eik-lib/cli/commit/3e40b11b527c722f4ecf51872f0b09d82eef034b)) +* update ssri package ([944426a](https://github.com/eik-lib/cli/commit/944426add01481af20232410b3d86fc983b73da8)) +* update tar package ([41c8227](https://github.com/eik-lib/cli/commit/41c8227578b166682c00c6dd841bcb972f475433)) +* update to Eik common v4.0.1 ([fb69c35](https://github.com/eik-lib/cli/commit/fb69c35c085266571d2352a60ebe9c9783e21d46)) + + +### chore + +* convert codebase to ESM ([f3c4c74](https://github.com/eik-lib/cli/commit/f3c4c746cc3ac283d0f8e493682af34086831f51)) + + +### Code Refactoring + +* remove eik v alias ([80ac9b6](https://github.com/eik-lib/cli/commit/80ac9b62a2cc7d53fd4e5dbbbd983efc490214bd)) + + +### Features + +* add alias command as an eventual replacement for the 3 existing alias commands ([ff4a27c](https://github.com/eik-lib/cli/commit/ff4a27cc8e46f55321a6c814d23a111737eba29d)) +* add eik --version and eik -v ali flags to list eik cli version ([5ddd162](https://github.com/eik-lib/cli/commit/5ddd16245a3285d9ebd002aa35d96557d50c2bd5)) +* init reads name and version from package.json ([6effb76](https://github.com/eik-lib/cli/commit/6effb768a7c2ec5110d935201960d9d872abff48)) +* support specifying a config file using --config or -c cli flags ([a78b9de](https://github.com/eik-lib/cli/commit/a78b9de9f8f8e7e64bcdf24e649e0c27ea6eec1f)) + + +### BREAKING CHANGES + +* eik v command is no longer an alias for eik version +* JavaScript API is now ESM only and no longer supports CJS + +# [3.0.0-next.1](https://github.com/eik-lib/cli/compare/v2.0.39...v3.0.0-next.1) (2024-08-06) + + +### Bug Fixes + +* add jsdoc for publish commands as well ([a2b51c8](https://github.com/eik-lib/cli/commit/a2b51c86fe10ab84aa21e07151007fdc723e36c4)) +* include type definitions for programatic API ([96d6079](https://github.com/eik-lib/cli/commit/96d6079145198f5df3cd353952e9bac4d530031d)) +* update boxen, chalk and ora ([73a200f](https://github.com/eik-lib/cli/commit/73a200f20a59edc69abc5fb3d8760fbf2630b0c1)) +* update date-fns ([0b32270](https://github.com/eik-lib/cli/commit/0b322700cd62e73052eef42016658931c27202c2)) +* update gzip-size ([6075766](https://github.com/eik-lib/cli/commit/6075766b9a3c60f91b7d64374e9396b87fb9294c)) +* update make-dir ([8d9c939](https://github.com/eik-lib/cli/commit/8d9c939449e0adfd8bed33d517f8e219d6790a74)) +* update rimraf ([3e40b11](https://github.com/eik-lib/cli/commit/3e40b11b527c722f4ecf51872f0b09d82eef034b)) +* update ssri package ([944426a](https://github.com/eik-lib/cli/commit/944426add01481af20232410b3d86fc983b73da8)) +* update tar package ([41c8227](https://github.com/eik-lib/cli/commit/41c8227578b166682c00c6dd841bcb972f475433)) + + +### chore + +* convert codebase to ESM ([f3c4c74](https://github.com/eik-lib/cli/commit/f3c4c746cc3ac283d0f8e493682af34086831f51)) + + +### Code Refactoring + +* remove eik v alias ([80ac9b6](https://github.com/eik-lib/cli/commit/80ac9b62a2cc7d53fd4e5dbbbd983efc490214bd)) + + +### Features + +* add alias command as an eventual replacement for the 3 existing alias commands ([ff4a27c](https://github.com/eik-lib/cli/commit/ff4a27cc8e46f55321a6c814d23a111737eba29d)) +* add eik --version and eik -v ali flags to list eik cli version ([5ddd162](https://github.com/eik-lib/cli/commit/5ddd16245a3285d9ebd002aa35d96557d50c2bd5)) + + +### BREAKING CHANGES + +* eik v command is no longer an alias for eik version +* JavaScript API is now ESM only and no longer supports CJS + +# [3.0.0-next.1](https://github.com/eik-lib/cli/compare/v2.0.39...v3.0.0-next.1) (2024-08-04) + + +### Bug Fixes + +* add jsdoc for publish commands as well ([a2b51c8](https://github.com/eik-lib/cli/commit/a2b51c86fe10ab84aa21e07151007fdc723e36c4)) +* include type definitions for programatic API ([96d6079](https://github.com/eik-lib/cli/commit/96d6079145198f5df3cd353952e9bac4d530031d)) +* update boxen, chalk and ora ([73a200f](https://github.com/eik-lib/cli/commit/73a200f20a59edc69abc5fb3d8760fbf2630b0c1)) +* update date-fns ([0b32270](https://github.com/eik-lib/cli/commit/0b322700cd62e73052eef42016658931c27202c2)) +* update gzip-size ([6075766](https://github.com/eik-lib/cli/commit/6075766b9a3c60f91b7d64374e9396b87fb9294c)) +* update make-dir ([8d9c939](https://github.com/eik-lib/cli/commit/8d9c939449e0adfd8bed33d517f8e219d6790a74)) +* update rimraf ([3e40b11](https://github.com/eik-lib/cli/commit/3e40b11b527c722f4ecf51872f0b09d82eef034b)) +* update ssri package ([944426a](https://github.com/eik-lib/cli/commit/944426add01481af20232410b3d86fc983b73da8)) +* update tar package ([41c8227](https://github.com/eik-lib/cli/commit/41c8227578b166682c00c6dd841bcb972f475433)) + + +### chore + +* convert codebase to ESM ([f3c4c74](https://github.com/eik-lib/cli/commit/f3c4c746cc3ac283d0f8e493682af34086831f51)) + + +### Features + +* add alias command as an eventual replacement for the 3 existing alias commands ([ff4a27c](https://github.com/eik-lib/cli/commit/ff4a27cc8e46f55321a6c814d23a111737eba29d)) + + +### BREAKING CHANGES + +* JavaScript API is now ESM only and no longer supports CJS + +# [3.0.0-next.1](https://github.com/eik-lib/cli/compare/v2.0.39...v3.0.0-next.1) (2024-08-01) + + +### Bug Fixes + +* add jsdoc for publish commands as well ([a2b51c8](https://github.com/eik-lib/cli/commit/a2b51c86fe10ab84aa21e07151007fdc723e36c4)) +* include type definitions for programatic API ([96d6079](https://github.com/eik-lib/cli/commit/96d6079145198f5df3cd353952e9bac4d530031d)) +* update boxen, chalk and ora ([73a200f](https://github.com/eik-lib/cli/commit/73a200f20a59edc69abc5fb3d8760fbf2630b0c1)) +* update date-fns ([0b32270](https://github.com/eik-lib/cli/commit/0b322700cd62e73052eef42016658931c27202c2)) +* update gzip-size ([6075766](https://github.com/eik-lib/cli/commit/6075766b9a3c60f91b7d64374e9396b87fb9294c)) +* update make-dir ([8d9c939](https://github.com/eik-lib/cli/commit/8d9c939449e0adfd8bed33d517f8e219d6790a74)) +* update rimraf ([3e40b11](https://github.com/eik-lib/cli/commit/3e40b11b527c722f4ecf51872f0b09d82eef034b)) +* update ssri package ([944426a](https://github.com/eik-lib/cli/commit/944426add01481af20232410b3d86fc983b73da8)) +* update tar package ([41c8227](https://github.com/eik-lib/cli/commit/41c8227578b166682c00c6dd841bcb972f475433)) + + +### chore + +* convert codebase to ESM ([f3c4c74](https://github.com/eik-lib/cli/commit/f3c4c746cc3ac283d0f8e493682af34086831f51)) + + +### BREAKING CHANGES + +* JavaScript API is now ESM only and no longer supports CJS + +# [3.0.0-next.1](https://github.com/eik-lib/cli/compare/v2.0.39...v3.0.0-next.1) (2024-08-01) + + +### Bug Fixes + +* add jsdoc for publish commands as well ([a2b51c8](https://github.com/eik-lib/cli/commit/a2b51c86fe10ab84aa21e07151007fdc723e36c4)) +* include type definitions for programatic API ([96d6079](https://github.com/eik-lib/cli/commit/96d6079145198f5df3cd353952e9bac4d530031d)) + + +### chore + +* convert codebase to ESM ([f3c4c74](https://github.com/eik-lib/cli/commit/f3c4c746cc3ac283d0f8e493682af34086831f51)) + + +### BREAKING CHANGES + +* JavaScript API is now ESM only and no longer supports CJS + +# [3.0.0-next.1](https://github.com/eik-lib/cli/compare/v2.0.39...v3.0.0-next.1) (2024-07-31) + + +### chore + +* convert codebase to ESM ([f3c4c74](https://github.com/eik-lib/cli/commit/f3c4c746cc3ac283d0f8e493682af34086831f51)) + + +### BREAKING CHANGES + +* JavaScript API is now ESM only and no longer supports CJS + ## [2.0.39](https://github.com/eik-lib/cli/compare/v2.0.38...v2.0.39) (2024-07-29) diff --git a/classes/alias.js b/classes/alias.js index 071a116f..41d3acfa 100644 --- a/classes/alias.js +++ b/classes/alias.js @@ -1,14 +1,39 @@ -'use strict'; +import assert from 'assert'; +import abslog from 'abslog'; +import { join } from 'path'; +import { schemas, validators } from '@eik/common'; +import { request } from '../utils/http/index.js'; +import { typeSlug } from '../utils/index.js'; -const assert = require('assert'); -const abslog = require('abslog'); -const { join } = require('path'); -const { schemas, validators } = require('@eik/common'); -const { request } = require('../utils/http'); -const { typeSlug } = require('../utils'); +/** + * @typedef {object} AliasOptions + * @property {import('abslog').AbstractLoggerOptions} [logger] + * @property {string} server + * @property {"package" | "npm" | "map"} [type="package"] + * @property {string} name + * @property {string} version + * @property {string} alias + * @property {string} token + */ -module.exports = class Alias { - constructor({ logger, server, token, type, name, version, alias } = {}) { +/** + * @typedef {object} AliasResult + * @property {string} server + * @property {string} type + * @property {string} name + * @property {string} alias + * @property {string} version + * @property {boolean} update + * @property {string[]} files + * @property {string} org + * @property {string} integrity + */ + +export default class Alias { + /** + * @param {AliasOptions} options + */ + constructor({ logger, server, token, type, name, version, alias }) { this.log = abslog(logger); this.server = server; this.token = token; @@ -18,6 +43,9 @@ module.exports = class Alias { this.version = version; } + /** + * @returns {Promise} + */ async run() { const data = { server: this.server, @@ -121,4 +149,4 @@ module.exports = class Alias { } } } -}; +} diff --git a/classes/index.js b/classes/index.js index 631d3ffe..d9932dc3 100644 --- a/classes/index.js +++ b/classes/index.js @@ -1,44 +1,68 @@ -'use strict'; - -const Ping = require('./ping'); -const Alias = require('./alias'); -const Meta = require('./meta'); -const Login = require('./login'); -const PublishMap = require('./publish/map'); -const PublishPackage = require('./publish/package/index'); -const Integrity = require('./integrity'); -const Version = require('./version'); - -module.exports = { - ping(opts) { - return new Ping(opts).run(); - }, +import Ping from './ping.js'; +import Alias from './alias.js'; +import Meta from './meta.js'; +import Login from './login.js'; +import PublishMap from './publish/map.js'; +import PublishPackage from './publish/package/index.js'; +import Integrity from './integrity.js'; +import Version from './version.js'; +export default { + /** + * @param {import('./alias.js').AliasOptions} opts + */ alias(opts) { return new Alias(opts).run(); }, - meta(opts) { - return new Meta(opts).run(); + /** + * @param {import('./integrity.js').IntegrityOptions} opts + */ + integrity(opts) { + return new Integrity(opts).run(); }, + /** + * Log in using a key to get a Bearer token for use with other commands. + * + * @param {import('./login.js').LoginOptions} opts + */ login(opts) { return new Login(opts).run(); }, - integrity(opts) { - return new Integrity(opts).run(); + /** + * @param {import('./publish/map.js').PublishMapOptions} opts + */ + map(opts) { + return new PublishMap(opts).run(); }, - version(opts) { - return new Version(opts).run(); + /** + * @param {import('./meta.js').MetaOptions} opts + */ + meta(opts) { + return new Meta(opts).run(); }, + /** + * @param {import('./ping.js').PingOptions} opts + */ + ping(opts) { + return new Ping(opts).run(); + }, + + /** + * @param {import('./publish/package/index.js').PublishOptions} opts + */ publish(opts) { return new PublishPackage(opts).run(); }, - map(opts) { - return new PublishMap(opts).run(); + /** + * @param {import('./version.js').VersionOptions} opts + */ + version(opts) { + return new Version(opts).run(); }, }; diff --git a/classes/integrity.js b/classes/integrity.js index 784018c3..d6ae95f6 100644 --- a/classes/integrity.js +++ b/classes/integrity.js @@ -1,15 +1,26 @@ -/* eslint-disable no-await-in-loop */ -/* eslint-disable no-plusplus */ - -'use strict'; - -const abslog = require('abslog'); -const { join } = require('path'); -const { schemas, ValidationError } = require('@eik/common'); -const fetch = require('node-fetch'); -const { typeSlug } = require('../utils'); - -module.exports = class Integrity { +import abslog from 'abslog'; +import { join } from 'path'; +import eik from '@eik/common'; +import { typeSlug } from '../utils/index.js'; + +const { schemas } = eik; + +/** + * @typedef {object} IntegrityOptions + * @property {import('abslog').AbstractLoggerOptions} [logger] + * @property {string} server + * @property {"package" | "npm" | "map"} [type="package"] + * @property {string} name + * @property {string} version + * @property {string} [cwd] + * @property {boolean} [debug] + */ + +export default class Integrity { + /** + * + * @param {IntegrityOptions} options + */ constructor({ logger, name, @@ -18,7 +29,7 @@ module.exports = class Integrity { type, debug = false, cwd = process.cwd(), - } = {}) { + }) { this.log = abslog(logger); this.server = server; this.name = name; @@ -46,12 +57,18 @@ module.exports = class Integrity { this.log.debug(` ==> debug: ${this.debug}`); if (typeof this.debug !== 'boolean') { - throw new ValidationError(`Parameter "debug" is not valid`); + // @ts-expect-error + throw new schemas.ValidationError( + `Parameter "debug" is not valid`, + ); } this.log.debug(` ==> cwd: ${this.cwd}`); if (typeof this.cwd !== 'string') { - throw new ValidationError(`Parameter "cwd" is not valid`); + // @ts-expect-error + throw new schemas.ValidationError( + `Parameter "cwd" is not valid`, + ); } } catch (err) { throw new Error( @@ -93,4 +110,4 @@ module.exports = class Integrity { ); } } -}; +} diff --git a/classes/login.js b/classes/login.js index 0dabe73a..efa66793 100644 --- a/classes/login.js +++ b/classes/login.js @@ -1,23 +1,37 @@ -'use strict'; +import abslog from 'abslog'; +import eik from '@eik/common'; +import { request } from '../utils/http/index.js'; -const abslog = require('abslog'); -const { schemas, ValidationError } = require('@eik/common'); -const { request } = require('../utils/http'); +const { schemas } = eik; -module.exports = class Login { - constructor({ logger, server, key } = {}) { +/** + * @typedef {object} LoginOptions + * @property {import('abslog').AbstractLoggerOptions} [logger] + * @property {string} server + * @property {string} key + */ + +export default class Login { + /** + * @param {LoginOptions} options + */ + constructor({ logger, server, key }) { this.log = abslog(logger); this.server = server; this.key = key; } + /** + * @returns {Promise} Bearer token, or false if login fails + */ async run() { this.log.debug('Validating input'); try { schemas.assert.server(this.server); if (!this.key || typeof !this.key === 'string') { - throw new ValidationError('"key" must be a string'); + // @ts-expect-error + throw new schemas.ValidationError('"key" must be a string'); } } catch (err) { this.log.error(err.message); @@ -46,4 +60,4 @@ module.exports = class Login { } } } -}; +} diff --git a/classes/meta.js b/classes/meta.js index 8a2f8d97..6d510215 100644 --- a/classes/meta.js +++ b/classes/meta.js @@ -1,23 +1,31 @@ -/* eslint-disable no-await-in-loop */ -/* eslint-disable no-plusplus */ - -'use strict'; - -const abslog = require('abslog'); -const { join } = require('path'); -const { schemas } = require('@eik/common'); -const fetch = require('node-fetch'); +import abslog from 'abslog'; +import { join } from 'path'; +import { schemas } from '@eik/common'; const types = ['pkg', 'map', 'npm']; -module.exports = class Meta { - constructor({ logger, server, name, version } = {}) { +/** + * @typedef {object} MetaOptions + * @property {import('abslog').AbstractLoggerOptions} [logger] + * @property {string} server + * @property {string} name + * @property {string} version + */ + +export default class Meta { + /** + * @param {MetaOptions} options + */ + constructor({ logger, server, name, version }) { this.log = abslog(logger); this.server = server; this.name = name; this.version = version; } + /** + * @returns {Promise} + */ async run() { this.log.debug('Validating input'); @@ -90,4 +98,4 @@ module.exports = class Meta { return false; } } -}; +} diff --git a/classes/ping.js b/classes/ping.js index 01a9cd9c..010d3d03 100644 --- a/classes/ping.js +++ b/classes/ping.js @@ -1,15 +1,25 @@ -'use strict'; - -const fetch = require('node-fetch'); -const abslog = require('abslog'); -const { schemas } = require('@eik/common'); - -module.exports = class Ping { +import abslog from 'abslog'; +import { schemas } from '@eik/common'; + +/** + * @typedef {object} PingOptions + * @property {string} [server] + * @property {import('abslog').AbstractLoggerOptions} [logger] + */ + +export default class Ping { + /** + * @param {PingOptions} options + */ constructor({ logger, server } = {}) { this.log = abslog(logger); this.server = server; } + /** + * Run the ping command + * @returns {Promise} + */ async run() { this.log.debug('Validating input'); @@ -22,10 +32,11 @@ module.exports = class Ping { this.log.debug('Requesting ping from server'); try { - const result = await fetch(this.server); + const result = await fetch(/** @type {string}*/ (this.server)); if (!result.ok) { const err = new Error('Ping unsuccessful'); + // @ts-expect-error err.statusCode = result.status; throw err; } @@ -48,4 +59,4 @@ module.exports = class Ping { } } } -}; +} diff --git a/classes/publish/map.js b/classes/publish/map.js index b43e122b..485b9b7c 100644 --- a/classes/publish/map.js +++ b/classes/publish/map.js @@ -1,13 +1,33 @@ -'use strict'; +import assert from 'assert'; +import abslog from 'abslog'; +import { join, parse, isAbsolute } from 'path'; +import { existsSync } from 'fs'; +import { schemas } from '@eik/common'; +import { request } from '../../utils/http/index.js'; -const assert = require('assert'); -const abslog = require('abslog'); -const { join, parse, isAbsolute } = require('path'); -const { existsSync } = require('fs'); -const { schemas } = require('@eik/common'); -const { request } = require('../../utils/http'); +/** + * @typedef {object} PublishMapOptions + * @property {import('abslog').AbstractLoggerOptions} [logger] + * @property {string} server + * @property {string} [cwd] + * @property {string} token + * @property {string} file + * @property {string} name + * @property {string} version + */ -module.exports = class PublishMap { +/** + * @typedef {object} PublishMapResult + * @property {string} server + * @property {string} name + * @property {string} version + * @property {string} type + */ + +export default class PublishMap { + /** + * @param {PublishMapOptions} options + */ constructor({ logger, cwd = process.cwd(), @@ -16,7 +36,7 @@ module.exports = class PublishMap { file, name, version, - } = {}) { + }) { this.log = abslog(logger); this.cwd = cwd; this.server = server; @@ -26,6 +46,9 @@ module.exports = class PublishMap { this.file = file; } + /** + * @returns {Promise} + */ async run() { this.log.debug('Running import map publish command'); @@ -93,4 +116,4 @@ module.exports = class PublishMap { } } } -}; +} diff --git a/classes/publish/package/index.js b/classes/publish/package/index.js index c92ad5fe..0fe37c6c 100644 --- a/classes/publish/package/index.js +++ b/classes/publish/package/index.js @@ -1,20 +1,52 @@ -'use strict'; +import abslog from 'abslog'; +import { join, isAbsolute } from 'path'; +import { EikConfig } from '@eik/common'; +import { typeSlug } from '../../../utils/index.js'; +import ValidateInput from './tasks/validate-input.js'; +import CreateTempDirectory from './tasks/create-temp-directory.js'; +import CreateZipFile from './tasks/create-zip-file.js'; +import CheckBundleSizes from './tasks/check-bundle-sizes.js'; +import DryRun from './tasks/dry-run.js'; +import CheckIfAlreadyPublished from './tasks/check-if-already-published.js'; +import UploadFiles from './tasks/upload-files.js'; +import SaveMetafile from './tasks/save-metafile.js'; +import Cleanup from './tasks/cleanup.js'; -const abslog = require('abslog'); -const { join, isAbsolute } = require('path'); -const { EikConfig } = require('@eik/common'); -const { typeSlug } = require('../../../utils'); -const ValidateInput = require('./tasks/validate-input'); -const CreateTempDirectory = require('./tasks/create-temp-directory'); -const CreateZipFile = require('./tasks/create-zip-file'); -const CheckBundleSizes = require('./tasks/check-bundle-sizes'); -const DryRun = require('./tasks/dry-run'); -const CheckIfAlreadyPublished = require('./tasks/check-if-already-published'); -const UploadFiles = require('./tasks/upload-files'); -const SaveMetafile = require('./tasks/save-metafile'); -const Cleanup = require('./tasks/cleanup'); +/** + * @typedef {object} PublishOptions + * @property {import('abslog').AbstractLoggerOptions} [logger] + * @property {string} [cwd] + * @property {string} token + * @property {boolean} [dryRun=false] + * @property {string} server + * @property {"package" | "map" | "npm"} [type="package"] + * @property {string} name + * @property {string} [version="1.0.0"] + * @property {string[]} [map] + * @property {string} [out="./.eik"] + * @property {Record} files + */ -module.exports = class Publish { +/** + * @typedef {object} PublishResult + * @property {string} type + * @property {string} server + * @property {string} name + * @property {unknown} level + * @property {boolean} dryRun + * @property {string} integrity + * @property {unknown} created + * @property {unknown} author + * @property {string} org + * @property {string} version + * @property {unknown} response + * @property {Array<{ pathname: string; type: string; }>} files + */ + +export default class Publish { + /** + * @param {PublishOptions} options + */ constructor({ logger, cwd = process.cwd(), @@ -27,7 +59,7 @@ module.exports = class Publish { map = [], out = './.eik', files = {}, - } = {}) { + }) { const config = new EikConfig( { server, @@ -84,6 +116,9 @@ module.exports = class Publish { }); } + /** + * @returns {Promise} + */ async run() { this.log.debug(`Running package command against server`); this.log.debug(` ==> package name: ${this.config.name}`); @@ -102,6 +137,7 @@ module.exports = class Publish { type: typeSlug(this.config.type), server: this.config.server, name: this.config.name, + // @ts-expect-error Not sure where this.level originated level: this.level, dryRun: this.dryRun, integrity: '', @@ -122,6 +158,7 @@ module.exports = class Publish { type: typeSlug(this.config.type), server: this.config.server, name: this.config.name, + // @ts-expect-error Not sure where this.level originated level: this.level, dryRun: this.dryRun, created: null, @@ -131,4 +168,4 @@ module.exports = class Publish { ...response, }; } -}; +} diff --git a/classes/publish/package/tasks/check-bundle-sizes.js b/classes/publish/package/tasks/check-bundle-sizes.js index e7a5edf3..b7e388b1 100644 --- a/classes/publish/package/tasks/check-bundle-sizes.js +++ b/classes/publish/package/tasks/check-bundle-sizes.js @@ -1,13 +1,9 @@ -/* eslint-disable no-await-in-loop */ +import bytes from 'bytes'; +import fs from 'fs'; +import { gzipSizeSync } from 'gzip-size'; +import Task from './task.js'; -'use strict'; - -const bytes = require('bytes'); -const fs = require('fs'); -const gzipSize = require('gzip-size'); -const Task = require('./task'); - -module.exports = class CheckBundleSizes extends Task { +export default class CheckBundleSizes extends Task { async process() { this.log.debug('Checking bundle file sizes'); try { @@ -17,7 +13,7 @@ module.exports = class CheckBundleSizes extends Task { ` ==> entrypoint size (${ mapping.source.destination } => ${file}): ${bytes( - gzipSize.sync(fs.readFileSync(file, 'utf8')), + gzipSizeSync(fs.readFileSync(file, 'utf8')), )}`, ); } @@ -25,4 +21,4 @@ module.exports = class CheckBundleSizes extends Task { throw new Error(`Failed to check bundle sizes: ${err.message}`); } } -}; +} diff --git a/classes/publish/package/tasks/check-if-already-published.js b/classes/publish/package/tasks/check-if-already-published.js index 09c78262..7baf7f62 100644 --- a/classes/publish/package/tasks/check-if-already-published.js +++ b/classes/publish/package/tasks/check-if-already-published.js @@ -1,14 +1,10 @@ -/* eslint-disable no-param-reassign */ +import { join } from 'path'; +import { integrity, versions } from '../../../../utils/http/index.js'; +import hash from '../../../../utils/hash/index.js'; +import { typeSlug } from '../../../../utils/index.js'; +import Task from './task.js'; -'use strict'; - -const { join } = require('path'); -const { integrity, versions } = require('../../../../utils/http'); -const hash = require('../../../../utils/hash'); -const { typeSlug } = require('../../../../utils'); -const Task = require('./task'); - -module.exports = class CheckIfAlreadyPublished extends Task { +export default class CheckIfAlreadyPublished extends Task { async process() { const { log, path } = this; const { server, name, version, files, type } = this.config; @@ -69,6 +65,7 @@ module.exports = class CheckIfAlreadyPublished extends Task { ); } + // @ts-expect-error const versionMap = new Map(pkgVersions); for (const v of versionMap.values()) { const same = hash.compare(v.integrity, localHash); @@ -84,4 +81,4 @@ module.exports = class CheckIfAlreadyPublished extends Task { return localHash; } -}; +} diff --git a/classes/publish/package/tasks/cleanup.js b/classes/publish/package/tasks/cleanup.js index 5ebe4243..46e6e71c 100644 --- a/classes/publish/package/tasks/cleanup.js +++ b/classes/publish/package/tasks/cleanup.js @@ -1,11 +1,9 @@ -'use strict'; +import { join } from 'path'; +import fs from 'fs'; +import { rimrafSync } from 'rimraf'; +import Task from './task.js'; -const { join } = require('path'); -const fs = require('fs'); -const rimraf = require('rimraf'); -const Task = require('./task'); - -module.exports = class Cleanup extends Task { +export default class Cleanup extends Task { async process() { const { log, path } = this; log.debug('Cleaning up'); @@ -13,7 +11,7 @@ module.exports = class Cleanup extends Task { if (fs.existsSync(path)) { fs.readdirSync(path) .filter((file) => file !== 'integrity.json') - .forEach((file) => rimraf.sync(join(path, file))); + .forEach((file) => rimrafSync(join(path, file))); } } -}; +} diff --git a/classes/publish/package/tasks/create-temp-directory.js b/classes/publish/package/tasks/create-temp-directory.js index df28cf32..25e782cd 100644 --- a/classes/publish/package/tasks/create-temp-directory.js +++ b/classes/publish/package/tasks/create-temp-directory.js @@ -1,9 +1,5 @@ -/* eslint-disable max-classes-per-file */ - -'use strict'; - -const mkdir = require('make-dir'); -const Task = require('./task'); +import { makeDirectorySync } from 'make-dir'; +import Task from './task.js'; class IOError extends Error { constructor(message, err) { @@ -13,7 +9,7 @@ class IOError extends Error { } } -module.exports = class CreateTempDir extends Task { +export default class CreateTempDir extends Task { async process() { const { log, path } = this; @@ -21,9 +17,9 @@ module.exports = class CreateTempDir extends Task { log.debug(` ==> ${path}`); try { - mkdir.sync(path); + makeDirectorySync(path); } catch (err) { throw new IOError('Unable to create temp dir', err); } } -}; +} diff --git a/classes/publish/package/tasks/create-zip-file.js b/classes/publish/package/tasks/create-zip-file.js index e5b85526..ef2b2136 100644 --- a/classes/publish/package/tasks/create-zip-file.js +++ b/classes/publish/package/tasks/create-zip-file.js @@ -1,16 +1,11 @@ -/* eslint-disable no-plusplus */ -/* eslint-disable no-await-in-loop */ - -'use strict'; - -const fs = require('fs'); -const { join, resolve, basename, dirname } = require('path'); -const tar = require('tar'); -const Task = require('./task'); +import fs from 'fs'; +import { join, resolve, basename, dirname } from 'path'; +import * as tar from 'tar'; +import Task from './task.js'; const { copyFileSync, writeFileSync } = fs; -module.exports = class CreateZipFile extends Task { +export default class CreateZipFile extends Task { async process() { const { log, path } = this; const { name, map, server, out, files } = this.config; @@ -80,4 +75,4 @@ module.exports = class CreateZipFile extends Task { throw new Error(`Unable to create zip file: ${err.message}`); } } -}; +} diff --git a/classes/publish/package/tasks/dry-run.js b/classes/publish/package/tasks/dry-run.js index 23e83494..bb9e5fdb 100644 --- a/classes/publish/package/tasks/dry-run.js +++ b/classes/publish/package/tasks/dry-run.js @@ -1,11 +1,7 @@ -/* eslint-disable no-param-reassign */ +import { join } from 'path'; +import Task from './task.js'; -'use strict'; - -const { join } = require('path'); -const Task = require('./task'); - -module.exports = class DryRun extends Task { +export default class DryRun extends Task { async process(zipFile) { const { path } = this; @@ -23,4 +19,4 @@ module.exports = class DryRun extends Task { return files; } -}; +} diff --git a/classes/publish/package/tasks/save-metafile.js b/classes/publish/package/tasks/save-metafile.js index f5184be2..6a7db422 100644 --- a/classes/publish/package/tasks/save-metafile.js +++ b/classes/publish/package/tasks/save-metafile.js @@ -1,10 +1,8 @@ -'use strict'; +import { join } from 'path'; +import json from '../../../../utils/json/index.js'; +import Task from './task.js'; -const { join } = require('path'); -const json = require('../../../../utils/json'); -const Task = require('./task'); - -module.exports = class SaveMetaFile extends Task { +export default class SaveMetaFile extends Task { async process(response) { const { log, cwd } = this; const { out } = this.config; @@ -19,4 +17,4 @@ module.exports = class SaveMetaFile extends Task { ); } } -}; +} diff --git a/classes/publish/package/tasks/task.js b/classes/publish/package/tasks/task.js index 7188fcad..904bcfa3 100644 --- a/classes/publish/package/tasks/task.js +++ b/classes/publish/package/tasks/task.js @@ -1,12 +1,10 @@ -'use strict'; +import abslog from 'abslog'; -const abslog = require('abslog'); - -module.exports = class Task { +export default class Task { constructor(options) { this.cwd = options.cwd; this.log = abslog(options.logger); this.path = options.path; this.config = options.config; } -}; +} diff --git a/classes/publish/package/tasks/upload-files.js b/classes/publish/package/tasks/upload-files.js index d3c5459f..ef33d8ae 100644 --- a/classes/publish/package/tasks/upload-files.js +++ b/classes/publish/package/tasks/upload-files.js @@ -1,13 +1,9 @@ -/* eslint-disable no-param-reassign */ +import { join } from 'path'; +import { request } from '../../../../utils/http/index.js'; +import { typeSlug } from '../../../../utils/index.js'; +import Task from './task.js'; -'use strict'; - -const { join } = require('path'); -const { request } = require('../../../../utils/http'); -const { typeSlug } = require('../../../../utils'); -const Task = require('./task'); - -module.exports = class UploadFiles extends Task { +export default class UploadFiles extends Task { async process(zipFile) { const { log } = this; const { server, name, version, type, token } = this.config; @@ -62,4 +58,4 @@ module.exports = class UploadFiles extends Task { } } } -}; +} diff --git a/classes/publish/package/tasks/validate-input.js b/classes/publish/package/tasks/validate-input.js index 1f8accc4..54ea1a90 100644 --- a/classes/publish/package/tasks/validate-input.js +++ b/classes/publish/package/tasks/validate-input.js @@ -1,9 +1,5 @@ -/* eslint-disable max-classes-per-file */ - -'use strict'; - -const { parse } = require('path'); -const Task = require('./task'); +import { parse } from 'path'; +import Task from './task.js'; class ValidationError extends Error { constructor(message, err) { @@ -15,7 +11,7 @@ class ValidationError extends Error { } } -module.exports = class ValidateInput extends Task { +export default class ValidateInput extends Task { process() { const { log } = this; const { cwd, dryRun } = this.config; @@ -34,4 +30,4 @@ module.exports = class ValidateInput extends Task { throw new ValidationError('Parameter "dryRun" is not valid'); } } -}; +} diff --git a/classes/version.js b/classes/version.js index b7f77e5e..49e94341 100644 --- a/classes/version.js +++ b/classes/version.js @@ -1,18 +1,31 @@ -/* eslint-disable max-classes-per-file */ - -'use strict'; - -const { copyFileSync, writeFileSync } = require('fs'); -const { join, isAbsolute, parse } = require('path'); -const abslog = require('abslog'); -const semver = require('semver'); -const mkdir = require('make-dir'); -const { schemas, EikConfig } = require('@eik/common'); -const { integrity } = require('../utils/http'); -const hash = require('../utils/hash'); -const { typeSlug } = require('../utils'); - -module.exports = class Version { +import { copyFileSync, writeFileSync } from 'fs'; +import { join, isAbsolute, parse } from 'path'; +import abslog from 'abslog'; +import semver from 'semver'; +import { makeDirectorySync } from 'make-dir'; +import { schemas, EikConfig } from '@eik/common'; +import { integrity } from '../utils/http/index.js'; +import hash from '../utils/hash/index.js'; +import { typeSlug } from '../utils/index.js'; + +/** + * @typedef {object} VersionOptions + * @property {import('abslog').AbstractLoggerOptions} [logger] + * @property {string} server + * @property {"package" | "npm" | "map"} [type="package"] + * @property {string} name + * @property {string} version + * @property {import("semver").ReleaseType} [level="patch"] + * @property {string} cwd + * @property {string[]} [map] + * @property {string} [out="./.eik"] + * @property {string | Record} files + */ + +export default class Version { + /** + * @param {VersionOptions} options + */ constructor({ logger, server, @@ -24,7 +37,7 @@ module.exports = class Version { map = [], out = './.eik', files, - } = {}) { + }) { const config = new EikConfig( { server, @@ -45,6 +58,10 @@ module.exports = class Version { this.level = level; } + /** + * Similar to `npm version`, but updates `eik.json` + * @returns {Promise} The new version number, or null if the versioning failed + */ async run() { const { name, server, type, version, cwd, out, files, map } = this.config; @@ -59,6 +76,7 @@ module.exports = class Version { log.debug(` ==> level: ${level}`); if (!['major', 'minor', 'patch'].includes(level)) { + // @ts-expect-error throw new schemas.ValidationError( 'Parameter "version" is not valid', ); @@ -66,11 +84,13 @@ module.exports = class Version { log.debug(` ==> files: ${JSON.stringify(files)}`); if (!files) { + // @ts-expect-error throw new schemas.ValidationError('Parameter "files" is not valid'); } log.debug(` ==> map: ${JSON.stringify(map)}`); if (!Array.isArray(map)) { + // @ts-expect-error throw new schemas.ValidationError('Parameter "map" is not valid'); } @@ -103,7 +123,7 @@ module.exports = class Version { let localHash; try { - mkdir.sync(path); + makeDirectorySync(path); const eikPathDest = join(path, './eik.json'); const eikJSON = { name, @@ -157,4 +177,4 @@ module.exports = class Version { log.debug(` ==> ${newVersion}`); return newVersion; } -}; +} diff --git a/commands/alias.js b/commands/alias.js new file mode 100644 index 00000000..5d76e3ad --- /dev/null +++ b/commands/alias.js @@ -0,0 +1,105 @@ +import ora from 'ora'; +import semver from 'semver'; +import Alias from '../classes/alias.js'; +import { logger, getDefaults } from '../utils/index.js'; +import { Alias as AliasFormatter } from '../formatters/index.js'; + +export const command = 'alias [name] [version] [alias]'; + +export const aliases = ['a']; + +export const describe = `Create or update a semver major alias for a package, NPM package or import map as identified by its name and version. A package with the given name and version must already exist on the Eik server. The alias should be the semver major part of the package version. Eg. for a package of version 5.4.3, you should use 5 as the alias. The alias type (npm, map, package) is detected from eik.json in the current working directory.`; + +export const builder = (yargs) => { + const defaults = getDefaults(yargs.argv.config || yargs.argv.cwd); + + yargs + .positional('name', { + describe: 'Name matching a package or import map on the Eik server', + type: 'string', + // @ts-expect-error + default: defaults.name, + }) + .positional('version', { + describe: 'The version the alias should redirect to', + type: 'string', + // @ts-expect-error + default: defaults.version, + }) + .positional('alias', { + describe: + 'Alias, should be the semver major component of version. Eg. 1.0.0 should be given the alias 1', + type: 'string', + // @ts-expect-error + default: defaults.version ? semver.major(defaults.version) : null, + }); + + yargs.options({ + server: { + alias: 's', + describe: 'Specify location of Eik asset server.', + // @ts-expect-error + default: defaults.server, + }, + type: { + describe: + 'Alter the alias type. Default is detected from eik.json. Valid values are `package`, `npm`, or `map` Eg. --type npm', + // @ts-expect-error + default: defaults.type, + }, + token: { + describe: + 'Provide a jwt token to be used to authenticate with the Eik server.', + default: '', + alias: 't', + }, + }); + + // @ts-expect-error + yargs.default('token', defaults.token, defaults.token ? '######' : ''); + + yargs.example(`eik alias my-app 1.0.0 1`); + yargs.example(`eik alias my-app 1.7.3 1`); + yargs.example(`eik alias my-app 6.3.1 6`); + yargs.example( + `eik alias my-app 6.3.1 6 --server https://assets.myeikserver.com`, + ); + yargs.example(`eik alias my-app 4.2.2 4 --debug`); + yargs.example(`eik alias my-app 4.2.2 4 --type package`); +}; + +export const handler = async (argv) => { + const spinner = ora({ stream: process.stdout }).start('working...'); + let success = false; + const { debug, server, type } = argv; + const log = logger(spinner, debug); + let af; + + try { + const data = await new Alias({ + type, + logger: log, + ...argv, + }).run(); + + // TODO: get rid of this rediculous formatter class idea that past me put here to irk present and future me. + // Smells like DRY silliness + af = new AliasFormatter(data); + + const createdOrUpdated = data.update ? 'Updated' : 'Created'; + log.info( + `${createdOrUpdated} alias for "${type}" "${data.name}". ("${data.version}" => "v${data.alias}")`, + ); + success = true; + } catch (err) { + log.warn(err.message); + } + + spinner.text = ''; + spinner.stopAndPersist(); + if (success) { + af?.format(server); + } else { + process.exit(1); + } +}; diff --git a/commands/index.js b/commands/index.js new file mode 100644 index 00000000..9d578bf3 --- /dev/null +++ b/commands/index.js @@ -0,0 +1,27 @@ +import * as init from './init.js'; +import * as integrity from './integrity.js'; +import * as login from './login.js'; +import * as mapAlias from './map-alias.js'; +import * as map from './map.js'; +import * as meta from './meta.js'; +import * as npmAlias from './npm-alias.js'; +import * as packageAlias from './package-alias.js'; +import * as ping from './ping.js'; +import * as publish from './publish.js'; +import * as version from './version.js'; +import * as alias from './alias.js'; + +export const commands = [ + init, + integrity, + login, + mapAlias, + map, + meta, + npmAlias, + packageAlias, + ping, + publish, + version, + alias, +]; diff --git a/commands/init.js b/commands/init.js index 3fd26dfe..f9300c06 100644 --- a/commands/init.js +++ b/commands/init.js @@ -1,41 +1,28 @@ -'use strict'; +import { join } from 'path'; +import fs from 'fs'; +import ora from 'ora'; +import { logger } from '../utils/index.js'; -const { join } = require('path'); -const fs = require('fs'); -const ora = require('ora'); -const { logger } = require('../utils'); +const command = 'init'; -exports.command = 'init'; +const aliases = ['i']; -exports.aliases = ['i']; +const describe = `Creates an eik.json file and saves it to the current working directory. If package.json exists in the directory its name and version will be used as the default. Override defaults using command line flags.`; -exports.describe = `Creates a new default "eik.json" file and saves it to the current working directory - Override default "eik.json" fields using command line flags --server, --name, --major, --js and --css`; - -exports.builder = (yargs) => { +const builder = (yargs) => { yargs.example('eik init'); yargs.example('eik init --cwd /path/to/dir'); yargs.example( - 'eik init --server https://assets.myserver.com --major 2 --name my-app --js ./scripts.js --css ./styles.css', + 'eik init --server https://assets.myserver.com --version 2.0.0 --name my-app --files "./public"', ); yargs.example('eik init --debug'); yargs.options({ server: { alias: 's', - describe: `Specify asset server field in "eik.json". - This the URL to an Eik asset server - Eg. --server https://assets.myeikserver.com`, + describe: `Specify asset server field in "eik.json". This the URL to an Eik asset server Eg. --server https://assets.myeikserver.com`, default: '', }, - cwd: { - alias: 'c', - describe: `Alter the current working directory - Defaults to the directory where the command is being run. - This affects where the generated "eik.json" file will be saved. - Eg. --cwd /path/to/save/to`, - default: process.cwd(), - }, version: { alias: 'v', describe: `Specify the semver version field in "eik.json". Eg. --version 1.0.0`, @@ -47,59 +34,89 @@ exports.builder = (yargs) => { Eg. --name my-great-app`, default: '', }, - debug: { - describe: 'Logs additional messages during command run', - default: false, - type: 'boolean', - }, }); }; -exports.handler = async (argv) => { - const spinner = ora({ stream: process.stdout }).start('working...'); - const { name, version, server, cwd, debug } = argv; +const handler = async (argv) => { + let { name, version } = argv; + const { server, cwd, debug } = argv; const pathname = join(cwd, './eik.json'); + + const spinner = ora({ stream: process.stdout }).start('working...'); const log = logger(spinner, debug); - let assetFileExists = false; try { - log.debug( - `Checking for existing "eik.json" file in directory (${cwd})`, - ); + log.debug(`Checking for existing ${pathname}`); + + let eikJsonExists = false; try { const st = fs.statSync(pathname); if (st.isFile()) { - assetFileExists = true; + eikJsonExists = true; } } catch (err) { // noop } - - if (assetFileExists) { + if (eikJsonExists) { throw new Error( `An "eik.json" file already exists in directory. File will not be written`, ); } - log.debug(`Writing "eik.json" to directory (${cwd})`); - fs.writeFileSync( - pathname, - JSON.stringify( - { - name, - version, - server, - files: {}, - }, - null, - 2, - ), + if (!name || !version || version === '1.0.0') { + log.debug('Looking for default from package.json'); + try { + let packageJson = fs.readFileSync( + join(cwd, 'package.json'), + 'utf-8', + ); + packageJson = JSON.parse(packageJson); + if (!name) { + name = packageJson.name; + log.debug( + `Using ${name} from package.json as default name`, + ); + } + if (!version || version === '1.0.0') { + version = packageJson.version; + log.debug( + `Using ${version} from package.json as default version`, + ); + } + } catch (e) { + // noop + } + } else { + log.debug(`Got ${name} and ${version}, skipping package.json`); + } + + log.debug(`Writing to ${pathname}`); + + const output = JSON.stringify( + { + $schema: + 'https://raw.githubusercontent.com/eik-lib/common/main/lib/schemas/eikjson.schema.json', + name, + version, + server, + files: './public', + 'import-map': [], + }, + null, + 2, ); + fs.writeFileSync(pathname, output); + + log.info(`Wrote to ${pathname} - log.info(`"eik.json" successfully written to directory`); +${output} + +Read more about configuring Eik on https://eik.dev/docs/reference/eik-json`); } catch (err) { log.warn(err.message); } spinner.text = ''; spinner.stopAndPersist(); }; + +export { command, aliases, describe, builder, handler }; diff --git a/commands/integrity.js b/commands/integrity.js index 209e5981..dd152b7e 100644 --- a/commands/integrity.js +++ b/commands/integrity.js @@ -1,57 +1,38 @@ -/* eslint-disable prefer-template */ -/* eslint-disable no-restricted-properties */ -/* eslint-disable one-var */ +import { join } from 'path'; +import ora from 'ora'; +import Integrity from '../classes/integrity.js'; +import { logger, getDefaults } from '../utils/index.js'; +import json from '../utils/json/index.js'; -'use strict'; +export const command = 'integrity [name] [version]'; -const { join } = require('path'); -const ora = require('ora'); -const { - helpers: { configStore }, -} = require('@eik/common'); -const Integrity = require('../classes/integrity'); -const { logger, getDefaults, getCWD } = require('../utils'); -const json = require('../utils/json'); +export const aliases = ['int']; -exports.command = 'integrity [name] [version]'; +export const describe = `Retrieve file integrity information for package name and version defined in eik.json, then populate integrity.json file with this information`; -exports.aliases = ['int']; - -exports.describe = `Retrieve file integrity information for package name and version defined in eik.json, then populate integrity.json file with this information`; - -exports.builder = (yargs) => { - const cwd = getCWD(); - const defaults = getDefaults(cwd); +export const builder = (yargs) => { + const defaults = getDefaults(yargs.argv.config || yargs.argv.cwd); yargs.options({ server: { alias: 's', describe: 'Specify location of asset server.', + // @ts-expect-error default: defaults.server, }, - debug: { - describe: 'Logs additional messages', - default: false, - type: 'boolean', - }, - cwd: { - alias: 'c', - describe: 'Alter current working directory.', - default: defaults.cwd, - }, }); yargs.example(`eik integrity`); yargs.example(`eik integrity --debug`); }; -exports.handler = async (argv) => { +export const handler = async (argv) => { const spinner = ora({ stream: process.stdout }).start('working...'); let integrity = false; - const { debug, cwd } = argv; + const { debug, cwd, config } = argv; const l = logger(spinner, debug); - const config = configStore.findInDirectory(cwd); - const { name, server, version, type, out } = config; + // @ts-expect-error + const { name, version, server, out, type } = getDefaults(config || cwd); try { integrity = await new Integrity({ diff --git a/commands/login.js b/commands/login.js index f09422dc..ecde18fa 100644 --- a/commands/login.js +++ b/commands/login.js @@ -1,59 +1,44 @@ -'use strict'; +import os from 'os'; +import readline from 'readline'; +import ora from 'ora'; +import Login from '../classes/login.js'; +import { logger, getDefaults } from '../utils/index.js'; +import json from '../utils/json/index.js'; -const homedir = require('os').homedir(); -const readline = require('readline'); -const ora = require('ora'); -const Login = require('../classes/login'); -const { logger, getDefaults, getCWD } = require('../utils'); -const json = require('../utils/json'); +const homedir = os.homedir(); -exports.command = 'login'; +export const command = 'login'; -exports.aliases = []; +export const aliases = []; -exports.describe = `Authenticate against an Eik server and save the returned token to an .eikrc file in the users home directory. - You can specify key and server values to authenticate against using the --key and --server flags which will then bypass login prompts - It is possible to be authenticated against multiple asset servers simultaneously. Simply call "eik login" multiple times.`; +export const describe = `Authenticate against an Eik server and save the returned token to an .eikrc file in the users home directory. You can specify key and server values to authenticate against using the --key and --server flags which will then bypass login prompts. It is possible to be authenticated against multiple asset servers simultaneously. Simply call "eik login" multiple times.`; -exports.builder = (yargs) => { +export const builder = (yargs) => { yargs.example('eik login --server https://assets.myserver.com'); yargs.example( 'eik login --server https://assets.myserver.com --key ######', ); yargs.example('eik login --server https://assets.myserver.com --debug'); - const cwd = getCWD(); - const defaults = getDefaults(cwd); + const defaults = getDefaults(yargs.argv.config || yargs.argv.cwd); yargs.options({ server: { alias: 's', - describe: `Eik server address - Specify location of the Eik asset server to authenticate against. - If an eik.json file is present in the current working directory, the files server value will be used as default. - If no eik.json file is present in the current working directory and this flag is not specified, a prompt will be presented to ask for the server address to be input - Eg. --server https://assets.myeikserver.com`, + describe: `Eik server address. Specify location of the Eik asset server to authenticate against. If an eik.json file is present in the current working directory, the files server value will be used as default. If no eik.json file is present in the current working directory and this flag is not specified, a prompt will be presented to ask for the server address to be input. Eg. --server https://assets.myeikserver.com`, type: 'string', default: defaults.server, }, key: { alias: 'k', - describe: `Login access key. - This is a passkey for a given user account and needs to be configured on the server. - If this flag is not specifed, a prompt will be used to ask for the key to be input. - Eg. --key ########`, + describe: `Login access key. This is a passkey for a given user account and needs to be configured on the server. If this flag is not specifed, a prompt will be used to ask for the key to be input. Eg. --key ########`, type: 'string', default: '', }, - debug: { - describe: 'Logs additional messages', - default: false, - type: 'boolean', - }, }); }; -exports.handler = async (argv) => { +export const handler = async (argv) => { let success = false; const { debug, key, server } = argv; let k = key; @@ -69,8 +54,9 @@ exports.handler = async (argv) => { if (!s) { await new Promise((resolve) => { - rl.question('Enter Eik server address > ', (input) => { + rl?.question('Enter Eik server address > ', (input) => { s = input; + // @ts-expect-error resolve(); }); }); @@ -78,8 +64,9 @@ exports.handler = async (argv) => { if (!k) { await new Promise((resolve) => { - rl.question(`Enter login key for ${s} > `, (input) => { + rl?.question(`Enter login key for ${s} > `, (input) => { k = input; + // @ts-expect-error resolve(); }); }); @@ -92,13 +79,14 @@ exports.handler = async (argv) => { try { const token = await new Login({ logger: logger(spinner, debug), - debug, key: k, server: s, }).run(); if (token) { - const meta = await json.read({ cwd: homedir, filename: '.eikrc' }); + const meta = /** @type {{ tokens: any }} */ ( + await json.read({ cwd: homedir, filename: '.eikrc' }) + ); const tokens = new Map(meta.tokens); tokens.set(s, token); @@ -108,6 +96,7 @@ exports.handler = async (argv) => { success = true; } } catch (err) { + // @ts-expect-error logger.warn(err.message); } diff --git a/commands/map-alias.js b/commands/map-alias.js index 55938582..4502a816 100644 --- a/commands/map-alias.js +++ b/commands/map-alias.js @@ -1,22 +1,18 @@ -'use strict'; +// @deprecated in favor of `alias` command -const ora = require('ora'); -const Alias = require('../classes/alias'); -const { logger, getDefaults, getCWD } = require('../utils'); -const { Alias: AliasFormatter } = require('../formatters'); +import ora from 'ora'; +import Alias from '../classes/alias.js'; +import { logger, getDefaults } from '../utils/index.js'; +import { Alias as AliasFormatter } from '../formatters/index.js'; -exports.command = 'map-alias '; +export const command = 'map-alias '; -exports.aliases = ['ma']; +export const aliases = ['ma']; -exports.describe = `Create a semver major alias for an import map as identified by its name and version. - An import map with the given name and version must already exist on asset server - Alias should be the semver major part of the import map version. - Eg. For an import map of version 5.4.3, you should use 5 as the alias`; +export const describe = `DEPRECATED: This command has been replaced by the alias command and will be removed in a future version. Create a semver major alias for an import map as identified by its name and version. An import map with the given name and version must already exist on asset server. Alias should be the semver major part of the import map version. Eg. For an import map of version 5.4.3, you should use 5 as the alias`; -exports.builder = (yargs) => { - const cwd = getCWD(); - const defaults = getDefaults(cwd); +export const builder = (yargs) => { + const defaults = getDefaults(yargs.argv.config || yargs.argv.cwd); yargs .positional('name', { @@ -36,18 +32,9 @@ exports.builder = (yargs) => { server: { alias: 's', describe: 'Specify location of asset server.', + // @ts-expect-error default: defaults.server, }, - cwd: { - alias: 'c', - describe: 'Alter current working directory.', - default: defaults.cwd, - }, - debug: { - describe: 'Logs additional messages', - default: false, - type: 'boolean', - }, token: { describe: 'Provide a jwt token to be used to authenticate with the Eik server.', @@ -56,6 +43,7 @@ exports.builder = (yargs) => { }, }); + // @ts-expect-error yargs.default('token', defaults.token, defaults.token ? '######' : ''); yargs.example(`eik map-alias my-map 1.0.0 1`); @@ -67,7 +55,7 @@ exports.builder = (yargs) => { yargs.example(`eik map-alias my-map 4.2.2 4 --debug`); }; -exports.handler = async (argv) => { +export const handler = async (argv) => { const spinner = ora({ stream: process.stdout }).start('working...'); let success = false; const { debug, name, version, server } = argv; @@ -102,3 +90,6 @@ exports.handler = async (argv) => { process.exit(1); } }; + +export const deprecated = + '"map-alias" will be removed in a future version. Please use "alias" instead'; diff --git a/commands/map.js b/commands/map.js index 03a22bc8..7329c41b 100644 --- a/commands/map.js +++ b/commands/map.js @@ -1,23 +1,17 @@ -'use strict'; +import { join } from 'path'; +import ora from 'ora'; +import PublishMap from '../classes/publish/map.js'; +import { logger, getDefaults } from '../utils/index.js'; +import { Artifact } from '../formatters/index.js'; -const { join } = require('path'); -const fetch = require('node-fetch'); -const ora = require('ora'); -const PublishMap = require('../classes/publish/map'); -const { logger, getDefaults, getCWD } = require('../utils'); -const { Artifact } = require('../formatters'); +export const command = 'map '; -exports.command = 'map '; +export const aliases = ['m']; -exports.aliases = ['m']; +export const describe = `Upload an import map file to the server under a given name and version. A name/version combination must be unique and a version must be semver compliant. Subsquent published versions must increase. Eg. 1.0.0 1.0.1, 1.1.0, 2.0.0 etc.`; -exports.describe = `Upload an import map file to the server under a given name and version. - A name/version combination must be unique and a version must be semver compliant. - Subsquent published versions must increase. Eg. 1.0.0 1.0.1, 1.1.0, 2.0.0 etc.`; - -exports.builder = (yargs) => { - const cwd = getCWD(); - const defaults = getDefaults(cwd); +export const builder = (yargs) => { + const defaults = getDefaults(yargs.argv.config || yargs.argv.cwd); yargs .positional('name', { @@ -39,18 +33,9 @@ exports.builder = (yargs) => { server: { alias: 's', describe: 'Specify location of asset server.', + // @ts-expect-error default: defaults.server, }, - cwd: { - alias: 'c', - describe: 'Alter current working directory.', - default: defaults.cwd, - }, - debug: { - describe: 'Logs additional messages', - default: false, - type: 'boolean', - }, token: { describe: 'Provide a jwt token to be used to authenticate with the Eik server.', @@ -59,6 +44,7 @@ exports.builder = (yargs) => { }, }); + // @ts-expect-error yargs.default('token', defaults.token, defaults.token ? '######' : ''); yargs.example(`eik map my-map 1.0.0 ./import-map.json`); @@ -68,7 +54,7 @@ exports.builder = (yargs) => { ); }; -exports.handler = async (argv) => { +export const handler = async (argv) => { const spinner = ora({ stream: process.stdout }).start('working...'); const { debug, server, name, version } = argv; diff --git a/commands/meta.js b/commands/meta.js index c103ffe5..91fcf497 100644 --- a/commands/meta.js +++ b/commands/meta.js @@ -1,24 +1,16 @@ -/* eslint-disable prefer-template */ -/* eslint-disable no-restricted-properties */ -/* eslint-disable one-var */ +import ora from 'ora'; +import Meta from '../classes/meta.js'; +import { Artifact } from '../formatters/index.js'; +import { logger, getDefaults } from '../utils/index.js'; -'use strict'; +export const command = 'meta '; -const ora = require('ora'); -const Meta = require('../classes/meta'); -const { Artifact } = require('../formatters'); -const { logger, getDefaults, getCWD } = require('../utils'); +export const aliases = ['show']; -exports.command = 'meta '; +export const describe = `Retrieve meta information by package, map or npm name.If a given name exists in several types (package and map for example), results will be returned and displayed from all matching types`; -exports.aliases = ['show']; - -exports.describe = `Retrieve meta information by package, map or npm name - If a given name exists in several types (package and map for example), results will be returned and displayed from all matching types`; - -exports.builder = (yargs) => { - const cwd = getCWD(); - const defaults = getDefaults(cwd); +export const builder = (yargs) => { + const defaults = getDefaults(yargs.argv.config || yargs.argv.cwd); yargs.positional('name', { describe: @@ -30,18 +22,9 @@ exports.builder = (yargs) => { server: { alias: 's', describe: 'Specify location of asset server.', + // @ts-expect-error default: defaults.server, }, - debug: { - describe: 'Logs additional messages', - default: false, - type: 'boolean', - }, - cwd: { - alias: 'c', - describe: 'Alter current working directory.', - default: defaults.cwd, - }, }); yargs.example(`eik meta lit-html`); @@ -49,13 +32,14 @@ exports.builder = (yargs) => { yargs.example(`eik meta my-app --server https://assets.myeikserver.com`); }; -exports.handler = async (argv) => { +export const handler = async (argv) => { const spinner = ora({ stream: process.stdout }).start('working...'); let meta = false; const { debug, server } = argv; const l = logger(spinner, debug); try { + // @ts-expect-error meta = await new Meta({ logger: l, ...argv }).run(); spinner.text = ''; spinner.stopAndPersist(); diff --git a/commands/npm-alias.js b/commands/npm-alias.js index a5b7dc05..e56d3f16 100644 --- a/commands/npm-alias.js +++ b/commands/npm-alias.js @@ -1,22 +1,18 @@ -'use strict'; +// @deprecated in favor of `alias` command -const ora = require('ora'); -const Alias = require('../classes/alias'); -const { logger, getDefaults, getCWD } = require('../utils'); -const { Alias: AliasFormatter } = require('../formatters'); +import ora from 'ora'; +import Alias from '../classes/alias.js'; +import { logger, getDefaults } from '../utils/index.js'; +import { Alias as AliasFormatter } from '../formatters/index.js'; -exports.command = 'npm-alias '; +export const command = 'npm-alias '; -exports.aliases = ['na', 'dep-alias', 'dependency-alias']; +export const aliases = ['na', 'dep-alias', 'dependency-alias']; -exports.describe = `Create a semver major alias for an NPM package as identified by its name and version. - An NPM package with the given name and version must already exist on the asset server - Alias should be the semver major part of the NPM package version. - Eg. For an NPM package of version 5.4.3, you should use 5 as the alias`; +export const describe = `DEPRECATED: This command has been replaced by the alias command and will be removed in a future version. Create a semver major alias for an NPM package as identified by its name and version. An NPM package with the given name and version must already exist on the asset server. Alias should be the semver major part of the NPM package version. Eg. For an NPM package of version 5.4.3, you should use 5 as the alias`; -exports.builder = (yargs) => { - const cwd = getCWD(); - const defaults = getDefaults(cwd); +export const builder = (yargs) => { + const defaults = getDefaults(yargs.argv.config || yargs.argv.cwd); yargs .positional('name', { @@ -37,18 +33,9 @@ exports.builder = (yargs) => { server: { alias: 's', describe: 'Specify location of asset server.', + // @ts-expect-error default: defaults.server, }, - cwd: { - alias: 'c', - describe: 'Alter current working directory.', - default: defaults.cwd, - }, - debug: { - describe: 'Logs additional messages', - default: false, - type: 'boolean', - }, token: { describe: 'Provide a jwt token to be used to authenticate with the Eik server.', @@ -57,6 +44,7 @@ exports.builder = (yargs) => { }, }); + // @ts-expect-error yargs.default('token', defaults.token, defaults.token ? '######' : ''); yargs.example(`eik npm lit-html 1.0.0 1`); @@ -66,7 +54,7 @@ exports.builder = (yargs) => { ); }; -exports.handler = async (argv) => { +export const handler = async (argv) => { const spinner = ora({ stream: process.stdout }).start('working...'); let success = false; const { debug, server } = argv; @@ -97,3 +85,6 @@ exports.handler = async (argv) => { process.exit(1); } }; + +export const deprecated = + '"npm-alias" will be removed in a future version. Please use "alias" instead'; diff --git a/commands/package-alias.js b/commands/package-alias.js index 4e35486e..9531ff71 100644 --- a/commands/package-alias.js +++ b/commands/package-alias.js @@ -1,40 +1,39 @@ -'use strict'; +// @deprecated in favor of `alias` command -const ora = require('ora'); -const semver = require('semver'); -const Alias = require('../classes/alias'); -const { logger, getDefaults, getCWD } = require('../utils'); -const { Alias: AliasFormatter } = require('../formatters'); +import ora from 'ora'; +import semver from 'semver'; +import Alias from '../classes/alias.js'; +import { logger, getDefaults } from '../utils/index.js'; +import { Alias as AliasFormatter } from '../formatters/index.js'; -exports.command = 'package-alias [name] [version] [alias]'; +export const command = 'package-alias [name] [version] [alias]'; -exports.aliases = ['pkg-alias', 'pa']; +export const aliases = ['pkg-alias', 'pa']; -exports.describe = `Create a semver major alias for a package as identified by its name and version. - A package with the given name and version must already exist on asset server - Alias should be the semver major part of the package version. - Eg. For a package of version 5.4.3, you should use 5 as the alias`; +export const describe = `DEPRECATED: This command has been replaced by the alias command and will be removed in a future version. Create a semver major alias for a package as identified by its name and version. A package with the given name and version must already exist on asset server. Alias should be the semver major part of the package version. Eg. For a package of version 5.4.3, you should use 5 as the alias`; -exports.builder = (yargs) => { - const cwd = getCWD(); - const defaults = getDefaults(cwd); +export const builder = (yargs) => { + const defaults = getDefaults(yargs.argv.config || yargs.argv.cwd); yargs .positional('name', { describe: 'Name matching existing name for a package on Eik server', type: 'string', + // @ts-expect-error default: defaults.name, }) .positional('version', { describe: 'Version matching existing version for a package on Eik server', type: 'string', + // @ts-expect-error default: defaults.version, }) .positional('alias', { describe: 'Alias for a semver version. Must be the semver major component of version. Eg. 1.0.0 should be given as 1', type: 'string', + // @ts-expect-error default: defaults.version ? semver.major(defaults.version) : null, }); @@ -42,18 +41,9 @@ exports.builder = (yargs) => { server: { alias: 's', describe: 'Specify location of Eik asset server.', + // @ts-expect-error default: defaults.server, }, - cwd: { - alias: 'c', - describe: 'Alter the current working directory.', - default: defaults.cwd, - }, - debug: { - describe: 'Logs additional messages', - default: false, - type: 'boolean', - }, token: { describe: 'Provide a jwt token to be used to authenticate with the Eik server.', @@ -62,6 +52,7 @@ exports.builder = (yargs) => { }, }); + // @ts-expect-error yargs.default('token', defaults.token, defaults.token ? '######' : ''); yargs.example(`eik package-alias my-app 1.0.0 1`); @@ -73,7 +64,7 @@ exports.builder = (yargs) => { yargs.example(`eik package-alias my-app 4.2.2 4 --debug`); }; -exports.handler = async (argv) => { +export const handler = async (argv) => { const spinner = ora({ stream: process.stdout }).start('working...'); let success = false; const { debug, server } = argv; @@ -101,8 +92,11 @@ exports.handler = async (argv) => { spinner.text = ''; spinner.stopAndPersist(); if (success) { - af.format(server); + af?.format(server); } else { process.exit(1); } }; + +export const deprecated = + '"package-alias" will be removed in a future version. Please use "alias" instead'; diff --git a/commands/ping.js b/commands/ping.js index 49e099b4..b8b4de85 100644 --- a/commands/ping.js +++ b/commands/ping.js @@ -1,44 +1,35 @@ -'use strict'; +import ora from 'ora'; +import Ping from '../classes/ping.js'; +import { logger, getDefaults } from '../utils/index.js'; -const ora = require('ora'); -const Ping = require('../classes/ping'); -const { logger, getDefaults, getCWD } = require('../utils'); +export const command = 'ping [server]'; -exports.command = 'ping [server]'; +export const aliases = []; -exports.aliases = []; +export const describe = `Ping an Eik server to check that it is responding.`; -exports.describe = `Ping an Eik server to check that it is responding.`; - -exports.builder = (yargs) => { - const cwd = getCWD(); - const defaults = getDefaults(cwd); +export const builder = (yargs) => { + const defaults = getDefaults(yargs.argv.config || yargs.argv.cwd); yargs.positional('server', { describe: 'Specify location of Eik server to ping.', + // @ts-expect-error default: defaults.server, }); - yargs.options({ - debug: { - describe: 'Logs additional messages', - default: false, - type: 'boolean', - }, - }); - yargs.example(`eik ping`); yargs.example(`eik ping http://assets.myeikserver.com`); yargs.example(`eik ping http://assets.myeikserver.com --debug`); }; -exports.handler = async (argv) => { +export const handler = async (argv) => { const spinner = ora({ stream: process.stdout }).start('working...'); const { debug, server } = argv; try { await new Ping({ logger: logger(spinner, debug), server }).run(); } catch (err) { + // @ts-expect-error logger.warn(err.message); } diff --git a/commands/publish.js b/commands/publish.js index 6ffa82da..a093a145 100644 --- a/commands/publish.js +++ b/commands/publish.js @@ -1,39 +1,20 @@ -'use strict'; - -const { join } = require('path'); -const fetch = require('node-fetch'); -const ora = require('ora'); -const chalk = require('chalk'); -const { - helpers: { configStore }, -} = require('@eik/common'); -const PublishPackage = require('../classes/publish/package/index'); -const { - logger, - getDefaults, - getCWD, - typeSlug, - typeTitle, -} = require('../utils'); -const { Artifact } = require('../formatters'); - -exports.command = 'publish'; - -exports.aliases = ['pkg', 'package', 'pub']; - -exports.describe = `Publish an app package to an Eik server. Reads configuration from eik.json or package.json files. See https://eik.dev for more details.`; - -exports.builder = (yargs) => { - const cwd = getCWD(); - const defaults = getDefaults(cwd); +import { join } from 'path'; +import ora from 'ora'; +import chalk from 'chalk'; +import PublishPackage from '../classes/publish/package/index.js'; +import { logger, getDefaults, typeSlug, typeTitle } from '../utils/index.js'; +import { Artifact } from '../formatters/index.js'; + +export const command = 'publish'; + +export const aliases = ['pkg', 'package', 'pub']; + +export const describe = `Publish an app package to an Eik server. Reads configuration from eik.json or package.json files. See https://eik.dev for more details.`; + +export const builder = (yargs) => { + const defaults = getDefaults(yargs.argv.config || yargs.argv.cwd); yargs.options({ - cwd: { - alias: 'c', - describe: 'Alter the current working directory.', - default: defaults.cwd, - type: 'string', - }, dryRun: { alias: 'd', describe: @@ -41,19 +22,14 @@ exports.builder = (yargs) => { default: false, type: 'boolean', }, - debug: { - describe: 'Logs additional messages', - default: false, - type: 'boolean', - }, token: { - describe: `Provide a jwt token to be used to authenticate with the Eik server. - Automatically determined if authenticated (via eik login)`, + describe: `Provide a jwt token to be used to authenticate with the Eik server. Automatically determined if authenticated (via eik login)`, type: 'string', alias: 't', }, }); + // @ts-expect-error yargs.default('token', defaults.token, defaults.token ? '######' : ''); yargs.example(`eik publish`); @@ -63,11 +39,13 @@ exports.builder = (yargs) => { yargs.example(`eik pkg --debug`); }; -exports.handler = async (argv) => { +export const handler = async (argv) => { const spinner = ora({ stream: process.stdout }).start('working...'); - const { debug, dryRun, cwd, token } = argv; - const config = configStore.findInDirectory(cwd); - const { name, server, version, type, map, out, files } = config; + const { debug, dryRun, cwd, token, config } = argv; + // @ts-expect-error + const { name, version, server, map, out, files, type } = getDefaults( + config || cwd, + ); if (type === 'map') { spinner.warn( diff --git a/commands/version.js b/commands/version.js index 6544f699..24c75d8b 100644 --- a/commands/version.js +++ b/commands/version.js @@ -1,25 +1,15 @@ -'use strict'; +import { execSync } from 'child_process'; +import { join } from 'path'; +import ora from 'ora'; +import VersionPackage from '../classes/version.js'; +import { logger, getDefaults } from '../utils/index.js'; +import json from '../utils/json/index.js'; -const { execSync } = require('child_process'); -const { join } = require('path'); -const ora = require('ora'); -const { - helpers: { configStore }, -} = require('@eik/common'); -const VersionPackage = require('../classes/version'); -const { logger, getDefaults, getCWD } = require('../utils'); -const json = require('../utils/json'); +export const command = 'version [level]'; -exports.command = 'version [level]'; - -exports.aliases = ['v']; - -exports.describe = `Compares local files with files on server and increments "version" field in eik.json if necessary.`; - -exports.builder = (yargs) => { - const cwd = getCWD(); - const defaults = getDefaults(cwd); +export const describe = `Compares local files with files on server and increments "version" field in eik.json if necessary.`; +export const builder = (yargs) => { yargs.positional('level', { describe: 'Semver level to increment version by', default: 'patch', @@ -28,12 +18,6 @@ exports.builder = (yargs) => { }); yargs.options({ - cwd: { - alias: 'c', - describe: 'Alter the current working directory.', - default: defaults.cwd, - type: 'string', - }, dryRun: { alias: 'd', describe: @@ -41,23 +25,19 @@ exports.builder = (yargs) => { default: false, type: 'boolean', }, - debug: { - describe: 'Logs additional messages', - default: false, - type: 'boolean', - }, }); yargs.example(`eik version`); yargs.example(`eik version minor`); - yargs.example(`eik v`); }; -exports.handler = async (argv) => { +export const handler = async (argv) => { const spinner = ora({ stream: process.stdout }).start('working...'); - const { level, debug, dryRun, cwd } = argv; - const config = configStore.findInDirectory(cwd); - const { name, version, server, map, out, files } = config; + const { level, debug, dryRun, cwd, config } = argv; + // @ts-expect-error + const { name, version, server, map, out, files } = getDefaults( + config || cwd, + ); try { const log = logger(spinner, debug); @@ -82,6 +62,7 @@ exports.handler = async (argv) => { ); } else { log.debug(`Writing new version ${newVersion} to eik.json`); + // @ts-expect-error await json.writeEik({ version: newVersion }, { cwd }); log.debug(`Committing eik.json to local git repository`); diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 00000000..5617a17d --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,10 @@ +import config from '@eik/eslint-config'; + +export default [ + ...config, + { + rules: { + 'no-unused-vars': 'off', + }, + }, +]; diff --git a/formatters/alias.js b/formatters/alias.js index bd5a7fa7..1e3e0aea 100644 --- a/formatters/alias.js +++ b/formatters/alias.js @@ -1,10 +1,6 @@ -/* eslint-disable no-underscore-dangle */ - -'use strict'; - -const { join } = require('path'); -const chalk = require('chalk'); -const File = require('./file'); +import { join } from 'path'; +import chalk from 'chalk'; +import File from './file.js'; function colorType(type) { if (type === 'npm') { @@ -79,4 +75,4 @@ class Alias { } } -module.exports = Alias; +export default Alias; diff --git a/formatters/artifact.js b/formatters/artifact.js index fb892fca..fda6d507 100644 --- a/formatters/artifact.js +++ b/formatters/artifact.js @@ -1,10 +1,6 @@ -/* eslint-disable no-underscore-dangle */ - -'use strict'; - -const { join } = require('path'); -const chalk = require('chalk'); -const Version = require('./version'); +import { join } from 'path'; +import chalk from 'chalk'; +import Version from './version.js'; const _name = Symbol('name'); const _type = Symbol('type'); @@ -86,4 +82,4 @@ class Artifact { } } -module.exports = Artifact; +export default Artifact; diff --git a/formatters/file.js b/formatters/file.js index 1db62bc6..6bc9f637 100644 --- a/formatters/file.js +++ b/formatters/file.js @@ -1,12 +1,5 @@ -/* eslint-disable no-restricted-properties */ -/* eslint-disable prefer-template */ -/* eslint-disable one-var */ -/* eslint-disable no-underscore-dangle */ - -'use strict'; - -const { join } = require('path'); -const chalk = require('chalk'); +import { join } from 'path'; +import chalk from 'chalk'; function readableBytes(bytes) { const i = Math.floor(Math.log(bytes) / Math.log(1024)), @@ -39,4 +32,4 @@ class File { } } -module.exports = File; +export default File; diff --git a/formatters/index.js b/formatters/index.js index edf3ecb1..32fba67c 100644 --- a/formatters/index.js +++ b/formatters/index.js @@ -1,6 +1,6 @@ -const Artifact = require('./artifact'); -const Alias = require('./alias'); -const File = require('./file'); -const Version = require('./version'); +import Artifact from './artifact.js'; +import Alias from './alias.js'; +import File from './file.js'; +import Version from './version.js'; -module.exports = { Artifact, Alias, Version, File }; +export { Artifact, Alias, Version, File }; diff --git a/formatters/version.js b/formatters/version.js index 8c1132b2..b0c55072 100644 --- a/formatters/version.js +++ b/formatters/version.js @@ -1,14 +1,7 @@ -/* eslint-disable no-restricted-properties */ -/* eslint-disable prefer-template */ -/* eslint-disable one-var */ -/* eslint-disable no-underscore-dangle */ - -'use strict'; - -const { join } = require('path'); -const chalk = require('chalk'); -const formatDistance = require('date-fns/formatDistance'); -const File = require('./file'); +import { join } from 'path'; +import chalk from 'chalk'; +import { formatDistance } from 'date-fns/formatDistance'; +import File from './file.js'; class Version { constructor({ @@ -65,4 +58,4 @@ class Version { } } -module.exports = Version; +export default Version; diff --git a/index.js b/index.js index 66bb4197..0618ce42 100755 --- a/index.js +++ b/index.js @@ -1,14 +1,31 @@ #!/usr/bin/env node +import chalk from 'chalk'; +import yargs from 'yargs'; +import { hideBin } from 'yargs/helpers'; +import boxen from 'boxen'; +import { join } from 'path'; +import { readFileSync } from 'fs'; +import { fileURLToPath } from 'url'; +import { dirname } from 'path'; +import { commands } from './commands/index.js'; -'use strict'; +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); -const chalk = require('chalk'); -const yargs = require('yargs'); -const boxen = require('boxen'); -const { join } = require('path'); -const { readFileSync } = require('fs'); +const { version } = JSON.parse( + readFileSync(join(__dirname, './package.json'), { encoding: 'utf-8' }), +); + +// short circuit and provide a -v and --version flag +if ( + process.argv.includes('-v') || + // last position only to avoid conflict with publish command + process.argv[process.argv.length - 1].includes('--version') +) { + console.log(version); + process.exit(0); +} -const { version } = JSON.parse(readFileSync(join(__dirname, './package.json'))); const greeting = chalk.white.bold(`Eik CLI (v${version})`); const boxenOptions = { @@ -18,26 +35,50 @@ const boxenOptions = { borderColor: 'green', backgroundColor: '#555555', }; +// @ts-expect-error const msgBox = boxen(greeting, boxenOptions); -// eslint-disable-next-line no-console console.log(msgBox); -// eslint-disable-next-line no-unused-expressions -yargs +yargs(hideBin(process.argv)) + .options({ + config: { + alias: 'c', + describe: + 'Provide an exact path to an eik.json or package.json file to use as config. Default is eik.json in the current working directory.', + }, + cwd: { + describe: 'Alter the current working directory.', + default: process.cwd(), + }, + debug: { + describe: 'Logs additional messages', + default: false, + type: 'boolean', + }, + }) + // @ts-expect-error .example('eik init') + // @ts-expect-error .example('eik login --server https://assets.myserver.com --key ######') + // @ts-expect-error .example('eik publish') + // @ts-expect-error .example('eik meta my-app --server https://assets.myserver.com') .example( + // @ts-expect-error 'eik npm-alias lit-html 1.0.0 1 --server https://assets.myserver.com --token ######', ) .example( + // @ts-expect-error 'eik map my-map 1.0.0 ./import-map.json --server https://assets.myserver.com --token ######', ) + // @ts-expect-error .example('eik map-alias my-map 1.0.0 1') - .commandDir('commands') + // @ts-expect-error + .command(commands) .demandCommand() .wrap(150) .version(false) - .help().argv; + .help() + .parse(); diff --git a/package.json b/package.json index 8e723803..d2d7b922 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,10 @@ { "name": "@eik/cli", - "version": "2.0.39", + "version": "3.0.0-next.1", "description": "CLI tool for publishing assets to an Eik server", "main": "./classes/index.js", + "types": "./types/classes/index.d.ts", + "type": "module", "bin": { "eik": "index.js" }, @@ -14,13 +16,15 @@ "commands", "classes", "utils", - "formatters" + "formatters", + "types" ], "scripts": { - "test": "cross-env HTTP_PORT=0 LOG_LEVEL=fatal tap --no-coverage-report --no-cov --timeout 0 --test-regex=.test.mjs --test-ignore=node_modules", - "test:integration": "cross-env HTTP_PORT=0 LOG_LEVEL=fatal tap --no-coverage-report --no-cov --timeout 0 test/integration/**/*.test.mjs", - "test:unit": "cross-env HTTP_PORT=0 LOG_LEVEL=fatal tap --no-coverage-report --no-cov --timeout 0 test/*.test.mjs", - "test:tasks": "cross-env HTTP_PORT=0 LOG_LEVEL=fatal tap --no-coverage-report --no-cov --timeout 0 test/tasks/*.test.mjs", + "clean": "rimraf .tap node_modules types", + "test": "cross-env HTTP_PORT=0 LOG_LEVEL=fatal tap --timeout 0 --disable-coverage test/**/*.test.mjs", + "test:integration": "cross-env HTTP_PORT=0 LOG_LEVEL=fatal tap --timeout 0 --disable-coverage test/integration/**/*.test.mjs", + "test:unit": "cross-env HTTP_PORT=0 LOG_LEVEL=fatal tap --timeout 0 --disable-coverage test/*.test.mjs", + "test:tasks": "cross-env HTTP_PORT=0 LOG_LEVEL=fatal tap --timeout 0 --disable-coverage test/tasks/*.test.mjs", "test:ci:integration": "npm run test:integration -- --jobs=1", "test:ci:unit": "npm run test:unit -- --jobs=1", "test:ci:tasks": "npm run test:tasks -- --jobs=1", @@ -29,47 +33,47 @@ "lint:fix": "eslint --fix .", "format:check": "prettier -c .", "format:fix": "prettier -w .", - "fix": "run-s lint:fix format:fix" + "fix": "run-s lint:fix format:fix", + "types": "run-s types:module types:test", + "types:module": "tsc", + "types:test": "tsc --project tsconfig.test.json" }, "keywords": [], "author": "", "license": "MIT", "dependencies": { - "@eik/common": "^3.0.0", + "@eik/common": "4.0.1", "abslog": "2.4.4", - "boxen": "5.1.2", + "boxen": "8.0.0", "bytes": "3.1.2", - "chalk": "4.1.2", - "date-fns": "2.30.0", + "chalk": "5.3.0", + "date-fns": "3.6.0", "form-data": "4.0.0", - "gzip-size": "6.0.0", - "make-dir": "3.1.0", - "node-fetch": "2.7.0", - "ora": "5.4.1", - "rimraf": "3.0.2", + "gzip-size": "7.0.0", + "make-dir": "5.0.0", + "ora": "8.0.1", + "rimraf": "6.0.1", "semver": "7.6.3", - "ssri": "8.0.1", - "tar": "6.2.1", + "ssri": "10.0.6", + "tar": "7.4.3", "yargs": "17.7.2", "yargs-parser": "21.1.1" }, "devDependencies": { - "@eik/core": "1.2.28", - "@eik/service": "1.2.98", - "@semantic-release/changelog": "6.0.3", - "@semantic-release/git": "10.0.1", + "@eik/eslint-config": "1.0.2", + "@eik/semantic-release-config": "1.0.0", + "@eik/service": "2.1.0", + "@eik/sink-memory": "1.1.1", + "@eik/typescript-config": "1.0.0", "cross-env": "7.0.3", - "eslint": "8.57.0", - "eslint-config-airbnb-base": "15.0.0", - "eslint-config-prettier": "8.10.0", - "eslint-plugin-import": "2.29.1", - "eslint-plugin-prettier": "4.2.1", - "fastify": "3.29.5", - "fs-extra": "10.1.0", - "npm-run-all2": "5.0.2", - "prettier": "2.8.8", - "semantic-release": "19.0.5", - "semantic-release-slack-bot": "3.5.3", - "tap": "15.2.3" + "eslint": "9.8.0", + "fastify": "4.28.1", + "fs-extra": "11.2.0", + "npm-run-all": "4.1.5", + "prettier": "3.3.3", + "semantic-release": "24.0.0", + "semantic-release-slack-bot": "4.0.2", + "tap": "21.0.0", + "typescript": "5.5.4" } } diff --git a/release.config.js b/release.config.js index 877b1721..728dfaa0 100644 --- a/release.config.js +++ b/release.config.js @@ -1,20 +1,6 @@ -module.exports = { +export default { + extends: '@eik/semantic-release-config', plugins: [ - '@semantic-release/commit-analyzer', - '@semantic-release/release-notes-generator', - '@semantic-release/changelog', - [ - '@semantic-release/npm', - { - tarballDir: 'release', - }, - ], - [ - '@semantic-release/github', - { - assets: 'release/*.tgz', - }, - ], [ 'semantic-release-slack-bot', { @@ -53,13 +39,5 @@ module.exports = { ], }, ], - '@semantic-release/git', - ], - preset: 'angular', - branches: [ - { name: 'main' }, - { name: 'alpha', prerelease: true }, - { name: 'beta', prerelease: true }, - { name: 'next', prerelease: true }, ], }; diff --git a/test/alias.test.mjs b/test/alias.test.mjs index 7ccb0847..e5e4d413 100644 --- a/test/alias.test.mjs +++ b/test/alias.test.mjs @@ -1,12 +1,11 @@ import fastify from 'fastify'; import { promises as fs } from 'fs'; import os from 'os'; -import { exec as execCallback } from 'child_process'; import { join, basename } from 'path'; import { mockLogger } from './utils.mjs'; import { test, beforeEach, afterEach } from 'tap'; import EikService from '@eik/service'; -import { sink } from '@eik/core'; +import Sink from '@eik/sink-memory'; import { fileURLToPath } from 'url'; import { dirname } from 'path'; import cli from '../classes/index.js'; @@ -16,7 +15,7 @@ const __dirname = dirname(__filename); beforeEach(async (t) => { const server = fastify({ logger: false }); - const memSink = new sink.MEM(); + const memSink = new Sink(); const service = new EikService({ customSink: memSink }); server.register(service.api()); const address = await server.listen({ diff --git a/test/fixtures/client-with-bare-imports.js b/test/fixtures/client-with-bare-imports.js index aa817d5c..24d1a480 100644 --- a/test/fixtures/client-with-bare-imports.js +++ b/test/fixtures/client-with-bare-imports.js @@ -1,13 +1,8 @@ -/* eslint-disable import/no-unresolved */ - -'use strict'; - +/* eslint-disable no-undef */ +// @ts-nocheck import scrollIntoView from 'scroll-into-view-if-needed'; const main = () => { - // eslint-disable-next-line no-undef - const node = document.getElementById('hero'); - scrollIntoView(node, { scrollMode: 'if-needed', block: 'nearest', diff --git a/test/fixtures/client.js b/test/fixtures/client.js index 6ae893a3..201c57ea 100644 --- a/test/fixtures/client.js +++ b/test/fixtures/client.js @@ -1,5 +1,3 @@ -'use strict'; - const main = () => { const thing = 'this is a test fixture'; return thing; diff --git a/test/integration/alias-legacy.test.mjs b/test/integration/alias-legacy.test.mjs new file mode 100644 index 00000000..e09ea608 --- /dev/null +++ b/test/integration/alias-legacy.test.mjs @@ -0,0 +1,233 @@ +import fastify from 'fastify'; +import { promises as fs } from 'node:fs'; +import os from 'node:os'; +import { exec as execCallback } from 'child_process'; +import { join, basename } from 'node:path'; +import { test, beforeEach, afterEach } from 'tap'; +import EikService from '@eik/service'; +import Sink from '@eik/sink-memory'; +import cli from '../../classes/index.js'; +import { fileURLToPath } from 'url'; +import { dirname } from 'path'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); + +function exec(cmd) { + return new Promise((resolve) => { + execCallback(cmd, (error, stdout, stderr) => { + resolve({ error, stdout, stderr }); + }); + }); +} + +beforeEach(async (t) => { + const server = fastify({ logger: false }); + const memSink = new Sink(); + const service = new EikService({ customSink: memSink }); + server.register(service.api()); + const address = await server.listen({ + host: '127.0.0.1', + port: 0, + }); + const folder = await fs.mkdtemp(join(os.tmpdir(), basename(__filename))); + const eik = join(__dirname, '../../index.js'); + + const token = await cli.login({ + server: address, + key: 'change_me', + }); + + const assets = { + name: 'scroll-into-view-if-needed', + version: '2.2.24', + type: 'npm', + server: address, + files: { + 'index.js': join(__dirname, './../fixtures/client.js'), + 'index.css': join(__dirname, './../fixtures/styles.css'), + }, + }; + + await fs.writeFile(join(folder, 'eik.json'), JSON.stringify(assets)); + + const cmd = `${eik} package --token ${token} --cwd ${folder}`; + await exec(cmd); + + const map = { + imports: { + 'scroll-into-view-if-needed': new URL( + '/npm/scroll-into-view-if-needed/2.2.24/index.js', + address, + ).href, + }, + }; + await fs.writeFile(join(folder, 'import-map.json'), JSON.stringify(map)); + const mapCmd = `${eik} map test-map 1.0.0 import-map.json + --token ${token} + --server ${address} + --cwd ${folder}`; + await exec(mapCmd.split('\n').join(' ')); + + t.context.server = server; + t.context.address = address; + t.context.folder = folder; + t.context.token = token; +}); + +afterEach(async (t) => { + await t.context.server.close(); +}); + +test('eik package-alias ', async (t) => { + const { address, token, folder: cwd } = t.context; + const eik = join(__dirname, '../../index.js'); + + const assets = { + server: address, + name: 'my-pack', + version: '1.0.0', + files: { + 'index.js': join(__dirname, '../fixtures/client.js'), + 'index.css': join(__dirname, '../fixtures/styles.css'), + }, + }; + + await fs.writeFile(join(cwd, 'eik.json'), JSON.stringify(assets)); + + const cmd1 = `${eik} package --token ${token} --cwd ${cwd}`; + await exec(cmd1); + + const cmd2 = `${eik} package-alias my-pack 1.0.0 1 + --token ${token} + --server ${address} + --cwd ${cwd}`; + + const { error, stdout } = await exec(cmd2.split('\n').join(' ')); + + const res = await fetch(new URL('/pkg/my-pack/v1/index.js', address)); + + t.equal(res.ok, true); + t.notOk(error); + t.match(stdout, 'PACKAGE'); + t.match(stdout, 'my-pack'); + t.match(stdout, '1.0.0'); + t.match(stdout, 'v1'); + t.match(stdout, 'NEW'); +}); + +test('eik npm-alias --token --server : no eik.json or .eikrc', async (t) => { + const eik = join(__dirname, '../../index.js'); + const cmd = `${eik} npm-alias scroll-into-view-if-needed 2.2.24 2 + --token ${t.context.token} + --server ${t.context.address} + --cwd ${t.context.folder}`; + + const { error, stdout } = await exec(cmd.split('\n').join(' ')); + + const res = await fetch( + new URL( + '/npm/scroll-into-view-if-needed/v2/index.js', + t.context.address, + ), + ); + + t.equal(res.ok, true); + t.notOk(error); + t.match(stdout, 'NPM'); + t.match(stdout, 'scroll-into-view-if-needed'); + t.match(stdout, '2.2.24'); + t.match(stdout, 'v2'); + t.match(stdout, 'NEW'); + t.end(); +}); + +test('eik npm-alias : publish details provided by eik.json file', async (t) => { + const assets = { + name: 'test-app', + version: '1.0.0', + server: t.context.address, + files: { + 'index.js': join(__dirname, './../fixtures/client.js'), + 'index.css': join(__dirname, './../fixtures/styles.css'), + }, + }; + await fs.writeFile( + join(t.context.folder, 'eik.json'), + JSON.stringify(assets), + ); + const eik = join(__dirname, '../../index.js'); + const cmd = `${eik} npm-alias scroll-into-view-if-needed 2.2.24 2 --token ${t.context.token} --cwd ${t.context.folder}`; + + const { error, stdout } = await exec(cmd); + + const res = await fetch( + new URL( + '/npm/scroll-into-view-if-needed/v2/index.js', + t.context.address, + ), + ); + + t.equal(res.ok, true); + t.notOk(error); + t.match(stdout, 'NPM'); + t.match(stdout, 'scroll-into-view-if-needed'); + t.match(stdout, '2.2.24'); + t.match(stdout, 'v2'); + t.match(stdout, 'NEW'); + t.end(); +}); + +test('eik map-alias --token --server : no eik.json or .eikrc', async (t) => { + const eik = join(__dirname, '../../index.js'); + const cmd = `${eik} map-alias test-map 1.0.0 1 + --token ${t.context.token} + --server ${t.context.address} + --cwd ${t.context.folder}`; + + const { error, stdout } = await exec(cmd.split('\n').join(' ')); + + const res = await fetch(new URL('/map/test-map/v1', t.context.address)); + + t.equal(res.ok, true); + + t.notOk(error); + t.match(stdout, 'MAP'); + t.match(stdout, 'test-map'); + t.match(stdout, '1.0.0'); + t.match(stdout, 'v1'); + t.match(stdout, 'NEW'); + t.end(); +}); + +test('eik map-alias : publish details provided by eik.json file', async (t) => { + const assets = { + name: 'test-app', + version: '1.0.0', + server: t.context.address, + files: { + 'index.js': join(__dirname, './../fixtures/client.js'), + 'index.css': join(__dirname, './../fixtures/styles.css'), + }, + }; + await fs.writeFile( + join(t.context.folder, 'eik.json'), + JSON.stringify(assets), + ); + const eik = join(__dirname, '../../index.js'); + const cmd = `${eik} map-alias test-map 1.0.0 1 --token ${t.context.token} --cwd ${t.context.folder}`; + + const { error, stdout } = await exec(cmd); + + const res = await fetch(new URL('/map/test-map/v1', t.context.address)); + + t.equal(res.ok, true); + + t.notOk(error); + t.match(stdout, 'MAP'); + t.match(stdout, 'test-map'); + t.match(stdout, '1.0.0'); + t.match(stdout, 'v1'); + t.match(stdout, 'NEW'); + t.end(); +}); diff --git a/test/integration/alias.test.mjs b/test/integration/alias.test.mjs index 6b8f7b68..af5a5f0e 100644 --- a/test/integration/alias.test.mjs +++ b/test/integration/alias.test.mjs @@ -1,11 +1,11 @@ import fastify from 'fastify'; import { promises as fs } from 'node:fs'; -import os from 'node:os'; +import os, { type } from 'node:os'; import { exec as execCallback } from 'child_process'; import { join, basename } from 'node:path'; import { test, beforeEach, afterEach } from 'tap'; import EikService from '@eik/service'; -import { sink } from '@eik/core'; +import Sink from '@eik/sink-memory'; import cli from '../../classes/index.js'; import { fileURLToPath } from 'url'; import { dirname } from 'path'; @@ -23,7 +23,7 @@ function exec(cmd) { beforeEach(async (t) => { const server = fastify({ logger: false }); - const memSink = new sink.MEM(); + const memSink = new Sink(); const service = new EikService({ customSink: memSink }); server.register(service.api()); const address = await server.listen({ @@ -79,12 +79,13 @@ afterEach(async (t) => { await t.context.server.close(); }); -test('eik package-alias ', async (t) => { +test('packages: eik alias ', async (t) => { const { address, token, folder: cwd } = t.context; const eik = join(__dirname, '../../index.js'); const assets = { server: address, + type: 'package', name: 'my-pack', version: '1.0.0', files: { @@ -98,7 +99,7 @@ test('eik package-alias ', async (t) => { const cmd1 = `${eik} package --token ${token} --cwd ${cwd}`; await exec(cmd1); - const cmd2 = `${eik} package-alias my-pack 1.0.0 1 + const cmd2 = `${eik} alias my-pack 1.0.0 1 --token ${token} --server ${address} --cwd ${cwd}`; @@ -116,10 +117,11 @@ test('eik package-alias ', async (t) => { t.match(stdout, 'NEW'); }); -test('eik npm-alias --token --server : no eik.json or .eikrc', async (t) => { +test('npm: eik alias --token --server : no eik.json or .eikrc', async (t) => { const eik = join(__dirname, '../../index.js'); const cmd = `${eik} npm-alias scroll-into-view-if-needed 2.2.24 2 --token ${t.context.token} + --type npm --server ${t.context.address} --cwd ${t.context.folder}`; @@ -142,9 +144,10 @@ test('eik npm-alias --token --server : no eik.json or . t.end(); }); -test('eik npm-alias : publish details provided by eik.json file', async (t) => { +test('npm: eik alias : publish details provided by eik.json file', async (t) => { const assets = { name: 'test-app', + type: 'npm', version: '1.0.0', server: t.context.address, files: { @@ -157,7 +160,7 @@ test('eik npm-alias : publish details provided by eik.j JSON.stringify(assets), ); const eik = join(__dirname, '../../index.js'); - const cmd = `${eik} npm-alias scroll-into-view-if-needed 2.2.24 2 --token ${t.context.token} --cwd ${t.context.folder}`; + const cmd = `${eik} alias scroll-into-view-if-needed 2.2.24 2 --token ${t.context.token} --cwd ${t.context.folder}`; const { error, stdout } = await exec(cmd); @@ -178,10 +181,11 @@ test('eik npm-alias : publish details provided by eik.j t.end(); }); -test('eik map-alias --token --server : no eik.json or .eikrc', async (t) => { +test('map: eik alias --token --server : no eik.json or .eikrc', async (t) => { const eik = join(__dirname, '../../index.js'); const cmd = `${eik} map-alias test-map 1.0.0 1 --token ${t.context.token} + --type map --server ${t.context.address} --cwd ${t.context.folder}`; @@ -200,9 +204,10 @@ test('eik map-alias --token --server : no eik.json or . t.end(); }); -test('eik map-alias : publish details provided by eik.json file', async (t) => { +test('map: eik alias : publish details provided by eik.json file', async (t) => { const assets = { name: 'test-app', + type: 'map', version: '1.0.0', server: t.context.address, files: { @@ -215,7 +220,7 @@ test('eik map-alias : publish details provided by eik.j JSON.stringify(assets), ); const eik = join(__dirname, '../../index.js'); - const cmd = `${eik} map-alias test-map 1.0.0 1 --token ${t.context.token} --cwd ${t.context.folder}`; + const cmd = `${eik} alias test-map 1.0.0 1 --token ${t.context.token} --cwd ${t.context.folder}`; const { error, stdout } = await exec(cmd); diff --git a/test/integration/init.test.mjs b/test/integration/init.test.mjs index 4276ae41..e9a1e0ce 100644 --- a/test/integration/init.test.mjs +++ b/test/integration/init.test.mjs @@ -3,7 +3,7 @@ import os from 'os'; import { test } from 'tap'; import { join, basename } from 'path'; import { readFileSync } from 'fs'; -import { exec as execCallback } from 'child_process'; +import { exec as execCallback } from 'node:child_process'; import { fileURLToPath } from 'url'; import { dirname } from 'path'; @@ -11,59 +11,78 @@ const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); function exec(cmd) { - return new Promise((resolve) => { - execCallback(cmd, (error, stdout, stderr) => { - resolve({ error, stdout, stderr }); - }); - }); + return /** @type {Promise} */ ( + new Promise((resolve, reject) => { + execCallback(cmd, (error, stdout, stderr) => { + if (stdout) console.log(stdout); + if (stderr) console.error(stderr); + if (error) reject(error); + resolve(); + }); + }) + ); } test('Initializing a new eik.json file', async (t) => { const eik = join(__dirname, '../../index.js'); const folder = await fs.mkdtemp(join(os.tmpdir(), basename(__filename))); - const publishCmd = `${eik} init --cwd ${folder}`; - await exec(publishCmd); - const assets = JSON.parse(readFileSync(join(folder, 'eik.json'), { encoding: 'utf8' })); + await exec(publishCmd); - t.equal(assets.name, '', 'eik.json "name" field should be empty'); - t.equal( - assets.version, - '1.0.0', - 'eik.json "version" field should equal 1.0.0', + const eikJson = JSON.parse( + readFileSync(join(folder, 'eik.json'), { encoding: 'utf8' }), ); - t.equal(assets.server, '', 'eik.json "server" field should be empty'); - t.same(assets.files, {}, 'eik.json "files" should be an empty object'); + t.ok(eikJson['$schema'], 'eik.json "$schema" field should not be empty'); + t.equal(eikJson.name, '', 'eik.json "name" field should be empty'); + t.equal(eikJson.version, '1.0.0'); + t.equal(eikJson.server, '', 'eik.json "server" field should be empty'); + t.same(eikJson.files, './public'); }); test('Initializing a new eik.json file passing custom values', async (t) => { const eik = join(__dirname, '../../index.js'); const folder = await fs.mkdtemp(join(os.tmpdir(), basename(__filename))); - - const publishCmd = `${eik} init + const publishCmd = `${eik} init --cwd ${folder} --name custom-name --version 2.0.0 --server http://localhost:4001`; - await exec(publishCmd.split('\n').join(' ')); - const assets = JSON.parse(readFileSync(join(folder, 'eik.json'), { encoding: 'utf8' })); + await exec(publishCmd.split('\n').join(' ')); - t.equal( - assets.name, - 'custom-name', - 'eik.json "name" field should not be empty', + const eikJson = JSON.parse( + readFileSync(join(folder, 'eik.json'), { encoding: 'utf8' }), ); - t.equal( - assets.version, - '2.0.0', - 'eik.json "version" field should not be empty', + + t.equal(eikJson.name, 'custom-name'); + t.equal(eikJson.version, '2.0.0'); + t.equal(eikJson.server, 'http://localhost:4001'); + t.same(eikJson.files, './public'); +}); + +test('Initializing a new eik.json file in an existing project', async (t) => { + const eik = join(__dirname, '../../index.js'); + const folder = await fs.mkdtemp(join(os.tmpdir(), basename(__filename))); + + const packageJson = { + name: 'legendary-app', + version: '13.3.7', + }; + + await fs.writeFile( + join(folder, 'package.json'), + JSON.stringify(packageJson, null, 2), + 'utf-8', ); - t.equal( - assets.server, - 'http://localhost:4001', - 'eik.json "server" field should not be empty', + + const publishCmd = `${eik} init --cwd ${folder}`; + await exec(publishCmd); + + const eikJson = JSON.parse( + readFileSync(join(folder, 'eik.json'), { encoding: 'utf8' }), ); - t.same(assets.files, {}, 'eik.json "js.input" field should not be empty'); + + t.equal(eikJson.name, packageJson.name); + t.equal(eikJson.version, packageJson.version); }); diff --git a/test/integration/integrity.test.mjs b/test/integration/integrity.test.mjs index dd1fc1e1..2cbf62bf 100644 --- a/test/integration/integrity.test.mjs +++ b/test/integration/integrity.test.mjs @@ -5,7 +5,7 @@ import { exec as execCallback } from 'child_process'; import { join, basename } from 'path'; import { test, beforeEach, afterEach } from 'tap'; import EikService from '@eik/service'; -import { sink } from '@eik/core'; +import Sink from '@eik/sink-memory'; import cli from '../../classes/index.js'; import { fileURLToPath } from 'url'; import { dirname } from 'path'; @@ -15,14 +15,14 @@ const __dirname = dirname(__filename); function exec(cmd) { return new Promise((resolve) => { - execCallback(cmd, (error, stdout, stderr) => { + execCallback(cmd, (error, stdout, stderr) => { resolve({ error, stdout, stderr }); }); }); } beforeEach(async (t) => { - const memSink = new sink.MEM(); + const memSink = new Sink(); const server = fastify({ logger: false }); const service = new EikService({ customSink: memSink }); server.register(service.api()); diff --git a/test/integration/login.test.mjs b/test/integration/login.test.mjs index b6811c5a..36f545bd 100644 --- a/test/integration/login.test.mjs +++ b/test/integration/login.test.mjs @@ -5,7 +5,7 @@ import { exec as execCallback } from 'child_process'; import { join, basename } from 'path'; import { test, beforeEach, afterEach } from 'tap'; import EikService from '@eik/service'; -import { sink } from '@eik/core'; +import Sink from '@eik/sink-memory'; import { fileURLToPath } from 'url'; import { dirname } from 'path'; @@ -21,7 +21,7 @@ function exec(cmd) { } beforeEach(async (t) => { - const memSink = new sink.MEM(); + const memSink = new Sink(); const server = fastify({ logger: false }); const service = new EikService({ customSink: memSink }); server.register(service.api()); diff --git a/test/integration/map.test.mjs b/test/integration/map.test.mjs index 64d6c882..ca56f686 100644 --- a/test/integration/map.test.mjs +++ b/test/integration/map.test.mjs @@ -4,9 +4,8 @@ import os from 'os'; import { exec as execCallback } from 'child_process'; import { join, basename } from 'path'; import { test, beforeEach, afterEach } from 'tap'; -import fetch from 'node-fetch'; import EikService from '@eik/service'; -import { sink } from '@eik/core'; +import Sink from '@eik/sink-memory'; import cli from '../../classes/index.js'; import { fileURLToPath } from 'url'; import { dirname } from 'path'; @@ -23,7 +22,7 @@ function exec(cmd) { } beforeEach(async (t) => { - const memSink = new sink.MEM(); + const memSink = new Sink(); const server = fastify({ logger: false }); const service = new EikService({ customSink: memSink }); server.register(service.api()); diff --git a/test/integration/meta.test.mjs b/test/integration/meta.test.mjs index aa1a2f4e..eb273b75 100644 --- a/test/integration/meta.test.mjs +++ b/test/integration/meta.test.mjs @@ -5,7 +5,7 @@ import { exec as execCallback } from 'child_process'; import { join, basename } from 'path'; import { test, beforeEach, afterEach } from 'tap'; import EikService from '@eik/service'; -import { sink } from '@eik/core'; +import Sink from '@eik/sink-memory'; import cli from '../../classes/index.js'; import { fileURLToPath } from 'url'; import { dirname } from 'path'; @@ -15,14 +15,14 @@ const __dirname = dirname(__filename); function exec(cmd) { return new Promise((resolve) => { - execCallback(cmd, (error, stdout, stderr) => { + execCallback(cmd, (error, stdout, stderr) => { resolve({ error, stdout, stderr }); }); }); } beforeEach(async (t) => { - const memSink = new sink.MEM(); + const memSink = new Sink(); const server = fastify({ logger: false }); const service = new EikService({ customSink: memSink }); server.register(service.api()); diff --git a/test/integration/package.test.mjs b/test/integration/package.test.mjs index 7cdbd68c..a438dc60 100644 --- a/test/integration/package.test.mjs +++ b/test/integration/package.test.mjs @@ -5,7 +5,7 @@ import { exec as execCallback } from 'child_process'; import { join, basename } from 'path'; import { test, beforeEach, afterEach } from 'tap'; import EikService from '@eik/service'; -import { sink } from '@eik/core'; +import Sink from '@eik/sink-memory'; import cli from '../../classes/index.js'; import { fileURLToPath } from 'url'; import { dirname } from 'path'; @@ -22,7 +22,7 @@ function exec(cmd) { } beforeEach(async (t) => { - const memSink = new sink.MEM(); + const memSink = new Sink(); const server = fastify({ logger: false }); const service = new EikService({ customSink: memSink }); server.register(service.api()); diff --git a/test/integrity.test.mjs b/test/integrity.test.mjs index 6bc58840..6ed68446 100644 --- a/test/integrity.test.mjs +++ b/test/integrity.test.mjs @@ -5,7 +5,7 @@ import { join, basename } from 'path'; import { mockLogger } from './utils.mjs'; import { test, beforeEach, afterEach } from 'tap'; import EikService from '@eik/service'; -import { sink } from '@eik/core'; +import Sink from '@eik/sink-memory'; import { fileURLToPath } from 'url'; import { dirname } from 'path'; import cli from '../classes/index.js'; @@ -15,7 +15,7 @@ const __dirname = dirname(__filename); beforeEach(async (t) => { const server = fastify({ logger: false }); - const memSink = new sink.MEM(); + const memSink = new Sink(); const service = new EikService({ customSink: memSink }); server.register(service.api()); const address = await server.listen({ diff --git a/test/login.test.mjs b/test/login.test.mjs index 27364524..aeb29e57 100644 --- a/test/login.test.mjs +++ b/test/login.test.mjs @@ -5,7 +5,7 @@ import { join, basename } from 'path'; import { mockLogger } from './utils.mjs'; import { test, beforeEach, afterEach } from 'tap'; import EikService from '@eik/service'; -import { sink } from '@eik/core'; +import Sink from '@eik/sink-memory'; import { fileURLToPath } from 'url'; import { dirname } from 'path'; import cli from '../classes/index.js'; @@ -14,7 +14,7 @@ const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); beforeEach(async (t) => { - const memSink = new sink.MEM(); + const memSink = new Sink(); const server = fastify({ logger: false }); const service = new EikService({ customSink: memSink }); server.register(service.api()); diff --git a/test/meta.test.mjs b/test/meta.test.mjs index 8fe80e44..ef005bb7 100644 --- a/test/meta.test.mjs +++ b/test/meta.test.mjs @@ -5,7 +5,7 @@ import { join, basename } from 'path'; import { mockLogger } from './utils.mjs'; import { test, beforeEach, afterEach } from 'tap'; import EikService from '@eik/service'; -import { sink } from '@eik/core'; +import Sink from '@eik/sink-memory'; import { fileURLToPath } from 'url'; import { dirname } from 'path'; import cli from '../classes/index.js'; @@ -15,7 +15,7 @@ const __dirname = dirname(__filename); beforeEach(async (t) => { const server = fastify({ logger: false }); - const memSink = new sink.MEM(); + const memSink = new Sink(); const service = new EikService({ customSink: memSink }); server.register(service.api()); const address = await server.listen({ diff --git a/test/publish-files-definitions.test.mjs b/test/publish-files-definitions.test.mjs index 9816fc3f..81801665 100644 --- a/test/publish-files-definitions.test.mjs +++ b/test/publish-files-definitions.test.mjs @@ -4,7 +4,7 @@ import os from 'os'; import { join, basename } from 'path'; import { test, beforeEach, afterEach } from 'tap'; import EikService from '@eik/service'; -import { sink } from '@eik/core'; +import Sink from '@eik/sink-memory'; import fsExtra from 'fs-extra'; import { fileURLToPath } from 'url'; import { dirname } from 'path'; @@ -25,7 +25,7 @@ const config = (files, server, token, cwd) => ({ }); beforeEach(async (t) => { - const memSink = new sink.MEM(); + const memSink = new Sink(); const server = fastify({ logger: false }); const service = new EikService({ customSink: memSink }); server.register(service.api()); @@ -55,6 +55,7 @@ afterEach(async (t) => { test('when a folder of files is specified as a string', async (t) => { const { address, token, cwd } = t.context; const pattern = 'fixtures/icons'; + // @ts-expect-error const { files } = await cli.publish(config(pattern, address, token, cwd)); t.equal( @@ -63,7 +64,7 @@ test('when a folder of files is specified as a string', async (t) => { 'eik.json file should be at package root', ); t.equal( - files[1].pathname, + files[6].pathname, '/checkbox-sprite-nontouch.svg', 'files should be packaged at package root', ); @@ -72,10 +73,11 @@ test('when a folder of files is specified as a string', async (t) => { test('when a folder of files is specified as a string prefixed by ./', async (t) => { const { address, token, cwd } = t.context; const pattern = './fixtures/icons'; + // @ts-expect-error const { files } = await cli.publish(config(pattern, address, token, cwd)); t.equal( - files[1].pathname, + files[6].pathname, '/checkbox-sprite-nontouch.svg', 'files should be packaged at package root', ); @@ -84,10 +86,11 @@ test('when a folder of files is specified as a string prefixed by ./', async (t) test('when a folder of files is specified as a string postfixed by /', async (t) => { const { address, token, cwd } = t.context; const pattern = './fixtures/icons/'; + // @ts-expect-error const { files } = await cli.publish(config(pattern, address, token, cwd)); t.equal( - files[1].pathname, + files[6].pathname, '/checkbox-sprite-nontouch.svg', 'files should be packaged at package root', ); @@ -96,10 +99,11 @@ test('when a folder of files is specified as a string postfixed by /', async (t) test('when a folder of files is specified with a nested folder mapping', async (t) => { const { address, token, cwd } = t.context; const patter = { 'path/to/folder': './fixtures/icons/' }; + // @ts-expect-error const { files } = await cli.publish(config(patter, address, token, cwd)); t.equal( - files[1].pathname, + files[6].pathname, '/path/to/folder/checkbox-sprite-nontouch.svg', 'files should be packaged at path/to/folder', ); @@ -108,10 +112,11 @@ test('when a folder of files is specified with a nested folder mapping', async ( test('when a folder of files is specified with a nested folder mapping prefixed by ./', async (t) => { const { address, token, cwd } = t.context; const pattern = { './path/to/folder': './fixtures/icons/' }; + // @ts-expect-error const { files } = await cli.publish(config(pattern, address, token, cwd)); t.equal( - files[1].pathname, + files[6].pathname, '/path/to/folder/checkbox-sprite-nontouch.svg', 'files should be packaged at path/to/folder', ); @@ -120,10 +125,11 @@ test('when a folder of files is specified with a nested folder mapping prefixed test('when a folder of files is specified with a nested folder mapping prefixed by /', async (t) => { const { address, token, cwd } = t.context; const pattern = { '/path/to/folder': './fixtures/icons/' }; + // @ts-expect-error const { files } = await cli.publish(config(pattern, address, token, cwd)); t.equal( - files[1].pathname, + files[6].pathname, '/path/to/folder/checkbox-sprite-nontouch.svg', 'files should be packaged at path/to/folder', ); @@ -132,10 +138,11 @@ test('when a folder of files is specified with a nested folder mapping prefixed test('when a folder of files is specified with a nested folder mapping post fixed with /', async (t) => { const { address, token, cwd } = t.context; const patter = { 'path/to/folder/': './fixtures/icons/' }; + // @ts-expect-error const { files } = await cli.publish(config(patter, address, token, cwd)); t.equal( - files[1].pathname, + files[6].pathname, '/path/to/folder/checkbox-sprite-nontouch.svg', 'files should be packaged at path/to/folder', ); @@ -144,6 +151,7 @@ test('when a folder of files is specified with a nested folder mapping post fixe test('when a folder of files is specified as an absolute path string', async (t) => { const { address, token, cwd } = t.context; const pattern = join(__dirname, './fixtures/icons'); + // @ts-expect-error const { files } = await cli.publish(config(pattern, address, token, cwd)); t.equal( @@ -152,7 +160,7 @@ test('when a folder of files is specified as an absolute path string', async (t) 'eik.json file should be at package root', ); t.equal( - files[1].pathname, + files[6].pathname, '/checkbox-sprite-nontouch.svg', 'files should be packaged at package root', ); @@ -163,10 +171,11 @@ test('when a folder of files is specified as an object', async (t) => { const pattern = { '/icons': './fixtures/icons', }; + // @ts-expect-error const { files } = await cli.publish(config(pattern, address, token, cwd)); t.equal( - files[1].pathname, + files[6].pathname, '/icons/checkbox-sprite-nontouch.svg', 'files should be packaged under /icons', ); @@ -177,10 +186,11 @@ test('when a folder of files is specified as an object with absolute path', asyn const pattern = { '/icons': join(__dirname, './fixtures/icons'), }; + // @ts-expect-error const { files } = await cli.publish(config(pattern, address, token, cwd)); t.equal( - files[1].pathname, + files[6].pathname, '/icons/checkbox-sprite-nontouch.svg', 'files should be packaged under /icons', ); @@ -192,6 +202,7 @@ test('when 2 specific file name entries are specified', async (t) => { '/esm.js': './fixtures/client.js', '/esm.css': './fixtures/styles.css', }; + // @ts-expect-error const { files } = await cli.publish(config(pattern, address, token, cwd)); t.equal( @@ -212,6 +223,7 @@ test('when 2 specific file name entries are specified with absolute paths', asyn '/esm.js': join(__dirname, './fixtures/client.js'), '/esm.css': join(__dirname, './fixtures/styles.css'), }; + // @ts-expect-error const { files } = await cli.publish(config(pattern, address, token, cwd)); t.equal( @@ -229,15 +241,16 @@ test('when 2 specific file name entries are specified with absolute paths', asyn test('when a recursive glob is specified', async (t) => { const { address, token, cwd } = t.context; const pattern = 'fixtures/**/*'; + // @ts-expect-error const { files } = await cli.publish(config(pattern, address, token, cwd)); t.equal( - files[2].pathname, + files[4].pathname, '/client.js', 'client.js should be packaged at /', ); t.equal( - files[3].pathname, + files[11].pathname, '/icons/checkbox-sprite-nontouch.svg', 'svgs should be packaged under /icons', ); @@ -246,12 +259,13 @@ test('when a recursive glob is specified', async (t) => { test('when a non recursive glob is specified', async (t) => { const { address, token, cwd } = t.context; const pattern = 'fixtures/*'; + // @ts-expect-error const { files } = await cli.publish(config(pattern, address, token, cwd)); const nested = files.filter((file) => file.pathname.includes('icons')); t.equal( - files[2].pathname, + files[4].pathname, '/client.js', 'client.js should be packaged at /', ); @@ -261,6 +275,7 @@ test('when a non recursive glob is specified', async (t) => { test('when a file is specified with a leading path', async (t) => { const { address, token, cwd } = t.context; const pattern = 'fixtures/client.js'; + // @ts-expect-error const { files } = await cli.publish(config(pattern, address, token, cwd)); t.equal( @@ -273,6 +288,7 @@ test('when a file is specified with a leading path', async (t) => { test('when a file is specified as an object and mapped with a leading path', async (t) => { const { address, token, cwd } = t.context; const pattern = { 'path/to/esm.js': 'fixtures/client.js' }; + // @ts-expect-error const { files } = await cli.publish(config(pattern, address, token, cwd)); t.equal( diff --git a/test/publish.map.test.mjs b/test/publish.map.test.mjs index ab1d71ff..9790a9de 100644 --- a/test/publish.map.test.mjs +++ b/test/publish.map.test.mjs @@ -5,7 +5,7 @@ import { join, basename } from 'path'; import { mockLogger } from './utils.mjs'; import { test, beforeEach, afterEach } from 'tap'; import EikService from '@eik/service'; -import { sink } from '@eik/core'; +import Sink from '@eik/sink-memory'; import { fileURLToPath } from 'url'; import { dirname } from 'path'; import cli from '../classes/index.js'; @@ -14,7 +14,7 @@ const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); beforeEach(async (t) => { - const memSink = new sink.MEM(); + const memSink = new Sink(); const server = fastify({ logger: false }); const service = new EikService({ customSink: memSink }); server.register(service.api()); diff --git a/test/publish.package.test.mjs b/test/publish.package.test.mjs index cabc552b..4313ddbc 100644 --- a/test/publish.package.test.mjs +++ b/test/publish.package.test.mjs @@ -5,7 +5,7 @@ import { join, basename } from 'path'; import { mockLogger } from './utils.mjs'; import { test, beforeEach, afterEach } from 'tap'; import EikService from '@eik/service'; -import { sink } from '@eik/core'; +import Sink from '@eik/sink-memory'; import { fileURLToPath } from 'url'; import { dirname } from 'path'; import cli from '../classes/index.js'; @@ -14,7 +14,7 @@ const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); beforeEach(async (t) => { - const memSink = new sink.MEM(); + const memSink = new Sink(); const server = fastify({ logger: false }); const service = new EikService({ customSink: memSink }); server.register(service.api()); diff --git a/test/tasks/cleanup.test.mjs b/test/tasks/cleanup.test.mjs index 45fa6b5c..902c2b49 100644 --- a/test/tasks/cleanup.test.mjs +++ b/test/tasks/cleanup.test.mjs @@ -1,7 +1,7 @@ import { promises as fs } from 'fs'; import { join } from 'path'; import { test, beforeEach, afterEach } from 'tap'; -import rimraf from 'rimraf'; +import { rimrafSync } from 'rimraf'; import CleanupTask from '../../classes/publish/package/tasks/cleanup.js'; import { fileURLToPath } from 'url'; import { dirname } from 'path'; @@ -28,7 +28,7 @@ beforeEach(async (t) => { }); afterEach((t) => { - rimraf.sync(t.context.path); + rimrafSync(t.context.path); }); test('basic cleanup', async (t) => { diff --git a/test/utils.test.mjs b/test/utils.test.mjs index 1fdbfe80..33e51cd9 100644 --- a/test/utils.test.mjs +++ b/test/utils.test.mjs @@ -17,7 +17,7 @@ test('calculate file hash', async (t) => { const hash = await h.file(join(__dirname, 'fixtures', 'client.js')); t.equal( hash, - 'sha512-7y37q0qk5mDqzHrGvJAR9J8kPX+orJhuO+KrCTKw11ZKRI/5udUuKt2Zb/thH5H39OQYrvnHTLbZS9ShG/lGCg==', + 'sha512-AzZUEv6TzJOlb7MOJSkAtFDihZnjCqOjgWqQmRlQj+/9CsWGQKGJzOT1CPp2R9PQlA0dd3B1+xrrgLsDX9OFtQ==', 'returned hash should match', ); }); @@ -238,9 +238,7 @@ test('fetch remote hash for a given version', async (t) => { }); test('write JSON file - object - file relative to cwd', async (t) => { - const cwd = await fs.mkdtemp( - join(os.tmpdir(), basename(__filename)), - ); + const cwd = await fs.mkdtemp(join(os.tmpdir(), basename(__filename))); await j.write( { version: '1.0.0', integrity: [] }, { cwd, filename: '.eikrc' }, @@ -253,11 +251,11 @@ test('write JSON file - object - file relative to cwd', async (t) => { }); test('write JSON file - object - file absolute path', async (t) => { - const cwd = await fs.mkdtemp( - join(os.tmpdir(), basename(__filename)), - ); + const cwd = await fs.mkdtemp(join(os.tmpdir(), basename(__filename))); await j.write({ prop: 'val' }, { filename: join(cwd, 'test.json') }); - const eikrc = await fs.readFile(join(cwd, 'test.json'), { encoding: 'utf8' }); + const eikrc = await fs.readFile(join(cwd, 'test.json'), { + encoding: 'utf8', + }); const { prop } = JSON.parse(eikrc); t.equal(prop, 'val', 'Prop should equal val'); @@ -267,7 +265,7 @@ test('write JSON file - string - file relative path', async (t) => { await j.write({ prop: 'val' }, './test-using-relative.json'); const eikrc = await fs.readFile( join(__dirname, '../test-using-relative.json'), - { encoding: 'utf8' }, + { encoding: 'utf8' }, ); const { prop } = JSON.parse(eikrc); await fs.unlink(join(__dirname, '../test-using-relative.json')); @@ -276,20 +274,18 @@ test('write JSON file - string - file relative path', async (t) => { }); test('write JSON file - string - file absolute path', async (t) => { - const cwd = await fs.mkdtemp( - join(os.tmpdir(), basename(__filename)), - ); + const cwd = await fs.mkdtemp(join(os.tmpdir(), basename(__filename))); await j.write({ prop: 'val' }, join(cwd, 'test3.json')); - const eikrc = await fs.readFile(join(cwd, 'test3.json'), { encoding: 'utf8' }); + const eikrc = await fs.readFile(join(cwd, 'test3.json'), { + encoding: 'utf8', + }); const { prop } = JSON.parse(eikrc); t.equal(prop, 'val', 'Prop should equal val'); }); test('read JSON file - object - file relative path', async (t) => { - const cwd = await fs.mkdtemp( - join(os.tmpdir(), basename(__filename)), - ); + const cwd = await fs.mkdtemp(join(os.tmpdir(), basename(__filename))); await fs.writeFile(join(cwd, 'test3.json'), JSON.stringify({ key: 'val' })); const json = await j.read({ cwd, filename: './test3.json' }); @@ -297,9 +293,7 @@ test('read JSON file - object - file relative path', async (t) => { }); test('read JSON file - object - file absolute path', async (t) => { - const cwd = await fs.mkdtemp( - join(os.tmpdir(), basename(__filename)), - ); + const cwd = await fs.mkdtemp(join(os.tmpdir(), basename(__filename))); await fs.writeFile(join(cwd, 'test3.json'), JSON.stringify({ key: 'val' })); const json = await j.read({ filename: join(cwd, './test3.json') }); @@ -317,9 +311,7 @@ test('read JSON file - string - file relative path', async (t) => { }); test('read JSON file - string - file absolute path', async (t) => { - const cwd = await fs.mkdtemp( - join(os.tmpdir(), basename(__filename)), - ); + const cwd = await fs.mkdtemp(join(os.tmpdir(), basename(__filename))); await fs.writeFile( join(cwd, './test-read-json-2.json'), JSON.stringify({ key: 'val' }), diff --git a/test/version.test.mjs b/test/version.test.mjs index dfbff693..c0cb4ac0 100644 --- a/test/version.test.mjs +++ b/test/version.test.mjs @@ -5,7 +5,7 @@ import { join, basename } from 'path'; import { mockLogger } from './utils.mjs'; import { test, beforeEach, afterEach } from 'tap'; import EikService from '@eik/service'; -import { sink } from '@eik/core'; +import Sink from '@eik/sink-memory'; import { fileURLToPath } from 'url'; import { dirname } from 'path'; import cli from '../classes/index.js'; @@ -14,7 +14,7 @@ const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); beforeEach(async (t) => { - const memSink = new sink.MEM(); + const memSink = new Sink(); const server = fastify({ logger: false }); const service = new EikService({ customSink: memSink }); server.register(service.api()); diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 00000000..c23c8cc8 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "@eik/typescript-config/module.json", + "include": ["./classes/**/*.js"], + "compilerOptions": { + "outDir": "types" + } +} diff --git a/tsconfig.test.json b/tsconfig.test.json new file mode 100644 index 00000000..2d07b9ab --- /dev/null +++ b/tsconfig.test.json @@ -0,0 +1,4 @@ +{ + "extends": "@eik/typescript-config/test.json", + "include": ["./test/**/*.js"] +} diff --git a/utils/get-cwd.js b/utils/get-cwd.js deleted file mode 100644 index aacf8ade..00000000 --- a/utils/get-cwd.js +++ /dev/null @@ -1,14 +0,0 @@ -'use strict'; - -const av = require('yargs-parser')(process.argv.slice(2)); - -/** - * Returns the current working directory path - * If a --cwd or -c command line flag has been used, the value given will be returned - * Otherwise, the directory where the process was run from is used - * - * @returns {string} - */ -module.exports = function getCWD() { - return av.cwd || av.c || process.cwd(); -}; diff --git a/utils/hash/compare.js b/utils/hash/compare.js index aca384b6..bd32fd49 100644 --- a/utils/hash/compare.js +++ b/utils/hash/compare.js @@ -1,5 +1,3 @@ -'use strict'; - /** * Compares 2 hash strings for comparison. Returns `true` if hashes are identical, false otherwise. * @@ -10,4 +8,4 @@ * * @example hash.compare('a1b22c23d24e25f4g33a123b23c34', 'a1b22c23d24e25f4g33a123b23c34'); */ -module.exports = (hash1, hash2) => hash1 === hash2; +export default (hash1, hash2) => hash1 === hash2; diff --git a/utils/hash/file.js b/utils/hash/file.js index ffb9c6fe..14564253 100644 --- a/utils/hash/file.js +++ b/utils/hash/file.js @@ -1,7 +1,5 @@ -'use strict'; - -const ssri = require('ssri'); -const fs = require('fs'); +import ssri from 'ssri'; +import fs from 'fs'; /** * Reads a file from a given path and produces and returns an integrity hash from its contents @@ -12,7 +10,7 @@ const fs = require('fs'); * * @example hash.file('/path/to/file.js'); */ -module.exports = async (path) => { +export default async (path) => { const integrity = await ssri.fromStream(fs.createReadStream(path)); return integrity.toString(); }; diff --git a/utils/hash/files.js b/utils/hash/files.js index fbff6d93..262651e4 100644 --- a/utils/hash/files.js +++ b/utils/hash/files.js @@ -1,18 +1,16 @@ -'use strict'; - -const ssri = require('ssri'); -const fileHash = require('./file'); +import ssri from 'ssri'; +import fileHash from './file.js'; /** * Reads files from given paths and produces and returns an integrity hash from all files contents * - * @param {[string]} files - an array of file paths + * @param {string[]} files - an array of file paths * * @returns {Promise} - integrity string * * @example hash.files(['/path/to/file1.js', '/path/to/file2.js']); */ -module.exports = async (files) => { +export default async (files) => { const hashes = await Promise.all(files.map(fileHash)); const hasher = ssri.create(); for (const hash of hashes.sort()) { diff --git a/utils/hash/index.js b/utils/hash/index.js index 079c5c25..bf18b795 100644 --- a/utils/hash/index.js +++ b/utils/hash/index.js @@ -1,5 +1,5 @@ -const file = require('./file'); -const files = require('./files'); -const compare = require('./compare'); +import file from './file.js'; +import files from './files.js'; +import compare from './compare.js'; -module.exports = { file, files, compare }; +export default { file, files, compare }; diff --git a/utils/http/index.js b/utils/http/index.js index 28fa5c81..7559924b 100644 --- a/utils/http/index.js +++ b/utils/http/index.js @@ -1,6 +1,7 @@ -const latestVersion = require('./latest-version'); -const versions = require('./versions'); -const integrity = require('./integrity'); -const request = require('./request'); +import latestVersion from './latest-version.js'; +import versions from './versions.js'; +import integrity from './integrity.js'; +import request from './request.js'; -module.exports = { latestVersion, versions, integrity, request }; +export default { latestVersion, versions, integrity, request }; +export { latestVersion, versions, integrity, request }; diff --git a/utils/http/integrity.js b/utils/http/integrity.js index 349d742a..53c35a1d 100644 --- a/utils/http/integrity.js +++ b/utils/http/integrity.js @@ -1,7 +1,4 @@ -'use strict'; - -const { join } = require('path'); -const fetch = require('node-fetch'); +import { join } from 'path'; /** * Fetches package integrity string by name and version from a given Eik asset server. @@ -14,7 +11,7 @@ const fetch = require('node-fetch'); * * @throws Error */ -module.exports = async (server, type, name, version) => { +export default async (server, type, name, version) => { const url = new URL(join(type, name, version), server); url.search = `?t=${Date.now()}`; diff --git a/utils/http/latest-version.js b/utils/http/latest-version.js index 159bfe9a..35282a47 100644 --- a/utils/http/latest-version.js +++ b/utils/http/latest-version.js @@ -1,7 +1,4 @@ -'use strict'; - -const { join } = require('path'); -const fetch = require('node-fetch'); +import { join } from 'path'; /** * Fetches the latest version from an Eik server of a package by name, optionally restricting the lookup to a specified semver major version @@ -14,7 +11,7 @@ const fetch = require('node-fetch'); * * @throws Error */ -module.exports = async (server, type, name, major) => { +export default async (server, type, name, major) => { const url = new URL(`${join(type, name)}?t=${Date.now()}`, server); const res = await fetch(url); if (!res.ok) { diff --git a/utils/http/request.js b/utils/http/request.js index e61e1749..8dd12be6 100644 --- a/utils/http/request.js +++ b/utils/http/request.js @@ -1,59 +1,65 @@ -'use strict'; +import { readFile } from 'node:fs/promises'; -const fetch = require('node-fetch'); -const FormData = require('form-data'); -const { createReadStream } = require('fs'); +/** + * @typedef {object} RequestOptions + * @property {string} [method="POST"] + * @property {string} host + * @property {string} pathname + * @property {unknown} [data] + * @property {string} [file] + * @property {string} [map] + * @property {string} [token] + */ /** * HTTP Utility for making requests against an Eik server * - * @param {{method:string,host:string,pathname:string,data:object,file:string,map:string,token:string}} options + * @param {RequestOptions} options * - * @returns {Promise<{status:number,message:object|string}>} - Promise that resolves to an object with properties status and message + * @returns {Promise<{ status:number; message: object | string }>} - Promise that resolves to an object with properties status and message * * @throws Error */ async function request(options) { const { method = 'POST', host, pathname, data, file, map, token } = options; - const form = new FormData(); - const headers = {}; + const body = new FormData(); + const headers = new Headers(); if (data) { for (const [key, value] of Object.entries(data)) { - form.append(key, value); + body.set(key, value); } } if (file) { - form.append('package', createReadStream(file)); + const fileData = await readFile(file); + body.set('package', new Blob([fileData])); } if (map) { - form.append('map', createReadStream(map)); + const mapData = await readFile(map); + body.set('map', new Blob([mapData])); } if (token) { - headers.Authorization = `Bearer ${token}`; + headers.set('Authorization', `Bearer ${token}`); } try { const url = new URL(pathname, host); url.search = `?t=${Date.now()}`; - const res = await fetch(url, { - method, - body: form, - headers: { ...headers, ...form.getHeaders() }, - }); + const res = await fetch(url, { method, body, headers }); if (!res.ok) { const err = new Error( `Server responded with a non 200 ok status code. Response: ${res.status}`, ); + // @ts-ignore err.statusCode = res.status; throw err; } - if (res.headers.get('content-type').includes('application/json')) { + if (res?.headers?.get('content-type')?.includes('application/json')) { return { message: await res.json(), status: res.status }; } return { message: await res.text(), status: res.status }; @@ -65,4 +71,4 @@ async function request(options) { } } -module.exports = request; +export default request; diff --git a/utils/http/versions.js b/utils/http/versions.js index 03c4dd97..3468954e 100644 --- a/utils/http/versions.js +++ b/utils/http/versions.js @@ -1,7 +1,4 @@ -'use strict'; - -const { join } = require('path'); -const fetch = require('node-fetch'); +import { join } from 'path'; /** * Fetches package versions by name from a given Eik asset server. @@ -13,7 +10,7 @@ const fetch = require('node-fetch'); * * @throws Error */ -module.exports = async (server, type, name) => { +export default async (server, type, name) => { const pkg = join(type, name); const url = new URL(pkg, server); url.search = `?t=${Date.now()}`; diff --git a/utils/index.js b/utils/index.js index 26d39f7b..b5375968 100644 --- a/utils/index.js +++ b/utils/index.js @@ -1,11 +1,8 @@ -'use strict'; +import { helpers } from '@eik/common'; +import logger from './logger.js'; +import typeSlug from './type-slug.js'; +import typeTitle from './type-title.js'; -const { - helpers: { getDefaults, files }, -} = require('@eik/common'); -const logger = require('./logger'); -const getCWD = require('./get-cwd'); -const typeSlug = require('./type-slug'); -const typeTitle = require('./type-title'); +const { getDefaults } = helpers; -module.exports = { logger, getDefaults, getCWD, files, typeSlug, typeTitle }; +export { logger, getDefaults, typeSlug, typeTitle }; diff --git a/utils/json/index.js b/utils/json/index.js index 5bedead7..2e7f62bd 100644 --- a/utils/json/index.js +++ b/utils/json/index.js @@ -1,5 +1,5 @@ -const read = require('./read'); -const write = require('./write'); -const writeEik = require('./write-eik'); +import read from './read.js'; +import write from './write.js'; +import writeEik from './write-eik.js'; -module.exports = { read, write, writeEik }; +export default { read, write, writeEik }; diff --git a/utils/json/read.js b/utils/json/read.js index 0a092338..48793d36 100644 --- a/utils/json/read.js +++ b/utils/json/read.js @@ -1,8 +1,6 @@ -'use strict'; - -const assert = require('assert'); -const fs = require('fs').promises; -const { join, isAbsolute } = require('path'); +import assert from 'assert'; +import fs from 'node:fs/promises'; +import { join, isAbsolute } from 'path'; /** * Reads a file at a given location, assumes the contents to be JSON and then deserializes into a JavaScript object @@ -10,7 +8,7 @@ const { join, isAbsolute } = require('path'); * @param {string|{filename:string,cwd:string}} location - Path string or object describing location for where to write JSON to. * If location is a string it can be relative or absolute. * If location is an object, `pathname` must be given which can be relative or absolute. `cwd` can also be given to define the current working directory. - * @return {Promise} - JavaScript object deserialized from JSON file contents + * @return {Promise} - JavaScript object deserialized from JSON file contents * * @example json.read('/path/to/file.json'); * @example json.read('./relative/path/to/file.json'); @@ -18,7 +16,7 @@ const { join, isAbsolute } = require('path'); * @example json.read({ filename: './relative/path/to/file.json' }); * @example json.read({ filename: './relative/path/to/file.json', cwd: '/path/to/cwd }); */ -module.exports = async (location) => { +export default async (location) => { if (typeof location !== 'string') { assert( location.filename, diff --git a/utils/json/write-eik.js b/utils/json/write-eik.js index cf602247..bbb83b59 100644 --- a/utils/json/write-eik.js +++ b/utils/json/write-eik.js @@ -1,7 +1,5 @@ -'use strict'; - -const fs = require('fs').promises; -const { join } = require('path'); +import fs from 'node:fs/promises'; +import { join } from 'path'; /** * Reads, updates and then writes data to given eik.json file (defaults to file in current directory) @@ -15,10 +13,10 @@ const { join } = require('path'); * @example json.writeEik({ key: 'value' }, { cwd: '/path/to/cwd' }); * @example json.writeEik({ key: 'value' }, { cwd: '/path/to/cwd', filename: 'eik.json' }); */ -module.exports = async (data = {}, options) => { +export default async (data = {}, options) => { const { cwd = process.cwd(), filename = 'eik.json' } = options; const eikpath = join(cwd, filename); - const eik = await fs.readFile(eikpath); + const eik = await fs.readFile(eikpath, 'utf-8'); const eikjson = JSON.parse(eik); await fs.writeFile( diff --git a/utils/json/write.js b/utils/json/write.js index ce1977dc..d7ea886c 100644 --- a/utils/json/write.js +++ b/utils/json/write.js @@ -1,8 +1,6 @@ -'use strict'; - -const assert = require('assert'); -const fs = require('fs').promises; -const { join, isAbsolute, dirname } = require('path'); +import assert from 'assert'; +import fs from 'node:fs/promises'; +import { join, isAbsolute, dirname } from 'path'; /** * Utility function that can be used to write a JavaScript object to a file at a given location. @@ -21,7 +19,7 @@ const { join, isAbsolute, dirname } = require('path'); * * @throws Error */ -module.exports = async (meta = {}, location) => { +export default async (meta = {}, location) => { if (typeof location !== 'string') { assert( location.filename, diff --git a/utils/logger.js b/utils/logger.js index a5cb389d..d22feb6e 100644 --- a/utils/logger.js +++ b/utils/logger.js @@ -1,5 +1,3 @@ -'use strict'; - /** * Creates a logger object that wraps an instance of the "ora" module in order to provide consistent command line logging that includes a spinner * @@ -30,10 +28,9 @@ const logger = (spinner, debug = false) => ({ */ info(message) { if (typeof message !== 'string') { - // eslint-disable-next-line no-param-reassign spinner.text = ''; spinner.stopAndPersist(); - // eslint-disable-next-line no-console + console.log(message); spinner.start(); } else { @@ -54,4 +51,4 @@ const logger = (spinner, debug = false) => ({ }, }); -module.exports = logger; +export default logger; diff --git a/utils/type-slug.js b/utils/type-slug.js index e0266111..6d5e72cc 100644 --- a/utils/type-slug.js +++ b/utils/type-slug.js @@ -1,4 +1,4 @@ -module.exports = (type) => { +export default (type) => { if (type === 'package') return 'pkg'; return type; }; diff --git a/utils/type-title.js b/utils/type-title.js index ffe0973b..fa39162c 100644 --- a/utils/type-title.js +++ b/utils/type-title.js @@ -1,4 +1,4 @@ -module.exports = (type) => { +export default (type) => { if (type === 'package') return 'PACKAGE'; if (type === 'npm') return 'NPM'; return 'MAP';