diff --git a/src/models/NoteData.ts b/src/models/NoteData.ts index 66e979b0..73c6339e 100644 --- a/src/models/NoteData.ts +++ b/src/models/NoteData.ts @@ -23,6 +23,7 @@ export interface NoteData { } export interface EvernoteNoteData { + _type_id: 'EvernoteNoteData'; title?: string; created?: string; updated?: string; diff --git a/src/outputLanguages/StandardMD.ts b/src/outputLanguages/StandardMD.ts index a08c142f..b339b18e 100644 --- a/src/outputLanguages/StandardMD.ts +++ b/src/outputLanguages/StandardMD.ts @@ -19,8 +19,7 @@ export class StandardMD implements Language { postProcess= async(options: YarleOptions, outputNotebookFolders: string[]) => {}; noteExtension= '.md'; noteProcess= (options: YarleOptions, noteData: NoteData, note: EvernoteNoteData) => { - - saveMdFile(fixImagesInLink(noteData.appliedMarkdownContent), noteData) + saveMdFile(fixImagesInLink(noteData.appliedMarkdownContent), noteData, note) }; tagProcess= (content: string, tasks: Map, currentTaskPlaceholder: string, updatedContent: string): string => { return updatedContent; diff --git a/src/process-resources.ts b/src/process-resources.ts index b893fbe9..eed72ac0 100644 --- a/src/process-resources.ts +++ b/src/process-resources.ts @@ -10,7 +10,7 @@ import { yarleOptions } from './yarle'; import { OutputFormat } from './output-format'; import { EvernoteNoteData } from './models'; -const getResourceWorkDirs = (note: any) => { +const getResourceWorkDirs = (note: EvernoteNoteData) => { const pathSepRegExp = new RegExp(`\\${path.sep}`, 'g'); const relativeResourceWorkDir = utils.getRelativeResourceDir(note).replace(pathSepRegExp, yarleOptions.pathSeparator); const absoluteResourceWorkDir = utils.getAbsoluteResourceDir(note); // .replace(pathSepRegExp,yarleOptions.pathSeparator) @@ -101,7 +101,7 @@ const processResource = (workDir: string, resource: any): any => { }; export const prepareContentByExtractingDataUrlResources = ( - note: any, + note: EvernoteNoteData, content: string, ): string => { if (content.indexOf('src="data:') < 0 && content.indexOf('href="data:') < 0) { @@ -135,7 +135,7 @@ const createResourceFromData = ( base64: boolean, data: string, absoluteResourceWorkDir: string, - note: any, + note: EvernoteNoteData, ): string => { const baseName = 'embedded'; // data doesn't seem to include useful base filename const extension = extensionForMimeType(mediatype) || '.dat'; diff --git a/src/utils/content-utils.ts b/src/utils/content-utils.ts index 045142a0..61345590 100644 --- a/src/utils/content-utils.ts +++ b/src/utils/content-utils.ts @@ -1,6 +1,5 @@ import Moment from 'moment'; -import { utimesSync } from 'fs'; -import { utimes } from 'utimes'; +import { utimesSync } from 'utimes'; import { yarleOptions } from './../yarle'; import { MetaData } from './../models/MetaData'; @@ -116,19 +115,15 @@ export const logTags = (note: EvernoteNoteData): string => { return undefined; }; -export const setFileDates = (path: string, created: any, updated: any): void => { - const updatedMoment = Moment(updated).valueOf(); - const mtime = updatedMoment / 1000; - utimesSync(path, mtime, mtime); - // also set creation time where supported - const creationTime = Moment(created); - - const createdMoment = (Moment('1970-01-01 00:00:00.000').isBefore(creationTime) - ? creationTime - : Moment('1970-01-01 00:00:00.001')).valueOf(); - if (createdMoment) { - utimes(path, {btime: createdMoment}); - } +export const setFileDates = (path: string, created?: string | Date, updated?: string | Date): void => { + const createdTime = created ? Math.max(0, Moment(created).valueOf()) : 0; + const updatedTime = updated ? Math.max(0, Moment(updated).valueOf()) : createdTime; + + utimesSync(path, { + btime: createdTime, + mtime: updatedTime, + atime: updatedTime + }); }; export const getTimeStampMoment = (resource: any): any => { diff --git a/src/utils/filename-utils.ts b/src/utils/filename-utils.ts index ae36abcb..db2a34cd 100644 --- a/src/utils/filename-utils.ts +++ b/src/utils/filename-utils.ts @@ -14,6 +14,7 @@ import { getCreationTime } from './content-utils'; import { escapeStringRegexp } from './escape-string-regexp'; import { isLogseqJournal } from './is-logseq-journal'; import { closest } from 'fastest-levenshtein'; +import { EvernoteNoteData } from '../models'; const applyCharacterMapSafely = (title: string): string => { return applyCharacterMap(title).replace(/[/\\?%*:|"<>\[\]\+]/g, '-'); @@ -88,11 +89,11 @@ export const getResourceFileProperties = (workDir: string, resource: any): Resou }; }; -export const getFilePrefix = (note: any): string => { +export const getFilePrefix = (note: EvernoteNoteData): string => { return normalizeFilenameString(note['noteName'] ? `${note['noteName'].toString()}` : 'Untitled'); }; -export const getNoteFileName = (dstPath: string, note: any, extension: string = 'md'): string => { +export const getNoteFileName = (dstPath: string, note: EvernoteNoteData, extension: string = 'md'): string => { return `${getNoteName(dstPath, note)}.${extension}`; }; export const getExtensionFromResourceFileName = (resource: any): string => { @@ -120,7 +121,7 @@ export const getExtension = (resource: any): string => { return getExtensionFromResourceFileName(resource) || getExtensionFromMime(resource) || UNKNOWNEXTENSION; }; -export const getZettelKastelId = (note: any, dstPath: string): string => { +export const getZettelKastelId = (note: EvernoteNoteData, dstPath: string): string => { return Moment(note['created']).format('YYYYMMDDHHmm'); }; @@ -129,7 +130,7 @@ export const getUniqueId = (): string => { return nanoid(5); }; -export const getNoteName = (dstPath: string, note: any): string => { +export const getNoteName = (dstPath: string, note: EvernoteNoteData): string => { let noteName; if (yarleOptions.isZettelkastenNeeded || yarleOptions.useZettelIdAsFilename) { diff --git a/src/utils/folder-utils.ts b/src/utils/folder-utils.ts index 7bf5f304..b1d318d0 100644 --- a/src/utils/folder-utils.ts +++ b/src/utils/folder-utils.ts @@ -9,11 +9,12 @@ import { getNoteFileName, getNoteName, getUniqueId, normalizeFilenameString } fr import { loggerInfo } from './loggerInfo'; import { OutputFormat } from './../output-format'; import { RuntimePropertiesSingleton } from './../runtime-properties'; +import { EvernoteNoteData } from '../models'; export const paths: Path = {}; const MAX_PATH = 249; -export const getResourceDir = (dstPath: string, note: any): string => { +export const getResourceDir = (dstPath: string, note: EvernoteNoteData): string => { return getNoteName(dstPath, note).replace(/\s/g, '_').substr(0, 50); }; @@ -28,7 +29,7 @@ export const truncatFileName = (fileName: string, uniqueId: string): string =>  return fullPath.length <  MAX_PATH ? fileName : `${fileName.slice(0, MAX_PATH - 11)}_${uniqueId}.md`; }; -const truncateFilePath = (note: any, fileName: string, fullFilePath: string): string => { +const truncateFilePath = (note: EvernoteNoteData, fileName: string, fullFilePath: string): string => { const noteIdNameMap = RuntimePropertiesSingleton.getInstance(); const noteIdMap = noteIdNameMap.getNoteIdNameMapByNoteTitle(normalizeFilenameString(note.title))[0] || {uniqueEnd: getUniqueId()}; @@ -42,25 +43,25 @@ const truncateFilePath = (note: any, fileName: string, fullFilePath: string): st // -11 is the nanoid 5 char +_+ the max possible extension of the note (.md vs .html) }; -const getFilePath = (dstPath: string, note: any, extension: string): string => { +const getFilePath = (dstPath: string, note: EvernoteNoteData, extension: string): string => { const fileName = getNoteFileName(dstPath, note, extension); const fullFilePath = `${dstPath}${path.sep}${normalizeFilenameString(fileName)}`; return fullFilePath.length <  MAX_PATH ? fullFilePath : truncateFilePath(note, fileName, fullFilePath); }; -export const getMdFilePath = (note: any): string => { +export const getMdFilePath = (note: EvernoteNoteData): string => { return getFilePath(paths.mdPath, note, 'md'); }; -export const getJsonFilePath = (note: any): string => { +export const getJsonFilePath = (note: EvernoteNoteData): string => { return getFilePath(paths.mdPath, note, 'json'); }; -export const getHtmlFilePath = (note: any): string => { +export const getHtmlFilePath = (note: EvernoteNoteData): string => { return getFilePath(paths.resourcePath, note, 'html'); }; -export const getHtmlFileLink = (note: any): string => { +export const getHtmlFileLink = (note: EvernoteNoteData): string => { const filePath = getHtmlFilePath(note); return `.${filePath.slice(paths.resourcePath.lastIndexOf(path.sep))}`; @@ -73,7 +74,7 @@ const clearDistDir = (dstPath: string): void => { fs.mkdirSync(dstPath); }; -export const getRelativeResourceDir = (note: any): string => { +export const getRelativeResourceDir = (note: EvernoteNoteData): string => { const enexFolder = `${path.sep}${yarleOptions.resourcesDir}`; if (yarleOptions.haveGlobalResources) { return `..${enexFolder}`; @@ -90,7 +91,7 @@ export const createRootOutputDir = (): void => { : `${process.cwd()}${path.sep}${yarleOptions.outputDir}`; fsExtra.mkdirsSync(outputDir) } -export const getAbsoluteResourceDir = (note: any): string => { +export const getAbsoluteResourceDir = (note: EvernoteNoteData): string => { if (yarleOptions.haveGlobalResources) { return path.resolve(paths.resourcePath, '..', '..', yarleOptions.resourcesDir); } @@ -101,7 +102,7 @@ export const getAbsoluteResourceDir = (note: any): string => { }; const resourceDirClears = new Map(); -export const clearResourceDir = (note: any): void => { +export const clearResourceDir = (note: EvernoteNoteData): void => { const resPath = getAbsoluteResourceDir(note); if (!resourceDirClears.has(resPath)) { resourceDirClears.set(resPath, 0); diff --git a/src/utils/save-html-file.ts b/src/utils/save-html-file.ts index e29cd707..dfe75e04 100644 --- a/src/utils/save-html-file.ts +++ b/src/utils/save-html-file.ts @@ -1,8 +1,8 @@ -import { NoteData } from './../models'; +import { EvernoteNoteData, NoteData } from './../models'; import { getHtmlFilePath } from '.'; import { writeFile } from './file-utils'; -export const saveHtmlFile = (noteData: NoteData, note: any) => { +export const saveHtmlFile = (noteData: NoteData, note: EvernoteNoteData) => { if (noteData.htmlContent) { const absHtmlFilePath = getHtmlFilePath(note); writeFile(absHtmlFilePath, noteData.htmlContent, note); diff --git a/src/utils/save-md-file.ts b/src/utils/save-md-file.ts index 9d64bff9..4dfcc80b 100644 --- a/src/utils/save-md-file.ts +++ b/src/utils/save-md-file.ts @@ -1,14 +1,13 @@ -import { NoteData } from './../models'; +import { EvernoteNoteData, NoteData } from './../models'; import { RuntimePropertiesSingleton } from './../runtime-properties'; import { writeFile } from './file-utils'; import { getMdFilePath } from './folder-utils'; import { loggerInfo } from './loggerInfo'; -export const saveMdFile = (noteContent: string, note: NoteData) => { - - const absMdFilePath = getMdFilePath(note); +export const saveMdFile = (noteContent: string, note: NoteData, pureNote: EvernoteNoteData) => { + const absMdFilePath = getMdFilePath(pureNote); const runtimeProps = RuntimePropertiesSingleton.getInstance(); runtimeProps.setCurrentNotePath(absMdFilePath); - writeFile(absMdFilePath, noteContent, note); + writeFile(absMdFilePath, noteContent, pureNote); loggerInfo(`Note saved to ${absMdFilePath}`); }; diff --git a/test/utils.spec.ts b/test/utils.spec.ts index 2beb8875..4492d63a 100644 --- a/test/utils.spec.ts +++ b/test/utils.spec.ts @@ -1,5 +1,5 @@ import assert from 'assert'; -import fs from 'fs'; +import fs, { fstat } from 'fs'; import parser from 'fast-xml-parser'; import moment from 'moment'; @@ -40,16 +40,18 @@ describe('SetFileDates', () => { assert.ok(errorHappened); }); - it('set to now if no updated field in note', () => { + it('set to created time if no updated field in note', () => { notes['note']['updated'] = undefined; utils.setFileDates('./test/data/test-justText.enex', notes['note']['created'], notes['note']['updated']); const fStat = fs.statSync('./test/data/test-justText.enex'); - const atime = moment(fStat.atime); - const mtime = moment(fStat.mtime); - const referTimeLo = moment().subtract(3, 's'); - const referTimeHi = moment().add(3, 's'); - assert.ok(atime.isBetween(referTimeLo, referTimeHi)); - assert.ok(mtime.isBetween(referTimeLo, referTimeHi)); + const created = moment(notes['note']['created']).valueOf() + + const btime = fStat.birthtime.valueOf(); + const atime = fStat.atime.valueOf(); + const mtime = fStat.mtime.valueOf(); + assert.equal(btime, created) + assert.equal(atime, created) + assert.equal(mtime, created) }); });