diff --git a/CHANGELOG.md b/CHANGELOG.md index 46c91920..cf59e49b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,10 @@ - [Early preview] Set up build for Web extension such as [github.dev](https://github.dev) ([#281](https://github.com/marp-team/marp-vscode/issues/281), [#283](https://github.com/marp-team/marp-vscode/pull/283)) +### Fixed + +- Fix the default export name for untitled Markdown ([#280](https://github.com/marp-team/marp-vscode/issues/280), [#285](https://github.com/marp-team/marp-vscode/pull/285)) + ### Changed - Upgrade Marp CLI to [v1.4.0](https://github.com/marp-team/marp-cli/releases/tag/v1.4.0) ([#282](https://github.com/marp-team/marp-vscode/pull/282)) diff --git a/src/commands/export.test.ts b/src/commands/export.test.ts index d971e113..80304c69 100644 --- a/src/commands/export.test.ts +++ b/src/commands/export.test.ts @@ -117,6 +117,18 @@ describe('#saveDialog', () => { ) }) + it('opens save dialog with default name "untitled" if the document is untitled', async () => { + const document: any = { uri: { fsPath: '' }, isUntitled: true } + + await exportModule.saveDialog(document) + + expect(window.showSaveDialog).toHaveBeenCalledWith( + expect.objectContaining({ + defaultUri: expect.objectContaining({ fsPath: 'untitled.pdf' }), + }) + ) + }) + it('opens save dialog with configured default type', async () => { setConfiguration({ 'markdown.marp.exportType': 'pptx' }) @@ -197,13 +209,21 @@ describe('#doExport', () => { expect.stringContaining('[Error] ERROR') ) - // Unknown error + // Unknown error (via toString()) marpCliSpy.mockRejectedValueOnce('UNKNOWN ERROR!') await exportModule.doExport(saveURI(), document) expect(window.showErrorMessage).toHaveBeenCalledWith( expect.stringContaining('UNKNOWN ERROR!') ) + + // WTF + marpCliSpy.mockRejectedValueOnce(null) + await exportModule.doExport(saveURI(), document) + + expect(window.showErrorMessage).toHaveBeenCalledWith( + 'Failure to export by unknown error.' + ) }) describe('when enabled markdown.marp.pdf.noteAnnotations', () => { diff --git a/src/commands/export.ts b/src/commands/export.ts index c9e0ebf9..3aea3c87 100644 --- a/src/commands/export.ts +++ b/src/commands/export.ts @@ -15,7 +15,7 @@ import marpCli, { createWorkFile, MarpCLIError, } from '../marp-cli' -import { marpConfiguration, unlink } from '../utils' +import { marpConfiguration, unlink, hasToString } from '../utils' import { createWorkspaceProxyServer, WorkspaceProxyServer, @@ -152,8 +152,9 @@ export const doExport = async (uri: Uri, document: TextDocument) => { `Failure to export${(() => { if (e instanceof MarpCLIError) return `. ${e.message}` if (e instanceof Error) return `: [${e.name}] ${e.message}` + if (hasToString(e)) return `. ${e.toString()}` - return `. ${e.toString()}` + return ' by unknown error.' })()}` ) } finally { @@ -174,7 +175,11 @@ export const saveDialog = async (document: TextDocument) => { const types = [...new Set([defaultType, ...baseTypes])] const saveURI = await window.showSaveDialog({ - defaultUri: Uri.file(fsPath.slice(0, -path.extname(fsPath).length) + ext), + defaultUri: Uri.file( + (document.isUntitled + ? 'untitled' + : fsPath.slice(0, -path.extname(fsPath).length)) + ext + ), filters: types.reduce((f, t) => { if (baseTypes.includes(t)) f[descriptions[t]] = extensions[t] return f diff --git a/src/utils.test.ts b/src/utils.test.ts index 2febc5ac..7c6b998b 100644 --- a/src/utils.test.ts +++ b/src/utils.test.ts @@ -72,4 +72,24 @@ describe('Utilities', () => { jest.advanceTimersByTime(timeout) })) }) + + describe('#hasToString', () => { + it('returns true if the object has a toString method', () => { + expect(utils.hasToString({ toString: () => 'test' })).toBe(true) + expect(utils.hasToString({})).toBe(true) + expect(utils.hasToString(Object.create(null))).toBe(false) + }) + + it('returns true if the literal has a toString method', () => { + expect(utils.hasToString(0)).toBe(true) + expect(utils.hasToString(BigInt(1))).toBe(true) + expect(utils.hasToString('string')).toBe(true) + expect(utils.hasToString(Symbol())).toBe(true) + expect(utils.hasToString(utils.hasToString)).toBe(true) + expect(utils.hasToString(false)).toBe(true) + expect(utils.hasToString(true)).toBe(true) + expect(utils.hasToString(null)).toBe(false) + expect(utils.hasToString(undefined)).toBe(false) + }) + }) }) diff --git a/src/utils.ts b/src/utils.ts index dae1fc7d..328acb1a 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -64,3 +64,20 @@ export const writeFile = (target: Uri, text: string) => export const unlink = (target: Uri) => workspace.fs.delete(target, { useTrash: false }) + +export const hasToString = ( + target: unknown +): target is { toString(): string } => { + switch (typeof target) { + case 'object': + return typeof target?.toString === 'function' + case 'bigint': + case 'boolean': + case 'function': + case 'number': + case 'string': + case 'symbol': + return true + } + return false +}