Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: timestamp of MD file #624

Merged
merged 4 commits into from
Apr 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/models/NoteData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export interface NoteData {
}

export interface EvernoteNoteData {
_type_id: 'EvernoteNoteData';
title?: string;
created?: string;
updated?: string;
Expand Down
3 changes: 1 addition & 2 deletions src/outputLanguages/StandardMD.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<string, string>, currentTaskPlaceholder: string, updatedContent: string): string => {
return updatedContent;
Expand Down
6 changes: 3 additions & 3 deletions src/process-resources.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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';
Expand Down
25 changes: 10 additions & 15 deletions src/utils/content-utils.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -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 => {
Expand Down
9 changes: 5 additions & 4 deletions src/utils/filename-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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, '-');
Expand Down Expand Up @@ -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 => {
Expand Down Expand Up @@ -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');

};
Expand All @@ -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) {
Expand Down
21 changes: 11 additions & 10 deletions src/utils/folder-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,13 @@ import { yarleOptions } from '../yarle';
import { getNoteFileName, getNoteName, getUniqueId, normalizeFilenameString } from './filename-utils';
import { OutputFormat } from './../output-format';
import { RuntimePropertiesSingleton } from './../runtime-properties';
import { EvernoteNoteData } from '../models';
import { loggerInfo } from './loggerInfo';

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);
};

Expand All @@ -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()};
Expand All @@ -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);
const relativePath = `.${filePath.slice(paths.resourcePath.lastIndexOf(path.sep))}`;
if (yarleOptions.posixHtmlPath && path.sep !== path.posix.sep) {
Expand All @@ -76,7 +77,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}`;
Expand All @@ -93,7 +94,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);
}
Expand All @@ -104,7 +105,7 @@ export const getAbsoluteResourceDir = (note: any): string => {
};

const resourceDirClears = new Map<string, number>();
export const clearResourceDir = (note: any): void => {
export const clearResourceDir = (note: EvernoteNoteData): void => {
const resPath = getAbsoluteResourceDir(note);
if (!resourceDirClears.has(resPath)) {
resourceDirClears.set(resPath, 0);
Expand Down
4 changes: 2 additions & 2 deletions src/utils/save-html-file.ts
Original file line number Diff line number Diff line change
@@ -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);
Expand Down
9 changes: 4 additions & 5 deletions src/utils/save-md-file.ts
Original file line number Diff line number Diff line change
@@ -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}`);
};
31 changes: 18 additions & 13 deletions test/utils.spec.ts
Original file line number Diff line number Diff line change
@@ -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';

Expand Down Expand Up @@ -40,19 +40,24 @@ describe('SetFileDates', () => {
assert.ok(errorHappened);

});
it('set to now 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));
});
it('set to created time if no updated field in note', () => {
notes['note']['updated'] = undefined;
const { birthtime: oldBirthtime } = fs.statSync('./test/data/test-justText.enex');
utils.setFileDates('./test/data/test-justText.enex', notes['note']['created'], notes['note']['updated']);
const fStat = fs.statSync('./test/data/test-justText.enex');
const created = moment(notes['note']['created']).valueOf();

});
const btime = fStat.birthtime.valueOf();
const atime = fStat.atime.valueOf();
const mtime = fStat.mtime.valueOf();

// Linux does not support setting btime, so btime maybe equal to previous value
// see: https://www.npmjs.com/package/utimes#caveats
assert.ok(btime === created || btime === oldBirthtime.valueOf());
assert.equal(atime, created);
assert.equal(mtime, created);
});
});

describe('file utils', () => {
it('update file content safely', () => {
Expand Down