From 6fbab8359daf146860a07c874d18ac129766876f Mon Sep 17 00:00:00 2001 From: Yuki Hattori Date: Sat, 4 Sep 2021 03:25:29 +0900 Subject: [PATCH 1/3] Fix a default export name for untitled Markdown --- src/commands/export.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/commands/export.ts b/src/commands/export.ts index c9e0ebf9..5c0dabb7 100644 --- a/src/commands/export.ts +++ b/src/commands/export.ts @@ -152,8 +152,10 @@ 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 (typeof e === 'object' && typeof e?.toString === 'function') + return `. ${e.toString()}` - return `. ${e.toString()}` + return ' by unknown error.' })()}` ) } finally { @@ -174,7 +176,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 From 894d191471a1e3e8a8801ba8eca5f3219d3a978b Mon Sep 17 00:00:00 2001 From: Yuki Hattori Date: Sat, 4 Sep 2021 03:45:18 +0900 Subject: [PATCH 2/3] Add test cases --- src/commands/export.test.ts | 22 +++++++++++++++++++++- src/commands/export.ts | 5 ++--- src/utils.test.ts | 20 ++++++++++++++++++++ src/utils.ts | 17 +++++++++++++++++ 4 files changed, 60 insertions(+), 4 deletions(-) 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 5c0dabb7..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,7 @@ 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 (typeof e === 'object' && typeof e?.toString === 'function') - return `. ${e.toString()}` + if (hasToString(e)) return `. ${e.toString()}` return ' by unknown error.' })()}` 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 +} From 62477ffe5ae7e4f6f7ee4a30d37150bfa7f66d2d Mon Sep 17 00:00:00 2001 From: Yuki Hattori Date: Sat, 4 Sep 2021 03:50:07 +0900 Subject: [PATCH 3/3] [ci skip] Update CHANGELOG.md --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) 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))