mirror of
https://github.com/broekema41/obsidian-vcf-contacts.git
synced 2026-07-22 05:42:58 +00:00
Refs #32: Moving obsidion Notice outside the vcard module
This commit is contained in:
parent
b51052f239
commit
dc32e87c62
6 changed files with 101 additions and 42 deletions
11
src/contacts/vcard/shared/vcard.d.ts
vendored
11
src/contacts/vcard/shared/vcard.d.ts
vendored
|
|
@ -33,3 +33,14 @@ export enum VCardSupportedKey {
|
|||
export interface VCardForObsidianRecord {
|
||||
[key: string]: string,
|
||||
}
|
||||
|
||||
export interface VCardToStringError {
|
||||
status: string;
|
||||
file: string;
|
||||
message: string;
|
||||
}
|
||||
|
||||
export interface VCardToStringReply {
|
||||
vcards: string;
|
||||
errors: VCardToStringError[];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import { Notice, TFile } from "obsidian";
|
||||
import { TFile } from "obsidian";
|
||||
import { parseKey } from "src/contacts";
|
||||
import { StructuredFields } from "src/contacts/vcard/shared/structuredFields";
|
||||
import { VCardToStringError, VCardToStringReply } from "src/contacts/vcard/shared/vcard";
|
||||
import { getApp } from "src/context/sharedAppContext";
|
||||
|
||||
function filterNonNull<T>(array: (T | null | undefined)[]): T[] {
|
||||
|
|
@ -39,45 +40,54 @@ function renderSingleKey([key, value]:[string, string]):string {
|
|||
}
|
||||
|
||||
function generateVCard(file: TFile): string {
|
||||
try {
|
||||
const { metadataCache } = getApp();
|
||||
const frontMatter = metadataCache.getFileCache(file)?.frontmatter;
|
||||
if (!frontMatter) return "";
|
||||
const { metadataCache } = getApp();
|
||||
const frontMatter = metadataCache.getFileCache(file)?.frontmatter;
|
||||
if (!frontMatter) return "";
|
||||
|
||||
const entries = Object.entries(frontMatter) as Array<[string, string]>;
|
||||
const entries = Object.entries(frontMatter) as Array<[string, string]>;
|
||||
|
||||
const singleLineFields: Array<[string, string]> = [];
|
||||
const structuredFields: Array<[string, string]> = [];
|
||||
const singleLineFields: Array<[string, string]> = [];
|
||||
const structuredFields: Array<[string, string]> = [];
|
||||
|
||||
singleLineFields.push(['FN', file.basename]);
|
||||
singleLineFields.push(['FN', file.basename]);
|
||||
|
||||
entries.forEach(([key, value]) => {
|
||||
const keyObj = parseKey(key);
|
||||
entries.forEach(([key, value]) => {
|
||||
const keyObj = parseKey(key);
|
||||
|
||||
if (['ADR', 'N'].includes(keyObj.key)) {
|
||||
structuredFields.push([key, value]);
|
||||
} else if(['VERSION'].includes(keyObj.key) ) {
|
||||
// we target always v4 output
|
||||
singleLineFields.push(['VERSION', '4.0']);
|
||||
} else {
|
||||
singleLineFields.push([key, value]);
|
||||
}
|
||||
});
|
||||
if (['ADR', 'N'].includes(keyObj.key)) {
|
||||
structuredFields.push([key, value]);
|
||||
} else if(['VERSION'].includes(keyObj.key) ) {
|
||||
// we target always v4 output
|
||||
singleLineFields.push(['VERSION', '4.0']);
|
||||
} else {
|
||||
singleLineFields.push([key, value]);
|
||||
}
|
||||
});
|
||||
|
||||
const structuredLines = renderStructuredLines(structuredFields);
|
||||
const singleLines = singleLineFields.map(renderSingleKey);
|
||||
const lines = structuredLines.concat(singleLines);
|
||||
const structuredLines = renderStructuredLines(structuredFields);
|
||||
const singleLines = singleLineFields.map(renderSingleKey);
|
||||
const lines = structuredLines.concat(singleLines);
|
||||
|
||||
return `BEGIN:VCARD\n${lines.join("\n")}\nEND:VCARD`;
|
||||
|
||||
return `BEGIN:VCARD\n${lines.join("\n")}\nEND:VCARD`;
|
||||
} catch (err) {
|
||||
new Notice(`${err.message} in file skipping ${file.basename}`);
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
export async function toString(contactFiles: TFile[]): Promise<string> {
|
||||
return contactFiles
|
||||
.map(file => generateVCard(file))
|
||||
.filter(vcard => vcard !== "") // Remove empty results
|
||||
.join("\n");
|
||||
export async function toString(contactFiles: TFile[]): Promise<VCardToStringReply> {
|
||||
const vCards: string[] = [];
|
||||
const vCardsErrors: VCardToStringError[] = [];
|
||||
|
||||
contactFiles.forEach((file) => {
|
||||
try {
|
||||
const singleVcard = generateVCard(file)
|
||||
vCards.push(singleVcard)
|
||||
} catch (err) {
|
||||
vCardsErrors.push({"status": "error", "file": file.basename, "message": err.message})
|
||||
}
|
||||
})
|
||||
|
||||
return Promise.resolve({
|
||||
vcards: vCards.join('\n'),
|
||||
errors: vCardsErrors
|
||||
});
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -122,7 +122,10 @@ export const SidebarRootView = (props: SidebarRootViewProps) => {
|
|||
}}
|
||||
exportAllVCF={async() => {
|
||||
const allContactFiles = contacts.map((contact)=> contact.file)
|
||||
const vcards = await vcard.toString(allContactFiles);
|
||||
const {vcards, errors} = await vcard.toString(allContactFiles);
|
||||
errors.forEach((err) => {
|
||||
new Notice(`${err.message} in file skipping ${err.file}`);
|
||||
})
|
||||
saveVcardFilePicker(vcards)
|
||||
}}
|
||||
onCreateContact={async () => {
|
||||
|
|
@ -155,7 +158,10 @@ export const SidebarRootView = (props: SidebarRootViewProps) => {
|
|||
}}
|
||||
exportVCF={(contactFile: TFile) => {
|
||||
(async () => {
|
||||
const vcards = await vcard.toString([contactFile])
|
||||
const {vcards, errors} = await vcard.toString([contactFile])
|
||||
errors.forEach((err) => {
|
||||
new Notice(`${err.message} in file skipping ${err.file}`);
|
||||
})
|
||||
saveVcardFilePicker(vcards, contactFile)
|
||||
})();
|
||||
}} />
|
||||
|
|
|
|||
9
tests/fixtures/basic.frontmatter.js
vendored
Normal file
9
tests/fixtures/basic.frontmatter.js
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
module.exports = {
|
||||
'N.FN': 'Jan',
|
||||
'N.GN': 'Huntelaar',
|
||||
BDAY: '1980-08-17',
|
||||
'BDAY[Child,junior]': '1989-06-12',
|
||||
ANNIVERSARY: '2001-09-22',
|
||||
'ANNIVERSARY[1:]': '1999-06-11',
|
||||
VERSION: '4.0'
|
||||
}
|
||||
13
tests/fixtures/fixtures.ts
vendored
13
tests/fixtures/fixtures.ts
vendored
|
|
@ -1,11 +1,18 @@
|
|||
import { readFileSync } from 'fs';
|
||||
import { join } from 'path';
|
||||
import { join, resolve } from 'path';
|
||||
|
||||
export function readVcfFixture(fileName: string): string {
|
||||
const filePath = join(__dirname, fileName);
|
||||
return readFileSync(filePath, 'utf8');
|
||||
}
|
||||
|
||||
export const fixtures = {
|
||||
readVcfFixture
|
||||
export function readFrontmatterFixture(fileName: string): Record<string, any> {
|
||||
const fullPath = resolve(__dirname, fileName + '.js');
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
return require(fullPath);
|
||||
}
|
||||
|
||||
export const fixtures = {
|
||||
readVcfFixture,
|
||||
readFrontmatterFixture
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,20 @@
|
|||
import { App } from "obsidian";
|
||||
import { App, TFile } from "obsidian";
|
||||
import { vcard } from "src/contacts/vcard";
|
||||
import { setApp } from "src/context/sharedAppContext";
|
||||
import { fixtures } from "tests/fixtures/fixtures";
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
|
||||
setApp({} as App);
|
||||
setApp({
|
||||
metadataCache: {
|
||||
getFileCache: (file: TFile) => {
|
||||
console.log(file.basename);
|
||||
const frontmatter = fixtures.readFrontmatterFixture(file.basename);
|
||||
return {
|
||||
frontmatter
|
||||
};
|
||||
}
|
||||
}
|
||||
} as unknown as App);
|
||||
|
||||
vi.mock('src/ui/modals/contactNameModal', () => {
|
||||
class ContactNameModal {
|
||||
|
|
@ -134,7 +144,13 @@ describe('vcard parse', () => {
|
|||
expect(result[0]['N.FN']).toBe('Jan');
|
||||
expect(result[0]['NOTE']).toBe('This is a long note that continues on the next line, and still keeps going.');
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
||||
|
||||
describe('vcard tostring', () => {
|
||||
it('should be able to turn basic frontmatter to vcf string', async () => {
|
||||
const result = await vcard.toString([{ basename: 'basic.frontmatter' } as TFile]);
|
||||
console.log(result);
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in a new issue