vcf-to-json-converter 1.0.1 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (5) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +457 -457
  3. package/index.d.ts +32 -32
  4. package/index.js +252 -252
  5. package/package.json +5 -4
package/index.d.ts CHANGED
@@ -1,32 +1,32 @@
1
- export interface Phone {
2
- value: string;
3
- type: string;
4
- }
5
-
6
- export interface Email {
7
- value: string;
8
- type: string;
9
- }
10
-
11
- export interface Contact {
12
- fullName: string;
13
- firstName: string;
14
- lastName: string;
15
- phones: Phone[];
16
- emails: Email[];
17
- organization: string;
18
- title: string;
19
- note: string;
20
- photo: string;
21
- url: string;
22
- raw: any;
23
- }
24
-
25
- export declare function vcfToJson(vcfText: string): Contact[];
26
- export declare function vcfToJsonFromFile(filePath: string): Contact[];
27
- export declare function saveJsonToFile(
28
- jsonData: Contact[],
29
- outputPath: string,
30
- prettyPrint?: boolean
31
- ): void;
32
- export declare function cli(): void;
1
+ export interface Phone {
2
+ value: string;
3
+ type: string;
4
+ }
5
+
6
+ export interface Email {
7
+ value: string;
8
+ type: string;
9
+ }
10
+
11
+ export interface Contact {
12
+ fullName: string;
13
+ firstName: string;
14
+ lastName: string;
15
+ phones: Phone[];
16
+ emails: Email[];
17
+ organization: string;
18
+ title: string;
19
+ note: string;
20
+ photo: string;
21
+ url: string;
22
+ raw: any;
23
+ }
24
+
25
+ export declare function vcfToJson(vcfText: string): Contact[];
26
+ export declare function vcfToJsonFromFile(filePath: string): Contact[];
27
+ export declare function saveJsonToFile(
28
+ jsonData: Contact[],
29
+ outputPath: string,
30
+ prettyPrint?: boolean
31
+ ): void;
32
+ export declare function cli(): void;
package/index.js CHANGED
@@ -1,252 +1,252 @@
1
- const fs = require("fs");
2
- const path = require("path");
3
-
4
- /**
5
- * Manual VCF parser that properly extracts contact information
6
- * @param {string} vcfText - The VCF content as string
7
- * @returns {Array} Array of contact objects
8
- */
9
- function parseVCF(vcfText) {
10
- const contacts = [];
11
-
12
- // Split by BEGIN:VCARD to handle multiple contacts
13
- const vCards = vcfText.split("BEGIN:VCARD").filter((card) => card.trim());
14
-
15
- for (const vCard of vCards) {
16
- const lines = vCard.split(/\r?\n/).filter((line) => line.trim());
17
-
18
- const contact = {
19
- fullName: "",
20
- firstName: "",
21
- lastName: "",
22
- phones: [],
23
- emails: [],
24
- organization: "",
25
- title: "",
26
- note: "",
27
- photo: "",
28
- url: "",
29
- raw: vCard, // Store original vCard text
30
- };
31
-
32
- for (const line of lines) {
33
- // Parse FN (Formatted Name) - supports UTF-8/Hindi
34
- if (line.startsWith("FN:")) {
35
- contact.fullName = line.substring(3).trim();
36
- }
37
-
38
- // Parse N (Name) for first and last name
39
- if (line.startsWith("N:")) {
40
- const nameParts = line.substring(2).split(";");
41
- // Format: Last;First;Middle;Prefix;Suffix
42
- contact.lastName = (nameParts[0] || "").trim();
43
- contact.firstName = (nameParts[1] || "").trim();
44
-
45
- // If fullName is empty, construct it from first and last name
46
- if (!contact.fullName) {
47
- contact.fullName = `${contact.firstName} ${contact.lastName}`.trim();
48
- }
49
- }
50
-
51
- // Parse TEL (Phone)
52
- if (line.startsWith("TEL")) {
53
- const phoneMatch = line.match(/:([\d\s\-+()]+)/);
54
- if (phoneMatch) {
55
- // Extract phone type from the TEL line
56
- let phoneType = "unknown";
57
- if (line.includes("CELL")) phoneType = "mobile";
58
- else if (line.includes("HOME")) phoneType = "home";
59
- else if (line.includes("WORK")) phoneType = "work";
60
- else if (line.includes("VOICE")) phoneType = "voice";
61
- else if (line.includes("PREF")) phoneType = "primary";
62
-
63
- contact.phones.push({
64
- value: phoneMatch[1].trim(),
65
- type: phoneType,
66
- });
67
- }
68
- }
69
-
70
- // Parse EMAIL
71
- if (line.startsWith("EMAIL")) {
72
- const emailMatch = line.match(/:(.+)/);
73
- if (emailMatch) {
74
- // Extract email type from the EMAIL line
75
- let emailType = "unknown";
76
- if (line.includes("HOME")) emailType = "home";
77
- else if (line.includes("WORK")) emailType = "work";
78
- else if (line.includes("PREF")) emailType = "primary";
79
-
80
- contact.emails.push({
81
- value: emailMatch[1].trim(),
82
- type: emailType,
83
- });
84
- }
85
- }
86
-
87
- // Parse ORG (Organization)
88
- if (line.startsWith("ORG:")) {
89
- contact.organization = line.substring(4).trim();
90
- }
91
-
92
- // Parse TITLE
93
- if (line.startsWith("TITLE:")) {
94
- contact.title = line.substring(6).trim();
95
- }
96
-
97
- // Parse NOTE
98
- if (line.startsWith("NOTE:")) {
99
- contact.note = line.substring(5).trim();
100
- }
101
-
102
- // Parse URL
103
- if (line.startsWith("URL:")) {
104
- contact.url = line.substring(4).trim();
105
- }
106
-
107
- // Parse PHOTO (basic support)
108
- if (line.startsWith("PHOTO:")) {
109
- contact.photo = line.substring(6).trim();
110
- }
111
- }
112
-
113
- // Only add contact if it has meaningful data
114
- if (
115
- contact.fullName ||
116
- contact.firstName ||
117
- contact.lastName ||
118
- contact.phones.length > 0
119
- ) {
120
- contacts.push(contact);
121
- }
122
- }
123
-
124
- return contacts;
125
- }
126
-
127
- /**
128
- * Convert VCF text content to JSON
129
- * @param {string} vcfText - The VCF content as string
130
- * @returns {Array} Array of contact objects
131
- */
132
- function vcfToJson(vcfText) {
133
- if (!vcfText || typeof vcfText !== "string") {
134
- throw new Error("Invalid VCF content. Expected non-empty string.");
135
- }
136
-
137
- try {
138
- return parseVCF(vcfText);
139
- } catch (error) {
140
- throw new Error(`Failed to parse VCF content: ${error.message}`);
141
- }
142
- }
143
-
144
- /**
145
- * Convert VCF file to JSON
146
- * @param {string} filePath - Path to the VCF file
147
- * @returns {Array} Array of contact objects
148
- */
149
- function vcfToJsonFromFile(filePath) {
150
- if (!filePath || typeof filePath !== "string") {
151
- throw new Error("File path is required and must be a string.");
152
- }
153
-
154
- try {
155
- if (!fs.existsSync(filePath)) {
156
- throw new Error(`File not found: ${filePath}`);
157
- }
158
-
159
- const vcfText = fs.readFileSync(filePath, "utf8");
160
- return vcfToJson(vcfText);
161
- } catch (error) {
162
- if (error.code === "ENOENT") {
163
- throw new Error(`File not found: ${filePath}`);
164
- }
165
- if (error.code === "EACCES") {
166
- throw new Error(`Permission denied: ${filePath}`);
167
- }
168
- throw error;
169
- }
170
- }
171
-
172
- /**
173
- * Save JSON data to file
174
- * @param {Array} jsonData - The JSON data to save
175
- * @param {string} outputPath - Path to save the JSON file
176
- * @param {boolean} prettyPrint - Whether to format JSON with indentation
177
- */
178
- function saveJsonToFile(jsonData, outputPath, prettyPrint = true) {
179
- if (!outputPath || typeof outputPath !== "string") {
180
- throw new Error("Output path is required and must be a string.");
181
- }
182
-
183
- try {
184
- const jsonString = prettyPrint
185
- ? JSON.stringify(jsonData, null, 2)
186
- : JSON.stringify(jsonData);
187
-
188
- fs.writeFileSync(outputPath, jsonString, "utf8");
189
- } catch (error) {
190
- throw new Error(`Failed to save JSON file: ${error.message}`);
191
- }
192
- }
193
-
194
- /**
195
- * CLI function to convert VCF to JSON
196
- */
197
- function cli() {
198
- const args = process.argv.slice(2);
199
-
200
- if (args.length === 0 || args.includes("--help") || args.includes("-h")) {
201
- console.log(`
202
- VCF to JSON Converter
203
-
204
- Usage:
205
- vcf-to-json <input.vcf> [output.json] [options]
206
-
207
- Options:
208
- --compact, -c Output compact JSON (no formatting)
209
- --help, -h Show this help message
210
-
211
- Examples:
212
- vcf-to-json contacts.vcf
213
- vcf-to-json contacts.vcf output.json
214
- vcf-to-json contacts.vcf output.json --compact
215
- `);
216
- return;
217
- }
218
-
219
- const inputFile = args[0];
220
- const outputFile = args[1] || inputFile.replace(/\.vcf$/i, ".json");
221
- const compact = args.includes("--compact") || args.includes("-c");
222
-
223
- try {
224
- console.log(`Converting ${inputFile} to JSON...`);
225
- const jsonData = vcfToJsonFromFile(inputFile);
226
-
227
- if (args[1]) {
228
- saveJsonToFile(jsonData, outputFile, !compact);
229
- console.log(
230
- `✅ Converted ${jsonData.length} contacts and saved to ${outputFile}`
231
- );
232
- } else {
233
- console.log(JSON.stringify(jsonData, null, compact ? 0 : 2));
234
- }
235
- } catch (error) {
236
- console.error(`❌ Error: ${error.message}`);
237
- process.exit(1);
238
- }
239
- }
240
-
241
- // Export functions
242
- module.exports = {
243
- vcfToJson,
244
- vcfToJsonFromFile,
245
- saveJsonToFile,
246
- cli,
247
- };
248
-
249
- // If this file is run directly, execute CLI
250
- if (require.main === module) {
251
- cli();
252
- }
1
+ const fs = require("fs");
2
+ const path = require("path");
3
+
4
+ /**
5
+ * Manual VCF parser that properly extracts contact information
6
+ * @param {string} vcfText - The VCF content as string
7
+ * @returns {Array} Array of contact objects
8
+ */
9
+ function parseVCF(vcfText) {
10
+ const contacts = [];
11
+
12
+ // Split by BEGIN:VCARD to handle multiple contacts
13
+ const vCards = vcfText.split("BEGIN:VCARD").filter((card) => card.trim());
14
+
15
+ for (const vCard of vCards) {
16
+ const lines = vCard.split(/\r?\n/).filter((line) => line.trim());
17
+
18
+ const contact = {
19
+ fullName: "",
20
+ firstName: "",
21
+ lastName: "",
22
+ phones: [],
23
+ emails: [],
24
+ organization: "",
25
+ title: "",
26
+ note: "",
27
+ photo: "",
28
+ url: "",
29
+ raw: vCard, // Store original vCard text
30
+ };
31
+
32
+ for (const line of lines) {
33
+ // Parse FN (Formatted Name) - supports UTF-8/Hindi
34
+ if (line.startsWith("FN:")) {
35
+ contact.fullName = line.substring(3).trim();
36
+ }
37
+
38
+ // Parse N (Name) for first and last name
39
+ if (line.startsWith("N:")) {
40
+ const nameParts = line.substring(2).split(";");
41
+ // Format: Last;First;Middle;Prefix;Suffix
42
+ contact.lastName = (nameParts[0] || "").trim();
43
+ contact.firstName = (nameParts[1] || "").trim();
44
+
45
+ // If fullName is empty, construct it from first and last name
46
+ if (!contact.fullName) {
47
+ contact.fullName = `${contact.firstName} ${contact.lastName}`.trim();
48
+ }
49
+ }
50
+
51
+ // Parse TEL (Phone)
52
+ if (line.startsWith("TEL")) {
53
+ const phoneMatch = line.match(/:([\d\s\-+()]+)/);
54
+ if (phoneMatch) {
55
+ // Extract phone type from the TEL line
56
+ let phoneType = "unknown";
57
+ if (line.includes("CELL")) phoneType = "mobile";
58
+ else if (line.includes("HOME")) phoneType = "home";
59
+ else if (line.includes("WORK")) phoneType = "work";
60
+ else if (line.includes("VOICE")) phoneType = "voice";
61
+ else if (line.includes("PREF")) phoneType = "primary";
62
+
63
+ contact.phones.push({
64
+ value: phoneMatch[1].trim(),
65
+ type: phoneType,
66
+ });
67
+ }
68
+ }
69
+
70
+ // Parse EMAIL
71
+ if (line.startsWith("EMAIL")) {
72
+ const emailMatch = line.match(/:(.+)/);
73
+ if (emailMatch) {
74
+ // Extract email type from the EMAIL line
75
+ let emailType = "unknown";
76
+ if (line.includes("HOME")) emailType = "home";
77
+ else if (line.includes("WORK")) emailType = "work";
78
+ else if (line.includes("PREF")) emailType = "primary";
79
+
80
+ contact.emails.push({
81
+ value: emailMatch[1].trim(),
82
+ type: emailType,
83
+ });
84
+ }
85
+ }
86
+
87
+ // Parse ORG (Organization)
88
+ if (line.startsWith("ORG:")) {
89
+ contact.organization = line.substring(4).trim();
90
+ }
91
+
92
+ // Parse TITLE
93
+ if (line.startsWith("TITLE:")) {
94
+ contact.title = line.substring(6).trim();
95
+ }
96
+
97
+ // Parse NOTE
98
+ if (line.startsWith("NOTE:")) {
99
+ contact.note = line.substring(5).trim();
100
+ }
101
+
102
+ // Parse URL
103
+ if (line.startsWith("URL:")) {
104
+ contact.url = line.substring(4).trim();
105
+ }
106
+
107
+ // Parse PHOTO (basic support)
108
+ if (line.startsWith("PHOTO:")) {
109
+ contact.photo = line.substring(6).trim();
110
+ }
111
+ }
112
+
113
+ // Only add contact if it has meaningful data
114
+ if (
115
+ contact.fullName ||
116
+ contact.firstName ||
117
+ contact.lastName ||
118
+ contact.phones.length > 0
119
+ ) {
120
+ contacts.push(contact);
121
+ }
122
+ }
123
+
124
+ return contacts;
125
+ }
126
+
127
+ /**
128
+ * Convert VCF text content to JSON
129
+ * @param {string} vcfText - The VCF content as string
130
+ * @returns {Array} Array of contact objects
131
+ */
132
+ function vcfToJson(vcfText) {
133
+ if (!vcfText || typeof vcfText !== "string") {
134
+ throw new Error("Invalid VCF content. Expected non-empty string.");
135
+ }
136
+
137
+ try {
138
+ return parseVCF(vcfText);
139
+ } catch (error) {
140
+ throw new Error(`Failed to parse VCF content: ${error.message}`);
141
+ }
142
+ }
143
+
144
+ /**
145
+ * Convert VCF file to JSON
146
+ * @param {string} filePath - Path to the VCF file
147
+ * @returns {Array} Array of contact objects
148
+ */
149
+ function vcfToJsonFromFile(filePath) {
150
+ if (!filePath || typeof filePath !== "string") {
151
+ throw new Error("File path is required and must be a string.");
152
+ }
153
+
154
+ try {
155
+ if (!fs.existsSync(filePath)) {
156
+ throw new Error(`File not found: ${filePath}`);
157
+ }
158
+
159
+ const vcfText = fs.readFileSync(filePath, "utf8");
160
+ return vcfToJson(vcfText);
161
+ } catch (error) {
162
+ if (error.code === "ENOENT") {
163
+ throw new Error(`File not found: ${filePath}`);
164
+ }
165
+ if (error.code === "EACCES") {
166
+ throw new Error(`Permission denied: ${filePath}`);
167
+ }
168
+ throw error;
169
+ }
170
+ }
171
+
172
+ /**
173
+ * Save JSON data to file
174
+ * @param {Array} jsonData - The JSON data to save
175
+ * @param {string} outputPath - Path to save the JSON file
176
+ * @param {boolean} prettyPrint - Whether to format JSON with indentation
177
+ */
178
+ function saveJsonToFile(jsonData, outputPath, prettyPrint = true) {
179
+ if (!outputPath || typeof outputPath !== "string") {
180
+ throw new Error("Output path is required and must be a string.");
181
+ }
182
+
183
+ try {
184
+ const jsonString = prettyPrint
185
+ ? JSON.stringify(jsonData, null, 2)
186
+ : JSON.stringify(jsonData);
187
+
188
+ fs.writeFileSync(outputPath, jsonString, "utf8");
189
+ } catch (error) {
190
+ throw new Error(`Failed to save JSON file: ${error.message}`);
191
+ }
192
+ }
193
+
194
+ /**
195
+ * CLI function to convert VCF to JSON
196
+ */
197
+ function cli() {
198
+ const args = process.argv.slice(2);
199
+
200
+ if (args.length === 0 || args.includes("--help") || args.includes("-h")) {
201
+ console.log(`
202
+ VCF to JSON Converter
203
+
204
+ Usage:
205
+ vcf-to-json <input.vcf> [output.json] [options]
206
+
207
+ Options:
208
+ --compact, -c Output compact JSON (no formatting)
209
+ --help, -h Show this help message
210
+
211
+ Examples:
212
+ vcf-to-json contacts.vcf
213
+ vcf-to-json contacts.vcf output.json
214
+ vcf-to-json contacts.vcf output.json --compact
215
+ `);
216
+ return;
217
+ }
218
+
219
+ const inputFile = args[0];
220
+ const outputFile = args[1] || inputFile.replace(/\.vcf$/i, ".json");
221
+ const compact = args.includes("--compact") || args.includes("-c");
222
+
223
+ try {
224
+ console.log(`Converting ${inputFile} to JSON...`);
225
+ const jsonData = vcfToJsonFromFile(inputFile);
226
+
227
+ if (args[1]) {
228
+ saveJsonToFile(jsonData, outputFile, !compact);
229
+ console.log(
230
+ `✅ Converted ${jsonData.length} contacts and saved to ${outputFile}`
231
+ );
232
+ } else {
233
+ console.log(JSON.stringify(jsonData, null, compact ? 0 : 2));
234
+ }
235
+ } catch (error) {
236
+ console.error(`❌ Error: ${error.message}`);
237
+ process.exit(1);
238
+ }
239
+ }
240
+
241
+ // Export functions
242
+ module.exports = {
243
+ vcfToJson,
244
+ vcfToJsonFromFile,
245
+ saveJsonToFile,
246
+ cli,
247
+ };
248
+
249
+ // If this file is run directly, execute CLI
250
+ if (require.main === module) {
251
+ cli();
252
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vcf-to-json-converter",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "description": "A lightweight Node.js library to convert VCF (vCard) files to JSON format with CLI support",
5
5
  "license": "MIT",
6
6
  "author": "Shubhanshu Rao",
@@ -8,12 +8,13 @@
8
8
  "main": "index.js",
9
9
  "types": "index.d.ts",
10
10
  "bin": {
11
- "vcf-to-json": "./index.js"
11
+ "vcf-to-json": "index.js"
12
12
  },
13
13
  "scripts": {
14
14
  "start": "node index.js",
15
15
  "test": "node test.js",
16
- "demo": "node index.js contacts.vcf"
16
+ "demo": "node index.js contacts.vcf",
17
+ "build": "node index.js"
17
18
  },
18
19
  "keywords": [
19
20
  "vcf",
@@ -26,7 +27,7 @@
26
27
  ],
27
28
  "repository": {
28
29
  "type": "git",
29
- "url": "https://github.com/shubhanshurav/vcf-to-json.git"
30
+ "url": "git+https://github.com/shubhanshurav/vcf-to-json.git"
30
31
  },
31
32
  "bugs": {
32
33
  "url": "https://github.com/shubhanshurav/vcf-to-json.git/issues"