diff --git a/package.json b/package.json index 534e637e..970cdd25 100644 --- a/package.json +++ b/package.json @@ -154,7 +154,7 @@ "@marp-team/marp-core": "^3.7.0", "@marp-team/marpit": "^2.5.0", "chokidar": "^3.5.3", - "cosmiconfig": "~8.1.3", + "cosmiconfig": "^8.2.0", "is-wsl": "^2.2.0", "puppeteer-core": "20.8.0", "remove": "^0.1.5", diff --git a/src/config.ts b/src/config.ts index 151b98c4..1b836b2c 100644 --- a/src/config.ts +++ b/src/config.ts @@ -2,9 +2,9 @@ import fs from 'fs' import path from 'path' import chalk from 'chalk' -import { cosmiconfig } from 'cosmiconfig' +import { cosmiconfig, cosmiconfigSync } from 'cosmiconfig' import { osLocale } from 'os-locale' -import { info, warn } from './cli' +import { info, warn, error as cliError } from './cli' import { ConverterOption, ConvertType } from './converter' import { ResolvableEngine, ResolvedEngine } from './engine' import { keywordsAsArray } from './engine/meta-plugin' @@ -70,7 +70,7 @@ export type IMarpCLIConfig = Overwrite< progress?: boolean transition?: boolean } - engine?: ResolvableEngine | ResolvableEngine[] + engine?: ResolvableEngine html?: ConverterOption['html'] keywords?: string | string[] lang?: string @@ -211,7 +211,7 @@ export class MarpCLIConfig { this.conf.image if (image === 'png') return ConvertType.png - if (image === 'jpeg') return ConvertType.jpeg + if (image === 'jpg' || image === 'jpeg') return ConvertType.jpeg // Detect from filename const lowerOutput = (output || '').toLowerCase() @@ -331,7 +331,11 @@ export class MarpCLIConfig { } private async loadConf(confPath?: string) { - const explorer = cosmiconfig(MarpCLIConfig.moduleName) + const generateCosmiconfigExplorer = ResolvedEngine.isESMAvailable() + ? cosmiconfig + : cosmiconfigSync // sync version is using `require()` instead of `import()` so not expect to meet a trouble with ESM + + const explorer = generateCosmiconfigExplorer(MarpCLIConfig.moduleName) try { const ret = await (confPath === undefined @@ -343,10 +347,21 @@ export class MarpCLIConfig { this.conf = ret.config } } catch (e: unknown) { + const isErr = isError(e) + + if (isErr && e.code === 'ERR_REQUIRE_ESM') { + // Show reason why `require()` failed in the current context + if ('pkg' in process) { + cliError( + 'A standalone binary version of Marp CLI is currently not supported resolving ESM. Please consider using CommonJS, or trying to use Marp CLI via Node.js.' + ) + } + } + error( [ 'Could not find or parse configuration file.', - isError(e) && e.name !== 'Error' && `(${e.name})`, + isErr && `(${e.name}: ${e.message.trimEnd()})`, confPath !== undefined && `[${confPath}]`, ] .filter((m) => m) diff --git a/src/converter.ts b/src/converter.ts index 67dd7cfe..bad138a6 100644 --- a/src/converter.ts +++ b/src/converter.ts @@ -1,6 +1,6 @@ /* eslint-disable @typescript-eslint/no-non-null-assertion */ import { URL } from 'url' -import type { MarpOptions } from '@marp-team/marp-core' +import type { Marp, MarpOptions } from '@marp-team/marp-core' import { Marpit, Options as MarpitOptions } from '@marp-team/marpit' import chalk from 'chalk' import type { Browser, Page, HTTPRequest } from 'puppeteer-core' @@ -503,7 +503,9 @@ export class Converter { }) // Resolve functional engine - engine = await Promise.resolve(engine(opts)) + engine = await Promise.resolve( + engine(opts as typeof opts & { readonly marp: Marp }) + ) } if (isClass(engine)) engine = new engine(opts) diff --git a/src/engine.ts b/src/engine.ts index 030378f1..c0bf503f 100644 --- a/src/engine.ts +++ b/src/engine.ts @@ -8,15 +8,18 @@ import { resolve as importMetaResolve } from 'import-meta-resolve' import { pkgUp } from 'pkg-up' import { error, isError } from './error' -type MarpitInstanceOrClass = Marpit | typeof Marpit +type FunctionalEngine = ( + constructorOptions: ConstructorParameters[0] & { readonly marp: Marp } +) => Marpit | typeof Marpit | Promise -type FunctionEngine = ( - opts?: Marpit.Options -) => MarpitInstanceOrClass | Promise +export type Engine = + | Marpit + | typeof Marpit + | FunctionalEngine -export type Engine = MarpitInstanceOrClass | FunctionEngine - -export type ResolvableEngine = Engine | string +export type ResolvableEngine = + | Engine + | string const preResolveAsyncSymbol = Symbol('preResolveAsync') @@ -188,7 +191,7 @@ export class ResolvedEngine { // Show reason why `require()` failed in the current context if ('pkg' in process) { error( - 'A standalone binary version of Marp CLI is currently not supported resolving ESM engine. Please consider using CommonJS engine, or trying to use Marp CLI via Node.js.' + 'A standalone binary version of Marp CLI is currently not supported resolving ESM. Please consider using CommonJS, or trying to use Marp CLI via Node.js.' ) } } diff --git a/src/index.ts b/src/index.ts index e92e5505..0e568c8e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,7 +1,35 @@ +import type { Marp } from '@marp-team/marp-core' +import type { Marpit } from '@marp-team/marpit' +import type { IMarpCLIConfig } from './config' +import type { ResolvableEngine } from './engine' + import { apiInterface } from './marp-cli' +type Overwrite = Omit> & U + export { ObservationHelper, waitForObservation } from './marp-cli' export { CLIError, CLIErrorCode } from './error' export const marpCli = apiInterface export default apiInterface + +// --- + +// eslint-disable-next-line @typescript-eslint/no-empty-interface -- Use interface instead of type for better IntelliSense +export interface Config + extends Overwrite< + Omit< + IMarpCLIConfig, + /** + * This option is internal setting for collaboration with Marp team tools such as Marp for VS Code. + * It is not designed for users because the result of conversion may break if set wrong base URL. + */ + 'baseUrl' + >, + { + engine?: ResolvableEngine + image?: 'png' | 'jpeg' + images?: 'png' | 'jpeg' + options?: ConstructorParameters[0] + } + > {} diff --git a/yarn.lock b/yarn.lock index 8a68737a..af72599a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1735,9 +1735,9 @@ integrity sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ== "@types/node@*": - version "20.4.0" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.4.0.tgz#01d637d1891e419bc85763b46f42809cd2d5addb" - integrity sha512-jfT7iTf/4kOQ9S7CHV9BIyRaQqHu67mOjsIQBC3BKZvzvUB6zLxEwJ6sBE3ozcvP8kF6Uk5PXN0Q+c0dfhGX0g== + version "20.4.1" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.4.1.tgz#a6033a8718653c50ac4962977e14d0f984d9527d" + integrity sha512-JIzsAvJeA/5iY6Y/OxZbv1lUcc8dNSE77lb2gnBH+/PJ3lFR1Ccvgwl5JWnHAkNHcRsT0TbpVOsiMKZ1F/yyJg== "@types/node@^18.7.3": version "18.16.19" @@ -2507,9 +2507,9 @@ caniuse-api@^3.0.0: lodash.uniq "^4.5.0" caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001464, caniuse-lite@^1.0.30001503: - version "1.0.30001512" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001512.tgz#7450843fb581c39f290305a83523c7a9ef0d4cb4" - integrity sha512-2S9nK0G/mE+jasCUsMPlARhRCts1ebcp2Ji8Y8PWi4NDE1iRdLCnEPHkEfeBrGC45L4isBx5ur3IQ6yTE2mRZw== + version "1.0.30001513" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001513.tgz#382fe5fbfb0f7abbaf8c55ca3ac71a0307a752e9" + integrity sha512-pnjGJo7SOOjAGytZZ203Em95MRM8Cr6jhCXNF/FAXTpCTRTECnqQWLpiTRqrFtdYcth8hf4WECUpkezuYsMVww== "chainsaw@>=0.0.7 <0.1": version "0.0.9" @@ -2820,16 +2820,6 @@ cosmiconfig@^8.2.0: parse-json "^5.0.0" path-type "^4.0.0" -cosmiconfig@~8.1.3: - version "8.1.3" - resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-8.1.3.tgz#0e614a118fcc2d9e5afc2f87d53cd09931015689" - integrity sha512-/UkO2JKI18b5jVMJUp0lvKFMpa/Gye+ZgZjKD+DGEN9y7NRcf/nK1A0sp67ONmKtnDCNMS44E6jrk0Yc3bDuUw== - dependencies: - import-fresh "^3.2.1" - js-yaml "^4.1.0" - parse-json "^5.0.0" - path-type "^4.0.0" - crc-32@^1.2.0: version "1.2.2" resolved "https://registry.yarnpkg.com/crc-32/-/crc-32-1.2.2.tgz#3cad35a934b8bf71f25ca524b6da51fb7eace2ff" @@ -2860,9 +2850,9 @@ cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3: which "^2.0.1" css-declaration-sorter@^6.3.1: - version "6.4.0" - resolved "https://registry.yarnpkg.com/css-declaration-sorter/-/css-declaration-sorter-6.4.0.tgz#630618adc21724484b3e9505bce812def44000ad" - integrity sha512-jDfsatwWMWN0MODAFuHszfjphEXfNw9JUAhmY4pLu3TyTU+ohUpsbVtbU+1MZn4a47D9kqh03i4eyOm+74+zew== + version "6.4.1" + resolved "https://registry.yarnpkg.com/css-declaration-sorter/-/css-declaration-sorter-6.4.1.tgz#28beac7c20bad7f1775be3a7129d7eae409a3a71" + integrity sha512-rtdthzxKuyq6IzqX6jEcIzQF/YqccluefyCYheovBOLhFT/drQA9zj/UbRAa9J7C0o6EG6u3E6g+vKkay7/k3g== css-functions-list@^3.1.0: version "3.1.0" @@ -3341,9 +3331,9 @@ ee-first@1.1.1: integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== electron-to-chromium@^1.4.431: - version "1.4.451" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.451.tgz#12b63ee5c82cbbc7b4ddd91e90f5a0dfc10de26e" - integrity sha512-YYbXHIBxAHe3KWvGOJOuWa6f3tgow44rBW+QAuwVp2DvGqNZeE//K2MowNdWS7XE8li5cgQDrX1LdBr41LufkA== + version "1.4.454" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.454.tgz#774dc7cb5e58576d0125939ec34a4182f3ccc87d" + integrity sha512-pmf1rbAStw8UEQ0sr2cdJtWl48ZMuPD9Sto8HVQOq9vx9j2WgDEN6lYoaqFvqEHYOmGA9oRGn7LqWI9ta0YugQ== emittery@^0.13.1: version "0.13.1" @@ -4162,15 +4152,15 @@ glob-parent@^6.0.2: is-glob "^4.0.3" glob@^10.2.5: - version "10.3.1" - resolved "https://registry.yarnpkg.com/glob/-/glob-10.3.1.tgz#9789cb1b994515bedb811a6deca735b5c37d2bf4" - integrity sha512-9BKYcEeIs7QwlCYs+Y3GBvqAMISufUS0i2ELd11zpZjxI5V9iyRj0HgzB5/cLf2NY4vcYBTYzJ7GIui7j/4DOw== + version "10.3.2" + resolved "https://registry.yarnpkg.com/glob/-/glob-10.3.2.tgz#04fe71118ec6d2f4cb761849acbacec14b06cb1e" + integrity sha512-vsuLzB3c/uyDLLEdBZtT8vGnN0z57rwOxHV2oYZib/7HWmBspUaja/McYIobBjC4qaUTuNpUyFO2IdqM4DZIJA== dependencies: foreground-child "^3.1.0" jackspeak "^2.0.3" minimatch "^9.0.1" - minipass "^5.0.0 || ^6.0.2" - path-scurry "^1.10.0" + minipass "^5.0.0 || ^6.0.2 || ^7.0.0" + path-scurry "^1.10.1" glob@^7.1.3, glob@^7.1.4, glob@~7.2.0: version "7.2.3" @@ -5868,9 +5858,9 @@ minimatch@^5.0.1: brace-expansion "^2.0.1" minimatch@^9.0.0, minimatch@^9.0.1: - version "9.0.2" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.2.tgz#397e387fff22f6795844d00badc903a3d5de7057" - integrity sha512-PZOT9g5v2ojiTL7r1xF6plNHLtOeTpSlDI007As2NlA2aYBMfVom17yqa6QzhmDP8QOhn7LjHTg7DFCVSSa6yg== + version "9.0.3" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.3.tgz#a6e00c3de44c3a542bfaae70abfc22420a6da825" + integrity sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg== dependencies: brace-expansion "^2.0.1" @@ -5895,10 +5885,10 @@ minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.6: resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== -"minipass@^5.0.0 || ^6.0.2": - version "6.0.2" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-6.0.2.tgz#542844b6c4ce95b202c0995b0a471f1229de4c81" - integrity sha512-MzWSV5nYVT7mVyWCwn2o7JH13w2TBRmmSqSRCKzTw+lmft9X4z+3wjvs06Tzijo5z4W/kahUCDpRXTF+ZrmF/w== +"minipass@^5.0.0 || ^6.0.2 || ^7.0.0": + version "7.0.1" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.0.1.tgz#dff63464407cd8b83d7f008c0f116fa8c9b77ebf" + integrity sha512-NQ8MCKimInjVlaIqx51RKJJB7mINVkLTJbsZKmto4UAAOC/CWXES8PGaOgoBZyqoUsUA/U3DToGK7GJkkHbjJw== mitt@3.0.0: version "3.0.0" @@ -6010,9 +6000,9 @@ node-int64@^0.4.0: integrity sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw== node-releases@^2.0.12: - version "2.0.12" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.12.tgz#35627cc224a23bfb06fb3380f2b3afaaa7eb1039" - integrity sha512-QzsYKWhXTWx8h1kIvqfnC++o0pEmpRQA/aenALsL2F4pqNVr7YzcdMlDij5WBnwftRbJCNJL/O7zdKaxKPHqgQ== + version "2.0.13" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.13.tgz#d5ed1627c23e3461e819b02e57b75e4899b1c81d" + integrity sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ== normalize-package-data@^3.0.2: version "3.0.3" @@ -6361,13 +6351,13 @@ path-parse@^1.0.7: resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== -path-scurry@^1.10.0: - version "1.10.0" - resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.10.0.tgz#0ffbd4c1f7de9600f98a1405507d9f9acb438ab3" - integrity sha512-tZFEaRQbMLjwrsmidsGJ6wDMv0iazJWk6SfIKnY4Xru8auXgmJkOBa5DUbYFcFD2Rzk2+KDlIiF0GVXNCbgC7g== +path-scurry@^1.10.1: + version "1.10.1" + resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.10.1.tgz#9ba6bf5aa8500fe9fd67df4f0d9483b2b0bfc698" + integrity sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ== dependencies: lru-cache "^9.1.1 || ^10.0.0" - minipass "^5.0.0 || ^6.0.2" + minipass "^5.0.0 || ^6.0.2 || ^7.0.0" path-to-regexp@0.1.7: version "0.1.7" @@ -7611,9 +7601,9 @@ saxes@^6.0.0: xmlchars "^2.2.0" semver@^6.0.0, semver@^6.3.0, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8, semver@^7.5.3: - version "7.5.3" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.3.tgz#161ce8c2c6b4b3bdca6caadc9fa3317a4c4fe88e" - integrity sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ== + version "7.5.4" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" + integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== dependencies: lru-cache "^6.0.0"