diff --git a/lib/package-lock.json b/lib/package-lock.json index f3bbcf8..1769636 100644 --- a/lib/package-lock.json +++ b/lib/package-lock.json @@ -13,7 +13,8 @@ "papaparse": "^5.3.1", "pretty": "^2.0.0", "snake-case": "^3.0.4", - "ua-parser-js": "^1.0.2" + "ua-parser-js": "^1.0.2", + "vcard4-ts": "^0.4.1" }, "devDependencies": { "@types/node": "^17.0.12", @@ -536,6 +537,14 @@ "node": "*" } }, + "node_modules/vcard4-ts": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/vcard4-ts/-/vcard4-ts-0.4.1.tgz", + "integrity": "sha512-dg2PWsDt+FNKPo6ZjfgDoWp9ylLDRn7c85db+ylI9srkXDp0pz1DTOmANE5ZzBQV3sDokILGZ6kBFZ16vYNwcw==", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -945,6 +954,11 @@ "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.2.tgz", "integrity": "sha512-00y/AXhx0/SsnI51fTc0rLRmafiGOM4/O+ny10Ps7f+j/b8p/ZY11ytMgznXkOVo4GQ+KwQG5UQLkLGirsACRg==" }, + "vcard4-ts": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/vcard4-ts/-/vcard4-ts-0.4.1.tgz", + "integrity": "sha512-dg2PWsDt+FNKPo6ZjfgDoWp9ylLDRn7c85db+ylI9srkXDp0pz1DTOmANE5ZzBQV3sDokILGZ6kBFZ16vYNwcw==" + }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", diff --git a/lib/package.json b/lib/package.json index f796a6c..1526057 100644 --- a/lib/package.json +++ b/lib/package.json @@ -13,7 +13,8 @@ "papaparse": "^5.3.1", "pretty": "^2.0.0", "snake-case": "^3.0.4", - "ua-parser-js": "^1.0.2" + "ua-parser-js": "^1.0.2", + "vcard4-ts": "^0.4.1" }, "devDependencies": { "@types/node": "^17.0.12", diff --git a/lib/postProcessing/postProcessingCategoriser.ts b/lib/postProcessing/postProcessingCategoriser.ts index c1e5648..3212962 100644 --- a/lib/postProcessing/postProcessingCategoriser.ts +++ b/lib/postProcessing/postProcessingCategoriser.ts @@ -18,7 +18,10 @@ import { TwitterTweetsPostProcess } from './postProcessors/twitter' import { TextPostProcess } from './postProcessors/genericFallbacks/text' -import { ContactsCsvPostProcess } from './postProcessors/contacts' +import { + ContactsCsvPostProcess, + ContactsVcfPostProcess +} from './postProcessors/contacts' import { KeyValuePostProcess, NestedArrayPostProcess, @@ -57,6 +60,7 @@ const postProcessors = { TwitterFallbackPostProcess, TwitterManifestPostProcess, ContactsCsvPostProcess, + ContactsVcfPostProcess, YouTubeWatchHistoryPostProcess, YouTubeSearchHistoryPostProcess, DefaultHtmlPostProcess, diff --git a/lib/postProcessing/postProcessors/contacts.ts b/lib/postProcessing/postProcessors/contacts.ts index 0c5acbf..a4f75ab 100644 --- a/lib/postProcessing/postProcessors/contacts.ts +++ b/lib/postProcessing/postProcessors/contacts.ts @@ -1,5 +1,6 @@ import { PostProcess } from '../../typedefs/PostProcess' import { processContacts } from '../../vendors/google/Contacts' +import { processVCardContacts } from '../../vendors/google/VCardContacts' export const ContactsCsvPostProcess: PostProcess = { name: 'Contacts', @@ -15,3 +16,16 @@ export const ContactsCsvPostProcess: PostProcess = { component: 'VaadinGrid', postProcessingFunction: processContacts } + +export const ContactsVcfPostProcess: PostProcess = { + name: 'Contacts', + code: 'contacts-vcf', + classifier: { + topLevelIsArray: true, + filenameRegex: /^.+\.vcf$/, + preProcessingCategory: 'vcard', + itemCriteria: {} + }, + component: 'VaadinGrid', + postProcessingFunction: processVCardContacts +} diff --git a/lib/preProcessing/preProcessingCategoriser.ts b/lib/preProcessing/preProcessingCategoriser.ts index 63f06c4..d57fe92 100644 --- a/lib/preProcessing/preProcessingCategoriser.ts +++ b/lib/preProcessing/preProcessingCategoriser.ts @@ -46,6 +46,11 @@ const preProcessingTesters: PreProcessingTester[] = [ filenameRegex: /\.html$/, fileTypes: ['text/html'], preProcessingCategory: 'html' + }, + { + filenameRegex: /\.vcf$/, + fileTypes: ['text/x-vcard'], + preProcessingCategory: 'vcard' } ] diff --git a/lib/preProcessing/preProcessorMap.ts b/lib/preProcessing/preProcessorMap.ts index 5922933..6658085 100644 --- a/lib/preProcessing/preProcessorMap.ts +++ b/lib/preProcessing/preProcessorMap.ts @@ -7,6 +7,7 @@ import { twitterJsPreProcessor } from './preProcessors/twitterJs' import { videoPreProcessor } from './preProcessors/video' import { imagePreProcessor } from './preProcessors/image' import { htmlPreProcessor } from './preProcessors/html' +import { vcardPreProcessor } from './preProcessors/vcard' export const preProcessorMap: { [key in PreProcessingCategory]: PreProcessor } = { @@ -17,5 +18,6 @@ export const preProcessorMap: { [key in PreProcessingCategory]: PreProcessor } = twitterJs: twitterJsPreProcessor, image: imagePreProcessor, video: videoPreProcessor, - html: htmlPreProcessor + html: htmlPreProcessor, + vcard: vcardPreProcessor } diff --git a/lib/preProcessing/preProcessors/vcard.ts b/lib/preProcessing/preProcessors/vcard.ts new file mode 100644 index 0000000..27649e3 --- /dev/null +++ b/lib/preProcessing/preProcessors/vcard.ts @@ -0,0 +1,16 @@ +import { PreProcessor } from '../../typedefs/PreProcess' +import { ParsedVCards, parseVCards, sortByPREF } from 'vcard4-ts' + +export const vcardPreProcessor: PreProcessor = ({ + filename, + fileType, + fileContent +}) => { + const { nags, vCards } = parseVCards(fileContent, true) + const { length } = vCards + return { + data: vCards, + title: filename, + metadata: { length, nags } + } +} diff --git a/lib/typedefs/PreProcess.ts b/lib/typedefs/PreProcess.ts index 7481062..9e30fe5 100644 --- a/lib/typedefs/PreProcess.ts +++ b/lib/typedefs/PreProcess.ts @@ -7,6 +7,7 @@ export type PreProcessingCategory = | 'image' | 'video' | 'html' + | 'vcard' export type PreProcessingTester = { // tests filenameRegex?: RegExp diff --git a/lib/vendors/google/Contacts.ts b/lib/vendors/google/Contacts.ts index d8fe549..c3e60f7 100644 --- a/lib/vendors/google/Contacts.ts +++ b/lib/vendors/google/Contacts.ts @@ -87,7 +87,6 @@ export const processContacts: PostProcessor = ({ preProcessedOutput: { data, metadata } }) => { const { fields } = metadata - console.log(data) const contacts: Contact[] = [] for (const contact of data) { contacts.push({ @@ -122,7 +121,7 @@ export const processContacts: PostProcessor = ({ } } -function generateContacts(qty = 10): CsvContacts { +function generateCsvContacts(qty = 10): CsvContacts { const contacts = new Set() for (let i = 0; i < qty; i++) { const Name = getRandomFullName() @@ -141,6 +140,6 @@ function generateContacts(qty = 10): CsvContacts { } export function generateContactsFile(qty = 10): string { - const contacts = generateContacts(qty) + const contacts = generateCsvContacts(qty) return Papa.unparse(contacts) } diff --git a/lib/vendors/google/VCardContacts.ts b/lib/vendors/google/VCardContacts.ts new file mode 100644 index 0000000..c9758d2 --- /dev/null +++ b/lib/vendors/google/VCardContacts.ts @@ -0,0 +1,35 @@ +import { ParsedVCards } from 'vcard4-ts' +import { PostProcessor } from '../../typedefs/PostProcess' +import { Contact, CsvContacts } from './Contacts' + +export const processVCardContacts: PostProcessor< + ParsedVCards['vCards'], + Contact[] +> = ({ preProcessedOutput: { data, metadata, title } }) => { + const contacts: Contact[] = [] + for (const contact of data) { + contacts.push({ + address: contact.ADR?.[0] + ? { + postCode: contact.ADR[0].value.postalCode?.[0], + streetAddress: contact.ADR[0].value.streetAddress?.[0] + } + : null, + emailAddresses: contact.EMAIL?.map((t) => ({ + label: t.parameters?.TYPE?.at(0), + emailAddress: t.value + })), + firstName: contact.N?.value.givenNames.join(' '), + fullName: contact.FN[0]?.value, + lastName: contact.N?.value.familyNames.join(' '), + organisation: contact.ORG?.[0]?.value[0], + otherDetails: contact.x, + phoneNumbers: contact.TEL?.map((t) => ({ + label: t.parameters?.TYPE?.[0], + phoneNumber: t.value + })), + profilePictureUrl: contact.PHOTO?.[0]?.value + }) + } + return { data: contacts, metadata, title } +}