carnet panel contact

This commit is contained in:
alma 2025-04-20 21:50:30 +02:00
parent 0d8a099aef
commit ef6f08b6bc
27 changed files with 2657 additions and 102 deletions

View File

@ -11,6 +11,7 @@ import { useMediaQuery } from "@/hooks/use-media-query";
import { ContactsView } from '@/components/carnet/contacts-view';
import { X, Menu } from "lucide-react";
import { ContactDetails } from '@/components/carnet/contact-details';
import { VCard } from 'vcard-js';
// Layout modes
export enum PaneLayout {
@ -163,93 +164,21 @@ export default function CarnetPage() {
const parseVCard = (content: string): Contact[] => {
try {
console.log('Raw VCF content:', content);
const vcards = content.split('BEGIN:VCARD').filter(section => section.trim());
return vcards.map(section => {
const vcard = new VCard();
vcard.parse('BEGIN:VCARD' + section);
// Split the content into individual vCards
const vcardSections = content.split('BEGIN:VCARD').filter(section => section.trim());
console.log('Found vCard sections:', vcardSections.length);
return vcardSections.map(section => {
const lines = section.split('\n').filter(line => line.trim());
console.log('Processing vCard section with lines:', lines.length);
const contact: Partial<Contact> = {
id: Math.random().toString(36).substr(2, 9),
fullName: '',
email: '',
phone: '',
organization: '',
address: '',
notes: ''
return {
id: vcard.getProperty('UID')?.value || Math.random().toString(36).substr(2, 9),
fullName: vcard.getProperty('FN')?.value || '',
email: vcard.getProperty('EMAIL')?.value || '',
phone: vcard.getProperty('TEL')?.value || '',
organization: vcard.getProperty('ORG')?.value || '',
address: vcard.getProperty('ADR')?.value || '',
notes: vcard.getProperty('NOTE')?.value || '',
group: vcard.getProperty('CATEGORIES')?.value || ''
};
lines.forEach(line => {
console.log('Processing line:', line);
// Handle FN (Formatted Name)
if (line.startsWith('FN:')) {
contact.fullName = line.substring(3).trim();
console.log('Found full name:', contact.fullName);
}
// Handle N (Name components)
else if (line.startsWith('N:')) {
const nameParts = line.substring(2).split(';');
if (nameParts.length >= 2) {
const lastName = nameParts[0]?.trim();
const firstName = nameParts[1]?.trim();
if (!contact.fullName) {
contact.fullName = `${firstName} ${lastName}`.trim();
console.log('Constructed full name from N field:', contact.fullName);
}
}
}
// Handle EMAIL
else if (line.startsWith('EMAIL;')) {
const email = line.split(':')[1];
if (email) {
contact.email = email.trim();
console.log('Found email:', contact.email);
}
}
// Handle TEL
else if (line.startsWith('TEL;')) {
const phone = line.split(':')[1];
if (phone) {
contact.phone = phone.trim();
console.log('Found phone:', contact.phone);
}
}
// Handle ORG
else if (line.startsWith('ORG:')) {
contact.organization = line.substring(4).trim();
console.log('Found organization:', contact.organization);
}
// Handle ADR
else if (line.startsWith('ADR;')) {
const addressParts = line.split(':')[1].split(';');
if (addressParts.length >= 7) {
const street = addressParts[2]?.trim();
const city = addressParts[3]?.trim();
const state = addressParts[4]?.trim();
const zip = addressParts[5]?.trim();
const country = addressParts[6]?.trim();
contact.address = [street, city, state, zip, country].filter(Boolean).join(', ');
console.log('Found address:', contact.address);
}
}
// Handle NOTE
else if (line.startsWith('NOTE:')) {
contact.notes = line.substring(5).trim();
console.log('Found notes:', contact.notes);
}
});
if (!contact.fullName) {
contact.fullName = 'Unknown Contact';
console.log('No name found, using default');
}
console.log('Final contact object:', contact);
return contact as Contact;
});
} catch (error) {
console.error('Error parsing VCF content:', error);
@ -548,21 +477,18 @@ export default function CarnetPage() {
};
const generateVCard = (contact: Contact): string => {
const vcard = [
'BEGIN:VCARD',
'VERSION:3.0',
`UID:${contact.id}`,
`FN:${contact.fullName}`,
contact.email ? `EMAIL;TYPE=INTERNET:${contact.email}` : '',
contact.phone ? `TEL;TYPE=CELL:${contact.phone}` : '',
contact.organization ? `ORG:${contact.organization}` : '',
contact.address ? `ADR;TYPE=HOME:;;${contact.address}` : '',
contact.notes ? `NOTE:${contact.notes}` : '',
contact.group ? `CATEGORIES:${contact.group}` : '',
'END:VCARD'
].filter(line => line !== '').join('\r\n');
const vcard = new VCard();
return vcard;
vcard.setProperty('UID', contact.id);
vcard.setProperty('FN', contact.fullName);
if (contact.email) vcard.setProperty('EMAIL', contact.email);
if (contact.phone) vcard.setProperty('TEL', contact.phone);
if (contact.organization) vcard.setProperty('ORG', contact.organization);
if (contact.address) vcard.setProperty('ADR', contact.address);
if (contact.notes) vcard.setProperty('NOTE', contact.notes);
if (contact.group) vcard.setProperty('CATEGORIES', contact.group);
return vcard.toString();
};
if (isLoading) {

1
node_modules/.bin/quoted-printable generated vendored Symbolic link
View File

@ -0,0 +1 @@
../quoted-printable/bin/quoted-printable

28
node_modules/.package-lock.json generated vendored
View File

@ -4603,6 +4603,18 @@
"integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==",
"license": "MIT"
},
"node_modules/quoted-printable": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/quoted-printable/-/quoted-printable-1.0.1.tgz",
"integrity": "sha512-cihC68OcGiQOjGiXuo5Jk6XHANTHl1K4JLk/xlEJRTIXfy19Sg6XzB95XonYgr+1rB88bCpr7WZE7D7AlZow4g==",
"license": "MIT",
"dependencies": {
"utf8": "^2.1.0"
},
"bin": {
"quoted-printable": "bin/quoted-printable"
}
},
"node_modules/react": {
"version": "18.3.1",
"resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
@ -5487,6 +5499,12 @@
"semver": "~5.3.0"
}
},
"node_modules/utf8": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/utf8/-/utf8-2.1.2.tgz",
"integrity": "sha512-QXo+O/QkLP/x1nyi54uQiG0XrODxdysuQvE5dtVqv7F5K2Qb6FsN+qbr6KhF5wQ20tfcV3VQp0/2x1e1MRSPWg==",
"license": "MIT"
},
"node_modules/util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
@ -5514,6 +5532,16 @@
"react-dom": "^16.8 || ^17.0 || ^18.0"
}
},
"node_modules/vcard-js": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/vcard-js/-/vcard-js-1.2.2.tgz",
"integrity": "sha512-YShz0/tIXJ3gOg2o/OCNzuPCb7KTnhjn81cUaTZg5+elb99yVr+MRMkbD+vljTny6YuocPI0Dtb1ttG2Yf8oMg==",
"license": "ISC",
"dependencies": {
"quoted-printable": "^1.0.0",
"utf8": "^2.1.1"
}
},
"node_modules/victory-vendor": {
"version": "36.9.2",
"resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-36.9.2.tgz",

20
node_modules/quoted-printable/LICENSE-MIT.txt generated vendored Normal file
View File

@ -0,0 +1,20 @@
Copyright Mathias Bynens <https://mathiasbynens.be/>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

151
node_modules/quoted-printable/README.md generated vendored Normal file
View File

@ -0,0 +1,151 @@
# quoted-printable [![Build status](https://travis-ci.org/mathiasbynens/quoted-printable.svg?branch=master)](https://travis-ci.org/mathiasbynens/quoted-printable) [![Code coverage status](https://coveralls.io/repos/mathiasbynens/quoted-printable/badge.svg)](https://coveralls.io/r/mathiasbynens/quoted-printable) [![Dependency status](https://gemnasium.com/mathiasbynens/quoted-printable.svg)](https://gemnasium.com/mathiasbynens/quoted-printable)
_quoted-printable_ is a character encodingagnostic JavaScript implementation of [the `Quoted-Printable` content transfer encoding as defined by RFC 2045](https://tools.ietf.org/html/rfc2045#section-6.7). It can be used to encode plaintext to its `Quoted-Printable` encoding, or the other way around (i.e. decoding). [Heres an online demo using the UTF-8 character encoding.](https://mothereff.in/quoted-printable)
## Installation
Via [npm](https://www.npmjs.com/):
```bash
npm install quoted-printable
```
Via [Bower](http://bower.io/):
```bash
bower install quoted-printable
```
Via [Component](https://github.com/component/component):
```bash
component install mathiasbynens/quoted-printable
```
In a browser:
```html
<script src="quoted-printable.js"></script>
```
In [Node.js](https://nodejs.org/), [io.js](https://iojs.org/), [Narwhal](http://narwhaljs.org/), and [RingoJS](http://ringojs.org/):
```js
var quotedPrintable = require('quoted-printable');
```
In [Rhino](http://www.mozilla.org/rhino/):
```js
load('quoted-printable.js');
```
Using an AMD loader like [RequireJS](http://requirejs.org/):
```js
require(
{
'paths': {
'quoted-printable': 'path/to/quoted-printable'
}
},
['quoted-printable'],
function(quotedPrintable) {
console.log(quotedPrintable);
}
);
```
## API
### `quotedPrintable.version`
A string representing the semantic version number.
### `quotedPrintable.encode(input)`
This function takes an encoded byte string (the `input` parameter) and `Quoted-Printable`-encodes it. Each item in the input string represents an octet as per the desired character encoding. Heres an example that uses UTF-8:
```js
var utf8 = require('utf8');
quotedPrintable.encode(utf8.encode('foo=bar'));
// → 'foo=3Dbar'
quotedPrintable.encode(utf8.encode('Iñtërnâtiônàlizætiøn☃💩'));
// → 'I=C3=B1t=C3=ABrn=C3=A2ti=C3=B4n=C3=A0liz=C3=A6ti=C3=B8n=E2=98=83=F0=9F=92=\r\n=A9'
```
### `quotedPrintable.decode(text)`
This function takes a string of text (the `text` parameter) and `Quoted-Printable`-decodes it. The return value is a byte string, i.e. a string of which each item represents an octet as per the character encoding thats being used. Heres an example that uses UTF-8:
```js
var utf8 = require('utf8');
utf8.decode(quotedPrintable.decode('foo=3Dbar'));
// → 'foo=bar'
utf8.decode(quotedPrintable.decode('I=C3=B1t=C3=ABrn=C3=A2ti=C3=B4n=C3=A0liz=C3=A6ti=C3=B8n=E2=98=83=F0=9F=92=\r\n=A9'));
// → 'Iñtërnâtiônàlizætiøn☃💩'
```
### Using the `quoted-printable` binary
To use the `quoted-printable` binary in your shell, simply install _quoted-printable_ globally using npm:
```bash
npm install -g quoted-printable
```
After that, youll be able to use `quoted-printable` on the command line. Note that while the _quoted-printable_ library itself is character encodingagnostic, the command-line tool applies the UTF-8 character encoding on all input.
```bash
$ quoted-printable --encode 'foo=bar'
foo=3Dbar
$ quoted-printable --decode 'foo=3Dbar'
foo=bar
```
Read a local text file, `Quoted-Printable`-encode it, and save the result to a new file:
```bash
$ quoted-printable --encode < foo.txt > foo-quoted-printable.txt
```
Or do the same with an online text file:
```bash
$ curl -sL 'https://mths.be/brh' | quoted-printable --encode > quoted-printable.txt
```
Or, the opposite — read a local file containing a `Quoted-Printable`-encoded message, decode it back to plain text, and save the result to a new file:
```bash
$ quoted-printable --decode < quoted-printable.txt > original.txt
```
See `quoted-printable --help` for the full list of options.
## Support
_quoted-printable_ is designed to work in at least Node.js v0.10.0, io.js v1.0.0, Narwhal 0.3.2, RingoJS 0.8-0.11, PhantomJS 1.9.0, Rhino 1.7RC4, as well as old and modern versions of Chrome, Firefox, Safari, Opera, and Internet Explorer.
## Unit tests & code coverage
After cloning this repository, run `npm install` to install the dependencies needed for development and testing. You may want to install Istanbul _globally_ using `npm install istanbul -g`.
Once thats done, you can run the unit tests in Node using `npm test` or `node tests/tests.js`. To run the tests in Rhino, Ringo, Narwhal, and web browsers as well, use `grunt test`.
To generate the code coverage report, use `grunt cover`.
## Author
| [![twitter/mathias](https://gravatar.com/avatar/24e08a9ea84deb17ae121074d0f17125?s=70)](https://twitter.com/mathias "Follow @mathias on Twitter") |
|---|
| [Mathias Bynens](https://mathiasbynens.be/) |
## License
_quoted-printable_ is available under the [MIT](https://mths.be/mit) license.

116
node_modules/quoted-printable/bin/quoted-printable generated vendored Executable file
View File

@ -0,0 +1,116 @@
#!/usr/bin/env node
(function() {
var fs = require('fs');
var utf8 = require('utf8');
var quotedPrintable = require('../quoted-printable.js');
var strings = process.argv.splice(2);
var stdin = process.stdin;
var data;
var timeout;
var action;
var options = {};
var log = console.log;
var main = function() {
var option = strings[0];
var count = 0;
if (/^(?:-h|--help|undefined)$/.test(option)) {
log(
'quoted-printable v%s - https://mths.be/quoted-printable',
quotedPrintable.version
);
log([
'\nEncode or decode messages using the `Quoted-Printable` encoding (and UTF-8).',
'\nUsage:\n',
'\tquoted-printable [-e | --encode] string',
'\tquoted-printable [-d | --decode] string',
'\tquoted-printable [-v | --version]',
'\tquoted-printable [-h | --help]',
'\nExamples:\n',
'\tquoted-printable --encode \'foo = bar ©\'',
'\techo \'foo =3D bar =C2=A9\' | quoted-printable --decode',
].join('\n'));
return process.exit(1);
}
if (/^(?:-v|--version)$/.test(option)) {
log('v%s', quotedPrintable.version);
return process.exit(1);
}
strings.forEach(function(string) {
// Process options
if (string == '-e' || string == '--encode') {
action = 'encode';
return;
}
if (string == '-d' || string == '--decode') {
action = 'decode';
return;
}
// Process string(s)
var result;
if (!action) {
log('Error: quoted-printable requires at least one option and a string argument.');
log('Try `quoted-printable --help` for more information.');
return process.exit(1);
}
try {
if (action == 'encode') {
result = quotedPrintable.encode(utf8.encode(string, options));
} else if (action == 'decode') {
result = utf8.decode(quotedPrintable.decode(string, options));
}
log(result);
count++;
} catch (exception) {
log(exception.message + '\n');
log('Error: failed to %s.', action);
log('If you think this is a bug in quoted-printable, please report it:');
log('https://github.com/mathiasbynens/quoted-printable/issues/new');
log('\nStack trace using quoted-printable@%s:\n', quotedPrintable.version);
log(exception.stack);
return process.exit(1);
}
});
if (!count) {
log('Error: quoted-printable requires a string argument.');
log('Try `quoted-printable --help` for more information.');
return process.exit(1);
}
// Return with exit status 0 outside of the `forEach` loop, in case
// multiple strings were passed in.
return process.exit(0);
};
if (stdin.isTTY) {
// handle shell arguments
main();
} else {
// Either the script is called from within a non-TTY context, or `stdin`
// content is being piped in.
if (!process.stdout.isTTY) {
// The script was called from a non-TTY context. This is a rather uncommon
// use case we dont actively support. However, we dont want the script
// to wait forever in such cases, so…
timeout = setTimeout(function() {
// …if no piped data arrived after a whole minute, handle shell
// arguments instead.
main();
}, 60000);
}
data = '';
stdin.on('data', function(chunk) {
clearTimeout(timeout);
data += chunk;
});
stdin.on('end', function() {
strings.push(data.trim());
main();
});
stdin.resume();
}
}());

58
node_modules/quoted-printable/man/quoted-printable.1 generated vendored Normal file
View File

@ -0,0 +1,58 @@
.Dd May 4, 2014
.Dt quoted-printable 1
.Sh NAME
.Nm quoted-printable
.Nd encode or decode messages using the `Quoted-Printable` content transfer encoding
.Sh SYNOPSIS
.Nm
.Op Fl e | -encode Ar string
.br
.Op Fl d | -decode Ar string
.br
.Op Fl v | -version
.br
.Op Fl h | -help
.Sh DESCRIPTION
.Nm
encode or decode messages using the `Quoted-Printable` content transfer encoding.
.Sh OPTIONS
.Bl -ohang -offset
.It Sy "--encode"
Encode a string of text using the `Quoted-Printable` content transfer encoding.
.It Sy "--decode"
Decode a string of text using the `Quoted-Printable` content transfer encoding.
.It Sy "-v, --version"
Print quoted-printable's version.
.It Sy "-h, --help"
Show the help screen.
.El
.Sh EXIT STATUS
The
.Nm quoted-printable
utility exits with one of the following values:
.Pp
.Bl -tag -width flag -compact
.It Li 0
.Nm
successfully encoded/decoded the input and printed the result.
.It Li 1
.Nm
wasn't instructed to encode/decode anything (for example, the
.Ar --help
flag was set); or, an error occurred.
.El
.Sh EXAMPLES
.Bl -ohang -offset
.It Sy "quoted-printable --encode 'foo = bar'"
Print an encoded version of the given string.
.It Sy "quoted-printable --decode 'foo=3Dbar'"
Print the decoded version of the given `Quoted-Printable`-encoded message.
.It Sy "echo\ 'foo = bar'\ |\ quoted-printable --encode"
Print the encoded version of the string that gets piped in.
.El
.Sh BUGS
quoted-printable's bug tracker is located at <https://github.com/mathiasbynens/quoted-printable/issues>.
.Sh AUTHOR
Mathias Bynens <https://mathiasbynens.be/>
.Sh WWW
<https://mths.be/quoted-printable>

57
node_modules/quoted-printable/package.json generated vendored Normal file
View File

@ -0,0 +1,57 @@
{
"name": "quoted-printable",
"version": "1.0.1",
"description": "A robust & character encodingagnostic JavaScript implementation of the `Quoted-Printable` content transfer encoding as defined by RFC 2045.",
"homepage": "https://mths.be/quoted-printable",
"main": "quoted-printable.js",
"bin": "bin/quoted-printable",
"man": "man/quoted-printable.1",
"keywords": [
"decode",
"decoding",
"encode",
"encoding",
"quoted-printable",
"string"
],
"license": "MIT",
"author": {
"name": "Mathias Bynens",
"url": "https://mathiasbynens.be/"
},
"repository": {
"type": "git",
"url": "https://github.com/mathiasbynens/quoted-printable.git"
},
"bugs": "https://github.com/mathiasbynens/quoted-printable/issues",
"files": [
"LICENSE-MIT.txt",
"quoted-printable.js",
"bin/",
"man/"
],
"directories": {
"bin": "bin",
"man": "man",
"test": "tests"
},
"scripts": {
"test": "node tests/tests.js"
},
"dependencies": {
"utf8": "^2.1.0"
},
"devDependencies": {
"coveralls": "^2.11.1",
"grunt": "^0.4.5",
"grunt-shell": "^1.1.1",
"grunt-template": "^0.2.3",
"istanbul": "^0.3.5",
"jsesc": "^0.5.0",
"qunit-extras": "^1.4.0",
"qunitjs": "~1.11.0",
"regenerate": "^1.2.1",
"requirejs": "^2.1.15",
"string.fromcodepoint": "^0.2.1"
}
}

153
node_modules/quoted-printable/quoted-printable.js generated vendored Normal file
View File

@ -0,0 +1,153 @@
/*! https://mths.be/quoted-printable v1.0.1 by @mathias | MIT license */
;(function(root) {
// Detect free variables `exports`.
var freeExports = typeof exports == 'object' && exports;
// Detect free variable `module`.
var freeModule = typeof module == 'object' && module &&
module.exports == freeExports && module;
// Detect free variable `global`, from Node.js or Browserified code, and use
// it as `root`.
var freeGlobal = typeof global == 'object' && global;
if (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal) {
root = freeGlobal;
}
/*--------------------------------------------------------------------------*/
var stringFromCharCode = String.fromCharCode;
var decode = function(input) {
return input
// https://tools.ietf.org/html/rfc2045#section-6.7, rule 3:
// “Therefore, when decoding a `Quoted-Printable` body, any trailing white
// space on a line must be deleted, as it will necessarily have been added
// by intermediate transport agents.”
.replace(/[\t\x20]$/gm, '')
// Remove hard line breaks preceded by `=`. Proper `Quoted-Printable`-
// encoded data only contains CRLF line endings, but for compatibility
// reasons we support separate CR and LF too.
.replace(/=(?:\r\n?|\n|$)/g, '')
// Decode escape sequences of the form `=XX` where `XX` is any
// combination of two hexidecimal digits. For optimal compatibility,
// lowercase hexadecimal digits are supported as well. See
// https://tools.ietf.org/html/rfc2045#section-6.7, note 1.
.replace(/=([a-fA-F0-9]{2})/g, function($0, $1) {
var codePoint = parseInt($1, 16);
return stringFromCharCode(codePoint);
});
};
var handleTrailingCharacters = function(string) {
return string
.replace(/\x20$/, '=20') // Handle trailing space.
.replace(/\t$/, '=09') // Handle trailing tab.
};
var regexUnsafeSymbols = /[\0-\x08\n-\x1F=\x7F-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]/g;
var encode = function(string) {
// Encode symbols that are definitely unsafe (i.e. unsafe in any context).
var encoded = string.replace(regexUnsafeSymbols, function(symbol) {
if (symbol > '\xFF') {
throw RangeError(
'`quotedPrintable.encode()` expects extended ASCII input only. ' +
'Don\u2019t forget to encode the input first using a character ' +
'encoding like UTF-8.'
);
}
var codePoint = symbol.charCodeAt(0);
var hexadecimal = codePoint.toString(16).toUpperCase();
return '=' + ('0' + hexadecimal).slice(-2);
});
// Limit lines to 76 characters (not counting the CRLF line endings).
var lines = encoded.split(/\r\n?|\n/g);
var lineIndex = -1;
var lineCount = lines.length;
var result = [];
while (++lineIndex < lineCount) {
var line = lines[lineIndex];
// Leave room for the trailing `=` for soft line breaks.
var LINE_LENGTH = 75;
var index = 0;
var length = line.length;
while (index < length) {
var buffer = encoded.slice(index, index + LINE_LENGTH);
// If this line ends with `=`, optionally followed by a single uppercase
// hexadecimal digit, we broke an escape sequence in half. Fix it by
// moving these characters to the next line.
if (/=$/.test(buffer)) {
buffer = buffer.slice(0, LINE_LENGTH - 1);
index += LINE_LENGTH - 1;
} else if (/=[A-F0-9]$/.test(buffer)) {
buffer = buffer.slice(0, LINE_LENGTH - 2);
index += LINE_LENGTH - 2;
} else {
index += LINE_LENGTH;
}
result.push(buffer);
}
}
// Encode space and tab characters at the end of encoded lines. Note that
// with the current implementation, this can only occur at the very end of
// the encoded string — every other line ends with `=` anyway.
var lastLineLength = buffer.length;
if (/[\t\x20]$/.test(buffer)) {
// Theres a space or a tab at the end of the last encoded line. Remove
// this line from the `result` array, as it needs to change.
result.pop();
if (lastLineLength + 2 <= LINE_LENGTH + 1) {
// Its possible to encode the character without exceeding the line
// length limit.
result.push(
handleTrailingCharacters(buffer)
);
} else {
// Its not possible to encode the character without exceeding the line
// length limit. Remvoe the character from the line, and insert a new
// line that contains only the encoded character.
result.push(
buffer.slice(0, lastLineLength - 1),
handleTrailingCharacters(
buffer.slice(lastLineLength - 1, lastLineLength)
)
);
}
}
// `Quoted-Printable` uses CRLF.
return result.join('=\r\n');
};
var quotedPrintable = {
'encode': encode,
'decode': decode,
'version': '1.0.1'
};
// Some AMD build optimizers, like r.js, check for specific condition patterns
// like the following:
if (
typeof define == 'function' &&
typeof define.amd == 'object' &&
define.amd
) {
define(function() {
return quotedPrintable;
});
} else if (freeExports && !freeExports.nodeType) {
if (freeModule) { // in Node.js, io.js, or RingoJS v0.8.0+
freeModule.exports = quotedPrintable;
} else { // in Narwhal or RingoJS v0.7.0-
for (var key in quotedPrintable) {
quotedPrintable.hasOwnProperty(key) && (freeExports[key] = quotedPrintable[key]);
}
}
} else { // in Rhino or a web browser
root.quotedPrintable = quotedPrintable;
}
}(this));

20
node_modules/utf8/LICENSE-MIT.txt generated vendored Normal file
View File

@ -0,0 +1,20 @@
Copyright Mathias Bynens <https://mathiasbynens.be/>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

119
node_modules/utf8/README.md generated vendored Normal file
View File

@ -0,0 +1,119 @@
# utf8.js [![Build status](https://travis-ci.org/mathiasbynens/utf8.js.svg?branch=master)](https://travis-ci.org/mathiasbynens/utf8.js) [![Code coverage status](http://img.shields.io/coveralls/mathiasbynens/utf8.js/master.svg)](https://coveralls.io/r/mathiasbynens/utf8.js) [![Dependency status](https://gemnasium.com/mathiasbynens/utf8.js.svg)](https://gemnasium.com/mathiasbynens/utf8.js)
_utf8.js_ is a well-tested UTF-8 encoder/decoder written in JavaScript. Unlike many other JavaScript solutions, it is designed to be a _proper_ UTF-8 encoder/decoder: it can encode/decode any scalar Unicode code point values, as per [the Encoding Standard](https://encoding.spec.whatwg.org/#utf-8). [Heres an online demo.](https://mothereff.in/utf-8)
Feel free to fork if you see possible improvements!
## Installation
Via [npm](https://www.npmjs.com/):
```bash
npm install utf8
```
Via [Bower](http://bower.io/):
```bash
bower install utf8
```
Via [Component](https://github.com/component/component):
```bash
component install mathiasbynens/utf8.js
```
In a browser:
```html
<script src="utf8.js"></script>
```
In [Narwhal](http://narwhaljs.org/), [Node.js](https://nodejs.org/), and [RingoJS ≥ v0.8.0](http://ringojs.org/):
```js
var utf8 = require('utf8');
```
In [Rhino](http://www.mozilla.org/rhino/):
```js
load('utf8.js');
```
Using an AMD loader like [RequireJS](http://requirejs.org/):
```js
require(
{
'paths': {
'utf8': 'path/to/utf8'
}
},
['utf8'],
function(utf8) {
console.log(utf8);
}
);
```
## API
### `utf8.encode(string)`
Encodes any given JavaScript string (`string`) as UTF-8, and returns the UTF-8-encoded version of the string. It throws an error if the input string contains a non-scalar value, i.e. a lone surrogate. (If you need to be able to encode non-scalar values as well, use [WTF-8](https://mths.be/wtf8) instead.)
```js
// U+00A9 COPYRIGHT SIGN; see http://codepoints.net/U+00A9
utf8.encode('\xA9');
// → '\xC2\xA9'
// U+10001 LINEAR B SYLLABLE B038 E; see http://codepoints.net/U+10001
utf8.encode('\uD800\uDC01');
// → '\xF0\x90\x80\x81'
```
### `utf8.decode(byteString)`
Decodes any given UTF-8-encoded string (`byteString`) as UTF-8, and returns the UTF-8-decoded version of the string. It throws an error when malformed UTF-8 is detected. (If you need to be able to decode encoded non-scalar values as well, use [WTF-8](https://mths.be/wtf8) instead.)
```js
utf8.decode('\xC2\xA9');
// → '\xA9'
utf8.decode('\xF0\x90\x80\x81');
// → '\uD800\uDC01'
// → U+10001 LINEAR B SYLLABLE B038 E
```
### `utf8.version`
A string representing the semantic version number.
## Support
utf8.js has been tested in at least Chrome 27-39, Firefox 3-34, Safari 4-8, Opera 10-28, IE 6-11, Node.js v0.10.0, Narwhal 0.3.2, RingoJS 0.8-0.11, PhantomJS 1.9.0, and Rhino 1.7RC4.
## Unit tests & code coverage
After cloning this repository, run `npm install` to install the dependencies needed for development and testing. You may want to install Istanbul _globally_ using `npm install istanbul -g`.
Once thats done, you can run the unit tests in Node using `npm test` or `node tests/tests.js`. To run the tests in Rhino, Ringo, Narwhal, PhantomJS, and web browsers as well, use `grunt test`.
To generate the code coverage report, use `grunt cover`.
## FAQ
### Why is the first release named v2.0.0? Havent you heard of [semantic versioning](http://semver.org/)?
Long before utf8.js was created, the `utf8` module on npm was registered and used by another (slightly buggy) library. @ryanmcgrath was kind enough to give me access to the `utf8` package on npm when I told him about utf8.js. Since there has already been a v1.0.0 release of the old library, and to avoid breaking backwards compatibility with projects that rely on the `utf8` npm package, I decided the tag the first release of utf8.js as v2.0.0 and take it from there.
## Author
| [![twitter/mathias](https://gravatar.com/avatar/24e08a9ea84deb17ae121074d0f17125?s=70)](https://twitter.com/mathias "Follow @mathias on Twitter") |
|---|
| [Mathias Bynens](https://mathiasbynens.be/) |
## License
utf8.js is available under the [MIT](https://mths.be/mit) license.

39
node_modules/utf8/package.json generated vendored Normal file
View File

@ -0,0 +1,39 @@
{
"name": "utf8",
"version": "2.1.2",
"description": "A well-tested UTF-8 encoder/decoder written in JavaScript.",
"homepage": "https://mths.be/utf8js",
"main": "utf8.js",
"keywords": [
"charset",
"encoding",
"unicode",
"utf8"
],
"license": "MIT",
"author": {
"name": "Mathias Bynens",
"url": "https://mathiasbynens.be/"
},
"repository": {
"type": "git",
"url": "https://github.com/mathiasbynens/utf8.js.git"
},
"bugs": "https://github.com/mathiasbynens/utf8.js/issues",
"files": [
"LICENSE-MIT.txt",
"utf8.js"
],
"scripts": {
"test": "node tests/tests.js"
},
"devDependencies": {
"coveralls": "^2.11.14",
"grunt": "^1.0.1",
"grunt-shell": "^1.1.2",
"istanbul": "^0.4.5",
"qunit-extras": "^1.4.2",
"qunitjs": "~1.11.0",
"requirejs": "^2.3.2"
}
}

244
node_modules/utf8/utf8.js generated vendored Normal file
View File

@ -0,0 +1,244 @@
/*! https://mths.be/utf8js v2.1.2 by @mathias */
;(function(root) {
// Detect free variables `exports`
var freeExports = typeof exports == 'object' && exports;
// Detect free variable `module`
var freeModule = typeof module == 'object' && module &&
module.exports == freeExports && module;
// Detect free variable `global`, from Node.js or Browserified code,
// and use it as `root`
var freeGlobal = typeof global == 'object' && global;
if (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal) {
root = freeGlobal;
}
/*--------------------------------------------------------------------------*/
var stringFromCharCode = String.fromCharCode;
// Taken from https://mths.be/punycode
function ucs2decode(string) {
var output = [];
var counter = 0;
var length = string.length;
var value;
var extra;
while (counter < length) {
value = string.charCodeAt(counter++);
if (value >= 0xD800 && value <= 0xDBFF && counter < length) {
// high surrogate, and there is a next character
extra = string.charCodeAt(counter++);
if ((extra & 0xFC00) == 0xDC00) { // low surrogate
output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000);
} else {
// unmatched surrogate; only append this code unit, in case the next
// code unit is the high surrogate of a surrogate pair
output.push(value);
counter--;
}
} else {
output.push(value);
}
}
return output;
}
// Taken from https://mths.be/punycode
function ucs2encode(array) {
var length = array.length;
var index = -1;
var value;
var output = '';
while (++index < length) {
value = array[index];
if (value > 0xFFFF) {
value -= 0x10000;
output += stringFromCharCode(value >>> 10 & 0x3FF | 0xD800);
value = 0xDC00 | value & 0x3FF;
}
output += stringFromCharCode(value);
}
return output;
}
function checkScalarValue(codePoint) {
if (codePoint >= 0xD800 && codePoint <= 0xDFFF) {
throw Error(
'Lone surrogate U+' + codePoint.toString(16).toUpperCase() +
' is not a scalar value'
);
}
}
/*--------------------------------------------------------------------------*/
function createByte(codePoint, shift) {
return stringFromCharCode(((codePoint >> shift) & 0x3F) | 0x80);
}
function encodeCodePoint(codePoint) {
if ((codePoint & 0xFFFFFF80) == 0) { // 1-byte sequence
return stringFromCharCode(codePoint);
}
var symbol = '';
if ((codePoint & 0xFFFFF800) == 0) { // 2-byte sequence
symbol = stringFromCharCode(((codePoint >> 6) & 0x1F) | 0xC0);
}
else if ((codePoint & 0xFFFF0000) == 0) { // 3-byte sequence
checkScalarValue(codePoint);
symbol = stringFromCharCode(((codePoint >> 12) & 0x0F) | 0xE0);
symbol += createByte(codePoint, 6);
}
else if ((codePoint & 0xFFE00000) == 0) { // 4-byte sequence
symbol = stringFromCharCode(((codePoint >> 18) & 0x07) | 0xF0);
symbol += createByte(codePoint, 12);
symbol += createByte(codePoint, 6);
}
symbol += stringFromCharCode((codePoint & 0x3F) | 0x80);
return symbol;
}
function utf8encode(string) {
var codePoints = ucs2decode(string);
var length = codePoints.length;
var index = -1;
var codePoint;
var byteString = '';
while (++index < length) {
codePoint = codePoints[index];
byteString += encodeCodePoint(codePoint);
}
return byteString;
}
/*--------------------------------------------------------------------------*/
function readContinuationByte() {
if (byteIndex >= byteCount) {
throw Error('Invalid byte index');
}
var continuationByte = byteArray[byteIndex] & 0xFF;
byteIndex++;
if ((continuationByte & 0xC0) == 0x80) {
return continuationByte & 0x3F;
}
// If we end up here, its not a continuation byte
throw Error('Invalid continuation byte');
}
function decodeSymbol() {
var byte1;
var byte2;
var byte3;
var byte4;
var codePoint;
if (byteIndex > byteCount) {
throw Error('Invalid byte index');
}
if (byteIndex == byteCount) {
return false;
}
// Read first byte
byte1 = byteArray[byteIndex] & 0xFF;
byteIndex++;
// 1-byte sequence (no continuation bytes)
if ((byte1 & 0x80) == 0) {
return byte1;
}
// 2-byte sequence
if ((byte1 & 0xE0) == 0xC0) {
byte2 = readContinuationByte();
codePoint = ((byte1 & 0x1F) << 6) | byte2;
if (codePoint >= 0x80) {
return codePoint;
} else {
throw Error('Invalid continuation byte');
}
}
// 3-byte sequence (may include unpaired surrogates)
if ((byte1 & 0xF0) == 0xE0) {
byte2 = readContinuationByte();
byte3 = readContinuationByte();
codePoint = ((byte1 & 0x0F) << 12) | (byte2 << 6) | byte3;
if (codePoint >= 0x0800) {
checkScalarValue(codePoint);
return codePoint;
} else {
throw Error('Invalid continuation byte');
}
}
// 4-byte sequence
if ((byte1 & 0xF8) == 0xF0) {
byte2 = readContinuationByte();
byte3 = readContinuationByte();
byte4 = readContinuationByte();
codePoint = ((byte1 & 0x07) << 0x12) | (byte2 << 0x0C) |
(byte3 << 0x06) | byte4;
if (codePoint >= 0x010000 && codePoint <= 0x10FFFF) {
return codePoint;
}
}
throw Error('Invalid UTF-8 detected');
}
var byteArray;
var byteCount;
var byteIndex;
function utf8decode(byteString) {
byteArray = ucs2decode(byteString);
byteCount = byteArray.length;
byteIndex = 0;
var codePoints = [];
var tmp;
while ((tmp = decodeSymbol()) !== false) {
codePoints.push(tmp);
}
return ucs2encode(codePoints);
}
/*--------------------------------------------------------------------------*/
var utf8 = {
'version': '2.1.2',
'encode': utf8encode,
'decode': utf8decode
};
// Some AMD build optimizers, like r.js, check for specific condition patterns
// like the following:
if (
typeof define == 'function' &&
typeof define.amd == 'object' &&
define.amd
) {
define(function() {
return utf8;
});
} else if (freeExports && !freeExports.nodeType) {
if (freeModule) { // in Node.js or RingoJS v0.8.0+
freeModule.exports = utf8;
} else { // in Narwhal or RingoJS v0.7.0-
var object = {};
var hasOwnProperty = object.hasOwnProperty;
for (var key in utf8) {
hasOwnProperty.call(utf8, key) && (freeExports[key] = utf8[key]);
}
}
} else { // in Rhino or a web browser
root.utf8 = utf8;
}
}(this));

6
node_modules/vcard-js/.npmignore generated vendored Normal file
View File

@ -0,0 +1,6 @@
/out
node_modules
npm-debug.log
.*.swp
.direcotry
*~

89
node_modules/vcard-js/README.md generated vendored Normal file
View File

@ -0,0 +1,89 @@
# vcard-js
## Description
`vcard-js` is a library to deal with the vCard format.
It can parse from vCard format to jCard format,
and transform current version to other version.
## Installation
```
npm install vcard-js
```
## Usage
```js
var VCard = require('vcard-js');
var str = [
'BEGIN:VCARD',
'VERSION:2.1',
'N:Einstein',
'FN:Albert Einstein',
'TEL:(111) 555-6666',
'END:VCARD'
].join(VCard.EOL);
var arr = VCard.parse(str);
console.log(VCard.serialize(arr));
console.log(VCard.serialize(arr, '3.0'));
arr.forEach(function(vCard){
console.log(vCard.toString('4.0'));
console.log(vCard.toJSON());
});
```
## API
### Classes
#### VCard
* `VCard.EOL`
* `VCard.MAX_WIDTH`
* `VCard.parse(data[,opt])`
* `VCard.serialize(vCards,version)`
* `VCard.serialize(vCards[,opt])`
* `VCard.readFile(filename[,opt],callback)`
* `VCard.identifyType(item)`
* `VCard#items`
* `VCard#toJSON()`
* `VCard#toString(version)`
* `VCard#toString([opt])`
* `VCard#find(name)`
* `VCard#find(filter)`
* `VCard#add(line)`
* `VCard#remove(name)`
#### VCard.Item
* `VCard.Item#name`
* `VCard.Item#params`
* `VCard.Item#dataType`
* `VCard.Item#value`
* `VCard.Item#encode(value)`
* `VCard.Item#decode()`
* `VCard.Item#quotedPrintable([value])`
* `VCard.Item#base64([value])`
* `VCard.Item#toJSON()`
* `VCard.Item#toString(version)`
* `VCard.Item#toString([opt])`
You can output the detail documentation by [jsdoc](https://github.com/jsdoc3/jsdoc) command.
```
jsdoc -R README.md lib/
```
## References
* [Wikipedia](https://en.wikipedia.org/wiki/VCard)
* [IANA](http://www.iana.org/assignments/vcard-elements/vcard-elements.xhtml)
## License
ISC

1
node_modules/vcard-js/index.js generated vendored Normal file
View File

@ -0,0 +1 @@
module.exports = require('./lib/VCard');

713
node_modules/vcard-js/lib/VCard.js generated vendored Normal file
View File

@ -0,0 +1,713 @@
var util = require('util');
var fs = require('fs');
var quoted_printable = require('quoted-printable');
var utf8 = require('utf8');
/**
*
* @class VCard
* @version 1.2.1
* @param {array} lines
* @param {object} [opt]
* @param {string} [opt.filename]
* @param {VCard~filterCb} [opt.filter]
* @param {VCard~debugCb} [opt.debug]
*
*/
function VCard(lines, opt){
opt = opt || {};
var self = opt.vCard = this;
/**
* @member {array} VCard#_origin
* @protected
*/
this._origin = lines;
/**
*
* @member {string} VCard#_filename
* @protected
*/
this._filename = opt.filename;
/**
* @member {string} VCard#version
*/
this.version = getVersion(lines);
/**
* @member {VCard.Item[]} VCard#items
*/
this.items = [];
lines.forEach(function(line){
var item = new VCard.Item(line, opt);
if(opt.filter){
if(!opt.filter(item))
return;
}
self.items.push(item);
});
(opt.debug || VCard.debug)(self);
function getVersion(lines){
var line = find(lines, function(line){
if(util.isArray(line))
return /^version$/i.test(line[0]);
else
return /^version:/i.test(line);
});
if(util.isString(line))
return line.substr(8);
else if(util.isArray(line))
return line[3];
else
return null;
};
}
/**
*
* @function VCard#toString
* @param {object} [opt]
* @param {string} [opt.version]
* @param {VCard~filterCb} [opt.filter]
* @returns {string}
*/
/**
* @function VCard#toString
* @param {string} version
* @returns {string}
*/
VCard.prototype.toString = function(opt){
opt = opt || {};
var self = this;
var list = [];
if(util.isString(opt)){
opt = {
version : opt
};
}
self.items.forEach(function(item){
if(/^(begin|end):/i.test(item.name))
return;
if(opt.filter){
if(!opt.filter(item))
return;
}
var line = item.toString(opt);
line && list.push(line);
});
if(list.length){
list.unshift('BEGIN:VCARD');
list.push('END:VCARD');
return list.join(VCard.EOL);
}
return '';
};
/**
* @function VCard#toJSON
* @returns {array}
*/
VCard.prototype.toJSON = function(){
var self = this;
var list = [];
self.items.forEach(function(item){
if(/^(begin|end):/i.test(item.name))
return;
list.push(item.toJSON());
});
return ['vcard', list];
};
/**
* @function VCard#find
* @param {string} name
* @since 1.2.0
* @returns {VCard.Item[]}
*/
/**
* @function VCard#find
* @param {VCard~filterCb} filter
* @since 1.2.0
* @returns {VCard.Item[]}
*/
VCard.prototype.find = function(filter){
var self = this;
if(!util.isFunction(filter)){
var name = filter.toLowerCase();
filter = function(item){
return item.name.toLowerCase() === name;
};
}
return self.items.filter(filter);
};
/**
* @function VCard#add
* @param {(string|array)} line
* @since 1.2.0
* @returns {VCard.Item}
*/
VCard.prototype.add = function(line){
var self = this;
var item = new VCard.Item(line, {
vCard : self
});
self.items.push(item);
return item;
};
/**
* @function VCard#remove
* @param {string} name
* @since 1.2.0
* @returns {number}
*/
VCard.prototype.remove = function(name){
var self = this;
var i = 0, j = 0, item;
name = name.toLowerCase();
while(i < self.items.length){
item = self.items[i];
if(item.name.toLowerCase() === name){
self.items.splice(i, 1);
j++;
}else{
i++;
}
}
return j;
};
VCard.VCard = VCard;
/**
* @constant {string} VCard.EOL
* @default \r\n
*/
VCard.EOL = '\r\n';
/**
* @constant {number} VCard.MAX_WIDTH
* @default 1024
*/
VCard.MAX_WIDTH = 1024;
/**
* @function VCard.identifyType
* @param {VCard.Item} item
* @since 1.2.0
*/
VCard.identifyType = function(item){
if(item.name === 'LANG'){
item.type = 'language-tag';
}else if(item.name === 'REV'){
item.type = 'timestamp';
}else if(/^(http|https)\:\/\//i.test(item.value)){
item.type = 'uri';
}
};
/**
* @function VCard.debug
* @param {*} any
* @abstract
*/
VCard.debug = function(any){
};
/**
* @class VCard.Item
* @param {(string|array)} line
* @param {object} [opt]
* @param {VCard} [opt.vCard]
* @param {VCard~debugCb} [opt.debug]
*/
VCard.Item = function(line, opt){
opt = opt || {};
var self = this;
/**
* @member {VCard} VCard.Item#_vCard
* @protected
*/
this._vCard = opt.vCard;
/**
* @member {(string|array)} VCard.Item#_origin
* @protected
*/
this._origin = line;
/**
* @member {string} VCard.Item#name
*/
this.name = '';
/**
* @member {string} VCard.Item#value
*/
this.value = '';
/**
* @member {object} VCard.Item#params
*/
this.params = {};
/**
* @member {string} VCard.Item#type
* @default text
* @since 1.2.0
*/
this.type = 'text';
if(!line)
return;
else if(util.isString(line))
parse();
else if(util.isArray(line))
init();
(opt.debug || VCard.debug)(self);
function parse(){
var frag = line, results, k, v, i;
while(frag){
if(!self.name){
results = frag.match(/^([\w\-]+)(?=:|;|\r\n|\r|\n)/g);
if(results){
self.name = v = results[0];
frag = frag.substr(v.length);
continue;
}
}
if(frag.indexOf(':') !== 0){
frag = frag.replace(/^;/, '');
results = frag.match(/^([\w\-]+)="/);
if(results){
k = results[1];
frag = frag.substr(k.length + 2);
i = frag.search(/[^\\]"/);
if(i !== -1)
v = frag.substr(0, i + 1);
else
v = frag;
setParams(k, v);
frag = frag.substr(v.length + 1);
continue;
}
results = frag.match(/^([\w\-]+)=/)
if(results){
k = results[1];
frag = frag.substr(k.length + 1);
i = frag.search(/[^\\](;|:)/);
if(i !== -1)
v = frag.substr(0, i + 1);
else
v = frag;
setParams(k, v);
frag = frag.substr(v.length);
continue;
}
i = frag.search(/[^\\](;|:)/);
if(i !== -1){
v = frag.substr(0, i + 1);
setParams('type', v);
frag = frag.substr(v.length);
continue;
}
}
self.value = frag.replace(/^:/, '');
frag = null;
}
VCard.identifyType(self);
}
function init(){
self.name = line[0];
self.type = line[2];
self.value = line[3];
var k, o = line[1];
for(k in o){
self.params[k] = o[k];
}
self.encode(self.value);
}
function setParams(k, v){
var obj = self.params;
k = k.toUpperCase();
if(/^(type)$/i.test(k))
v = v.split(/\s*,\s*/);
if(obj.hasOwnProperty(k)){
if(!util.isArray(obj[k]))
obj[k] = [obj[k]];
if(util.isArray(v))
obj[k] = obj[k].concat(v);
else
obj[k].push(v);
return;
}
obj[k] = v;
}
};
/**
* @function VCard.Item#toString
* @param {object} [opt]
* @param {string} [opt.version]
* @param {VCard~replaceCb} [opt.replace]
* @returns {string}
*/
/**
* @function VCard.Item#toString
* @param {string} version
* @returns {string}
*/
VCard.Item.prototype.toString = function(opt){
opt = opt || {};
var self = this;
var line = self.name.toUpperCase(), k, v;
var value = self.value.toString();
if(util.isString(opt)){
opt = {
version : opt
};
}
var version = opt.version;
if(!version){
version = self._vCard ? self._vCard.version : '4.0';
}
for(k in self.params){
v = self.params[k];
k = k.toUpperCase();
if(version === '2.1' && /^(type)$/i.test(k)){
line += ';';
if(/^(photo)$/i.test(self.name))
line += k + '=';
if(util.isArray(v))
line += v.join(';');
else
line += v;
continue;
}
if(/^(impp)$/i.test(self.name)){
if(util.isArray(v)){
v.forEach(function(v){
line += ';' + k + '=' + v;
});
continue;
}
}
if(k === 'ENCODING'){
if(/^(BASE64|b)$/.test(v) || /^data\:.+\;base64\,/.test(value)){
if(version === '2.1')
v = 'BASE64';
else if(version === '3.0')
v = 'b';
else
v = '';
if(v)
value = value.replace(/^data\:.+\;base64\,/, '');
}
}
v = v.toString();
if(!v)
continue;
if(version >= 4 && /\s/.test(v)){
line += ';' + k + '="' + v + '"';
continue;
}
line += ';' + k + '=' + v;
}
if(version < 4)
value = value.replace(/^geo\:/i, '');
if(/^version$/i.test(self.name))
line += ':' + version;
else if(value)
line += ':' + value;
else
line = '';
if(line.length > VCard.MAX_WIDTH){
line = line.replace(/(^.{75})|(.{74})/g, function(v){
return v + VCard.EOL + ' ';
});
line = line.replace(/\s$/, '');
if(version === '2.1')
line += VCard.EOL;
}
if(opt.replace){
line = opt.replace(line, self);
}
return line;
};
/**
* @function VCard.Item#toJSON
* @returns {array}
*/
VCard.Item.prototype.toJSON = function(){
var self = this;
var name = self.name.toLowerCase();
var type = self.type;
var value = self.decode();
var params = {};
var k, v;
for(k in self.params){
v = self.params[k];
if(/^value$/i.test(k)){
type = v;
continue;
}else if(/^label$/i.test(k) && !value){
value = v;
}
params[k.toLowerCase()] = v;
}
switch(type){
case 'boolean':
value = value === 'TRUE';
break;
case 'integer':
value = parseInt(value);
break;
case 'float':
value = parseFloat(value);
break;
}
return [name, params, type, value];
};
/**
* @function VCard.Item#encode
* @param {string} value
* @since 1.1.0
*/
VCard.Item.prototype.encode = function(value){
switch(this.params.ENCODING){
case 'QUOTED-PRINTABLE':
this.quotedPrintable(value);
break;
case 'BASE64':
case 'b':
this.base64(value);
break;
}
};
/**
* @function VCard.Item#decode
* @returns {string}
* @since 1.1.0
*/
VCard.Item.prototype.decode = function(){
switch(this.params.ENCODING){
case 'QUOTED-PRINTABLE':
return this.quotedPrintable();
case 'BASE64':
case 'b':
return this.base64();
default:
return this.value;
}
};
/**
* @function VCard.Item#quotedPrintable
* @param {string} value
* @since 1.2.0
*/
/**
* @function VCard.Item#quotedPrintable
* @returns {string}
* @since 1.2.0
*/
VCard.Item.prototype.quotedPrintable = function(value){
if(value){
value = utf8.encode(value);
this.value = quoted_printable.encode(value);
this.params.CHARSET = 'UTF-8';
this.params.ENCODING = 'QUOTED-PRINTABLE';
}else{
value = quoted_printable.decode(this.value);
value = utf8.decode(value);
return value;
}
};
/**
* @function VCard.Item#base64
* @param {string} value
* @since 1.2.0
*/
/**
* @function VCard.Item#base64
* @returns {string}
* @since 1.2.0
*/
VCard.Item.prototype.base64 = function(value){
if(value){
this.value = value;
this.param.ENCODING = this.param.ENCODING || 'BASE64';
}else{
return this.value;
}
};
/**
* @function VCard.parse
* @param {(string|array)} data
* @param {object} [opt]
* @param {VCard~filterCb} [opt.filter]
* @returns {array}
*/
VCard.parse = function(data, opt){
opt = opt || {};
var vCards = [], lines, vCard;
if(util.isString(data)){
lines = [];
data = data.replace(/^=/mg, ' ');
data.split(/(\r\n|\r|\n)(?=\S)/).forEach(function(line){
line = line.replace(/^item\d+\.|\r\n\s*|\r\s*|\n\s*/g, '');
if(line){
switch(line){
case 'BEGIN:VCARD':
lines = [];
break;
case 'END:VCARD':
vCard = new VCard(lines, opt);
if(opt.filter){
if(!opt.filter(vCard))
break;
}
vCards.push(vCard);
break;
default:
lines.push(line);
}
}
});
}else if(util.isArray(data)){
data.forEach(function(arr){
vCards.push(new VCard(arr[1]));
});
}
return vCards;
};
/**
* @function VCard.serialize
* @param {(VCard[]|array)} vCards
* @param {string} version
* @returns {string}
*/
/**
* @function VCard.serialize
* @param {(VCard[]|array)} vCards
* @param {object} [opt]
* @param {VCard~filterCb} [opt.filter]
* @returns {string}
*/
VCard.serialize = function(vCards, opt){
opt = opt || {};
var list = [];
vCards.forEach(function(vCard){
if(util.isArray(vCard)){
vCard = new VCard(vCard[1]);
}
if(opt.filter){
if(!opt.filter(vCard))
return;
}
list.push(vCard.toString(opt));
});
return list.join(VCard.EOL);
};
/**
* @function VCard.readFile
* @param {string} filename
* @param {object} [opt]
* @param {string} [opt.encoding=utf8]
* @param {VCard~readFileCb} callback
*/
/**
*
* @callback VCard~readFileCb
* @param {?Error} err
* @param {array} vCards
* @param {string} data
*/
VCard.readFile = function (filename, opt, callback){
opt = opt || {};
if(util.isFunction(opt)){
callback = opt;
opt = {};
}
fs.readFile(opt.filename = filename, {
encoding : opt.encoding || 'utf8'
}, function(err, data){
var vCards = null;
if(!err)
try{
vCards = VCard.parse(data, opt);
}catch(e){
err = e;
}
callback(err, vCards, data);
});
};
function find(arr, predicate){
if(util.isArray(arr))
for(var i=0,len=arr.length,o; i<len; i++){
o = arr[i];
if(predicate(o))
return o;
}
return undefined;
}
module.exports = VCard;
/**
* @callback VCard~debugCb
* @param {*} any
*/
/**
* @callback VCard~filterCb
* @param {(VCard|VCard.Item)} any
* @returns {boolean}
*/
/**
* @callback VCard~replaceCb
* @param {string} line
* @param {VCard.Item} item
* @returns {string}
*/

31
node_modules/vcard-js/package.json generated vendored Normal file
View File

@ -0,0 +1,31 @@
{
"name": "vcard-js",
"version": "1.2.2",
"description": "Convert between vCard and jCard.",
"main": "index.js",
"directories": {
"test": "test"
},
"scripts": {
"test": "node test/test.js"
},
"repository": {
"type": "git",
"url": "git+https://github.com/zuojiang/vcard-js.git"
},
"keywords": [
"vCard",
"jCard",
"vcf"
],
"author": "zuojiang",
"license": "ISC",
"bugs": {
"url": "https://github.com/zuojiang/vcard-js/issues"
},
"homepage": "https://github.com/zuojiang/vcard-js#readme",
"dependencies": {
"quoted-printable": "^1.0.0",
"utf8": "^2.1.1"
}
}

21
node_modules/vcard-js/test/helloWorld.js generated vendored Normal file
View File

@ -0,0 +1,21 @@
//var VCard = require('vcard-js');
var VCard = require('../index');
var str = [
'BEGIN:VCARD',
'VERSION:2.1',
'N:Einstein',
'FN:Albert Einstein',
'TEL:(111) 555-6666',
'END:VCARD'
].join(VCard.EOL);
var arr = VCard.parse(str);
console.log(VCard.serialize(arr));
console.log(VCard.serialize(arr, '3.0'));
arr.forEach(function(vCard){
console.log(vCard.toString('4.0'));
console.log(vCard.toJSON());
});

73
node_modules/vcard-js/test/mix.vcf generated vendored Normal file
View File

@ -0,0 +1,73 @@
BEGIN:VCARD
VERSION:2.1
REV:20151216T141119Z
X-GENERATOR:IntSig
X-IS-ANGLE:90
N;CHARSET=utf-8:周;宪
X-IS-INFO:0,0,0,0,0,0,0,0;1,2,13
FN;CHARSET=utf-8:周宪
X-IS-INFO:540,484,583,484,583,615,540,615;0,9,10,13
TEL;CELL;VOICE:18573183138
X-IS-INFO:400,373,423,373,423,619,400,619;6,13
TEL;WORK;VOICE:073188033808
X-IS-INFO:369,338,392,338,392,619,369,619;3,4,5,6,13
EMAIL;PREF;INTERNET:66426222@qq.com
X-IS-INFO:336,296,362,296,362,619,336,619;7,14,13
URL;WORK;CHARSET=utf-8:www.zzyq.cc
X-IS-INFO:304,376,331,376,331,620,304,620;8,13
TITLE;CHARSET=utf-8:研发总监
X-IS-INFO:540,331,565,331,565,441,540,441;9,16,11,10,0,13
ORG;CHARSET=utf-8:北京中周理才信息技术有限公司;
X-IS-INFO:477,106,508,106,508,617,477,617;10,9,11,0,13
ADR;WORK;PREF;CHARSET=utf-8:;;开福区北辰三角洲 D3区1栋3001;长沙市;;410008;中国
X-IS-INFO:273,121,452,121,452,621,273,621;11,13
LABEL;WORK;PREF;CHARSET=utf-8:长沙市开福区北辰三角洲 D3区1栋3001, 410008
X-IS-INFO:273,121,452,121,452,621,273,621;11,13
NOTE;CHARSET=utf-8:中周至尚
X-IS-INFO:316,740,366,740,366,957,316,957;13,10,11,9,0
NOTE;CHARSET=utf-8:ZINGROW
X-IS-INFO:279,739,311,739,311,964,279,964;13,10,11,9,0
GEO:39.95;-75.1667
SOUND;OGG:http://example.com/sound.ogg
END:VCARD
BEGIN:VCARD
VERSION:3.0
N:Gump;Forrest;;Mr.
FN:Forrest Gump
ORG:Bubba Gump Shrimp Co.
TITLE:Shrimp Man
PHOTO;VALUE=URL;TYPE=GIF:http://www.example.com/dir_photos/my_photo.gif
TEL;TYPE=WORK,VOICE:(111) 555-1212
TEL;TYPE=HOME,VOICE:(404) 555-1212
ADR;TYPE=WORK:;;100 Waters Edge;Baytown;LA;30314;United States of America
LABEL;TYPE=WORK:100 Waters Edge\nBaytown\, LA 30314\nUnited States of Ameri
ca
ADR;TYPE=HOME:;;42 Plantation St.;Baytown;LA;30314;United States of America
LABEL;TYPE=HOME:42 Plantation St.\nBaytown\, LA 30314\nUnited States of Ame
rica
EMAIL;TYPE=PREF,INTERNET:forrestgump@example.com
IMPP;X-SERVICE-TYPE=Skype;type=WORK;type=pref:skype:neil.mckeown2
item1.ADR;TYPE=WORK:;;100 Waters Edge;Baytown;LA;30314;United States of America
PRODID:-//Apple Inc.//iOS 7.0.4//EN
REV:2008-04-24T19:52:43Z
END:VCARD
BEGIN:VCARD
VERSION:4.0
N:Gump;Forrest;;;
FN:Forrest Gump
ORG:Bubba Gump Shrimp Co.
TITLE:Shrimp Man
PHOTO;MEDIATYPE=image/gif:http://www.example.com/dir_photos/my_photo.gif
TEL;TYPE=work,voice;VALUE=uri:tel:+11115551212
TEL;TYPE=home,voice;VALUE=uri:tel:+14045551212
ADR;TYPE=work;LABEL="100 \" Waters Edge\nBaytown, LA 30314\nUnited States of A
merica":;;100 Waters Edge;Baytown;LA;30314;United States of America
ADR;TYPE=home;LABEL="42 Plantation St.\nBaytown, LA 30314\nUnited States of
America":;;42 Plantation St.;Baytown;LA;30314;United States of America
EMAIL:forrestgump@example.com
REV:20080424T195243Z
LANG:fr-CA
GEO:geo:39.95,-75.1667
END:VCARD

498
node_modules/vcard-js/test/mix.vcf.json generated vendored Normal file
View File

@ -0,0 +1,498 @@
[
[
"vcard",
[
[
"version",
{},
"text",
"2.1"
],
[
"rev",
{},
"timestamp",
"20151216T141119Z"
],
[
"x-generator",
{},
"text",
"IntSig"
],
[
"x-is-angle",
{},
"text",
"90"
],
[
"n",
{
"charset": "utf-8"
},
"text",
"周;宪"
],
[
"x-is-info",
{},
"text",
"0,0,0,0,0,0,0,0;1,2,13"
],
[
"fn",
{
"charset": "utf-8"
},
"text",
"周宪"
],
[
"x-is-info",
{},
"text",
"540,484,583,484,583,615,540,615;0,9,10,13"
],
[
"tel",
{
"type": [
"CELL",
"VOICE"
]
},
"text",
"18573183138"
],
[
"x-is-info",
{},
"text",
"400,373,423,373,423,619,400,619;6,13"
],
[
"tel",
{
"type": [
"WORK",
"VOICE"
]
},
"text",
"073188033808"
],
[
"x-is-info",
{},
"text",
"369,338,392,338,392,619,369,619;3,4,5,6,13"
],
[
"email",
{
"type": [
"PREF",
"INTERNET"
]
},
"text",
"66426222@qq.com"
],
[
"x-is-info",
{},
"text",
"336,296,362,296,362,619,336,619;7,14,13"
],
[
"url",
{
"type": [
"WORK"
],
"charset": "utf-8"
},
"text",
"www.zzyq.cc"
],
[
"x-is-info",
{},
"text",
"304,376,331,376,331,620,304,620;8,13"
],
[
"title",
{
"charset": "utf-8"
},
"text",
"研发总监"
],
[
"x-is-info",
{},
"text",
"540,331,565,331,565,441,540,441;9,16,11,10,0,13"
],
[
"org",
{
"charset": "utf-8"
},
"text",
"北京中周理才信息技术有限公司;"
],
[
"x-is-info",
{},
"text",
"477,106,508,106,508,617,477,617;10,9,11,0,13"
],
[
"adr",
{
"type": [
"WORK",
"PREF"
],
"charset": "utf-8"
},
"text",
";;开福区北辰三角洲 D3区1栋3001;长沙市;;410008;中国"
],
[
"x-is-info",
{},
"text",
"273,121,452,121,452,621,273,621;11,13"
],
[
"label",
{
"type": [
"WORK",
"PREF"
],
"charset": "utf-8"
},
"text",
"长沙市开福区北辰三角洲 D3区1栋3001, 410008"
],
[
"x-is-info",
{},
"text",
"273,121,452,121,452,621,273,621;11,13"
],
[
"note",
{
"charset": "utf-8"
},
"text",
"中周至尚"
],
[
"x-is-info",
{},
"text",
"316,740,366,740,366,957,316,957;13,10,11,9,0"
],
[
"note",
{
"charset": "utf-8"
},
"text",
"ZINGROW"
],
[
"x-is-info",
{},
"text",
"279,739,311,739,311,964,279,964;13,10,11,9,0"
],
[
"geo",
{},
"text",
"39.95;-75.1667"
],
[
"sound",
{
"type": [
"OGG"
]
},
"uri",
"http://example.com/sound.ogg"
]
]
],
[
"vcard",
[
[
"version",
{},
"text",
"3.0"
],
[
"n",
{},
"text",
"Gump;Forrest;;Mr."
],
[
"fn",
{},
"text",
"Forrest Gump"
],
[
"org",
{},
"text",
"Bubba Gump Shrimp Co."
],
[
"title",
{},
"text",
"Shrimp Man"
],
[
"photo",
{
"type": [
"GIF"
]
},
"URL",
"http://www.example.com/dir_photos/my_photo.gif"
],
[
"tel",
{
"type": [
"WORK",
"VOICE"
]
},
"text",
"(111) 555-1212"
],
[
"tel",
{
"type": [
"HOME",
"VOICE"
]
},
"text",
"(404) 555-1212"
],
[
"adr",
{
"type": [
"WORK"
]
},
"text",
";;100 Waters Edge;Baytown;LA;30314;United States of America"
],
[
"label",
{
"type": [
"WORK"
]
},
"text",
"100 Waters Edge\\nBaytown\\, LA 30314\\nUnited States of America"
],
[
"adr",
{
"type": [
"HOME"
]
},
"text",
";;42 Plantation St.;Baytown;LA;30314;United States of America"
],
[
"label",
{
"type": [
"HOME"
]
},
"text",
"42 Plantation St.\\nBaytown\\, LA 30314\\nUnited States of America"
],
[
"email",
{
"type": [
"PREF",
"INTERNET"
]
},
"text",
"forrestgump@example.com"
],
[
"impp",
{
"x-service-type": "Skype",
"type": [
"WORK",
"pref"
]
},
"text",
"skype:neil.mckeown2"
],
[
"adr",
{
"type": [
"WORK"
]
},
"text",
";;100 Waters Edge;Baytown;LA;30314;United States of America"
],
[
"prodid",
{},
"text",
"-//Apple Inc.//iOS 7.0.4//EN"
],
[
"rev",
{},
"timestamp",
"2008-04-24T19:52:43Z"
]
]
],
[
"vcard",
[
[
"version",
{},
"text",
"4.0"
],
[
"n",
{},
"text",
"Gump;Forrest;;;"
],
[
"fn",
{},
"text",
"Forrest Gump"
],
[
"org",
{},
"text",
"Bubba Gump Shrimp Co."
],
[
"title",
{},
"text",
"Shrimp Man"
],
[
"photo",
{
"mediatype": "image/gif"
},
"uri",
"http://www.example.com/dir_photos/my_photo.gif"
],
[
"tel",
{
"type": [
"work",
"voice"
]
},
"uri",
"tel:+11115551212"
],
[
"tel",
{
"type": [
"home",
"voice"
]
},
"uri",
"tel:+14045551212"
],
[
"adr",
{
"type": [
"work"
],
"label": "100 \\\" Waters Edge\\nBaytown, LA 30314\\nUnited States of America"
},
"text",
";;100 Waters Edge;Baytown;LA;30314;United States of America"
],
[
"adr",
{
"type": [
"home"
],
"label": "42 Plantation St.\\nBaytown, LA 30314\\nUnited States ofAmerica"
},
"text",
";;42 Plantation St.;Baytown;LA;30314;United States of America"
],
[
"email",
{},
"text",
"forrestgump@example.com"
],
[
"rev",
{},
"timestamp",
"20080424T195243Z"
],
[
"lang",
{},
"language-tag",
"fr-CA"
],
[
"geo",
{},
"text",
"geo:39.95,-75.1667"
]
]
]
]

67
node_modules/vcard-js/test/mix.vcf.txt generated vendored Normal file
View File

@ -0,0 +1,67 @@
BEGIN:VCARD
REV:20151216T141119Z
X-GENERATOR:IntSig
X-IS-ANGLE:90
N;CHARSET=utf-8:周;宪
X-IS-INFO:0,0,0,0,0,0,0,0;1,2,13
FN;CHARSET=utf-8:周宪
X-IS-INFO:540,484,583,484,583,615,540,615;0,9,10,13
TEL;CELL;VOICE:18573183138
X-IS-INFO:400,373,423,373,423,619,400,619;6,13
TEL;WORK;VOICE:073188033808
X-IS-INFO:369,338,392,338,392,619,369,619;3,4,5,6,13
EMAIL;PREF;INTERNET:66426222@qq.com
X-IS-INFO:336,296,362,296,362,619,336,619;7,14,13
URL;WORK;CHARSET=utf-8:www.zzyq.cc
X-IS-INFO:304,376,331,376,331,620,304,620;8,13
TITLE;CHARSET=utf-8:研发总监
X-IS-INFO:540,331,565,331,565,441,540,441;9,16,11,10,0,13
ORG;CHARSET=utf-8:北京中周理才信息技术有限公司;
X-IS-INFO:477,106,508,106,508,617,477,617;10,9,11,0,13
ADR;WORK;PREF;CHARSET=utf-8:;;开福区北辰三角洲 D3区1栋3001;长沙市;;410008;中国
X-IS-INFO:273,121,452,121,452,621,273,621;11,13
LABEL;WORK;PREF;CHARSET=utf-8:长沙市开福区北辰三角洲 D3区1栋3001, 410008
X-IS-INFO:273,121,452,121,452,621,273,621;11,13
NOTE;CHARSET=utf-8:中周至尚
X-IS-INFO:316,740,366,740,366,957,316,957;13,10,11,9,0
NOTE;CHARSET=utf-8:ZINGROW
X-IS-INFO:279,739,311,739,311,964,279,964;13,10,11,9,0
GEO:39.95;-75.1667
SOUND;OGG:http://example.com/sound.ogg
VERSION:2.1
END:VCARD
BEGIN:VCARD
N:Gump;Forrest;;Mr.
FN:Forrest Gump
ORG:Bubba Gump Shrimp Co.
TITLE:Shrimp Man
PHOTO;TYPE=GIF:http://www.example.com/dir_photos/my_photo.gif
TEL;TYPE=WORK,VOICE:(111) 555-1212
TEL;TYPE=HOME,VOICE:(404) 555-1212
ADR;TYPE=WORK:;;100 Waters Edge;Baytown;LA;30314;United States of America
LABEL;TYPE=WORK:100 Waters Edge\nBaytown\, LA 30314\nUnited States of America
ADR;TYPE=HOME:;;42 Plantation St.;Baytown;LA;30314;United States of America
LABEL;TYPE=HOME:42 Plantation St.\nBaytown\, LA 30314\nUnited States of America
EMAIL;TYPE=PREF,INTERNET:forrestgump@example.com
IMPP;X-SERVICE-TYPE=Skype;TYPE=WORK;TYPE=pref:skype:neil.mckeown2
ADR;TYPE=WORK:;;100 Waters Edge;Baytown;LA;30314;United States of America
PRODID:-//Apple Inc.//iOS 7.0.4//EN
REV:2008-04-24T19:52:43Z
VERSION:3.0
END:VCARD
BEGIN:VCARD
N:Gump;Forrest;;;
FN:Forrest Gump
ORG:Bubba Gump Shrimp Co.
TITLE:Shrimp Man
PHOTO;MEDIATYPE=image/gif:http://www.example.com/dir_photos/my_photo.gif
TEL;TYPE=work,voice:tel:+11115551212
TEL;TYPE=home,voice:tel:+14045551212
ADR;TYPE=work;LABEL="100 \" Waters Edge\nBaytown, LA 30314\nUnited States of America":;;100 Waters Edge;Baytown;LA;30314;United States of America
ADR;TYPE=home;LABEL="42 Plantation St.\nBaytown, LA 30314\nUnited States ofAmerica":;;42 Plantation St.;Baytown;LA;30314;United States of America
EMAIL:forrestgump@example.com
REV:20080424T195243Z
LANG:fr-CA
GEO:geo:39.95,-75.1667
VERSION:4.0
END:VCARD

66
node_modules/vcard-js/test/test.js generated vendored Normal file
View File

@ -0,0 +1,66 @@
var assert = require('assert');
var fs = require('fs');
var VCard = require('../index.js');
VCard.debug = function(any){
if(any instanceof VCard.Item){
if(/^(photo)$/i.test(any.name) || typeof any._origin !== 'string')
return;
var vCard = any._vCard;
var line = any._origin;
var text = any.toString(vCard.version);
var json = any.toJSON();
if(text.toLowerCase() === line.toLowerCase())
return;
console.log('\n\nfilename : %s\nversion\t : %s', vCard._filename, vCard.version);
console.log('origin\t : %s', any._origin);
console.log('text\t : %s', text);
console.log('json\t : %j', json);
}else if(any instanceof VCard){
if(isNaN(any.version)){
console.log('\n\nfilename : %s\nversion\t : %s', any._filename, any.version);
}
}
};
var dir = '' || __dirname;
fs.readdir(dir, function(err, files){
if(err)
throw err;
for(var i in files)
(function(file){
if(/\.vcf$/i.test(file)){
var filename = dir + '/'+ file;
VCard.readFile(filename, {
filter : function(any){
if(any instanceof VCard){
return /^(2\.1|3\.0|4\.0)$/.test(any.version);
}
return true;
}
}, function(err, list, data){
if(err)
throw err;
var jsonStr = JSON.stringify(list, null, ' ');
var jsonArr = JSON.parse(jsonStr);
list = VCard.parse(jsonArr);
list.forEach(function(vCard){
var version = vCard.find('version')[0].value;
assert.ok(vCard.remove('version'))
assert.equal(vCard.add('VERSION:'+version).value, version);
});
jsonArr = list.map(function(vCard){
return vCard.toJSON();
});
fs.writeFileSync(filename + '.txt', VCard.serialize(jsonArr));
fs.writeFileSync(filename + '.json', jsonStr);
});
}
})(files[i]);
});

31
package-lock.json generated
View File

@ -76,7 +76,8 @@
"sonner": "^1.7.1",
"tailwind-merge": "^2.5.5",
"tailwindcss-animate": "^1.0.7",
"vaul": "^0.9.6"
"vaul": "^0.9.6",
"vcard-js": "^1.2.2"
},
"devDependencies": {
"@types/imapflow": "^1.0.20",
@ -5225,6 +5226,18 @@
"integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==",
"license": "MIT"
},
"node_modules/quoted-printable": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/quoted-printable/-/quoted-printable-1.0.1.tgz",
"integrity": "sha512-cihC68OcGiQOjGiXuo5Jk6XHANTHl1K4JLk/xlEJRTIXfy19Sg6XzB95XonYgr+1rB88bCpr7WZE7D7AlZow4g==",
"license": "MIT",
"dependencies": {
"utf8": "^2.1.0"
},
"bin": {
"quoted-printable": "bin/quoted-printable"
}
},
"node_modules/react": {
"version": "18.3.1",
"resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
@ -6109,6 +6122,12 @@
"semver": "~5.3.0"
}
},
"node_modules/utf8": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/utf8/-/utf8-2.1.2.tgz",
"integrity": "sha512-QXo+O/QkLP/x1nyi54uQiG0XrODxdysuQvE5dtVqv7F5K2Qb6FsN+qbr6KhF5wQ20tfcV3VQp0/2x1e1MRSPWg==",
"license": "MIT"
},
"node_modules/util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
@ -6136,6 +6155,16 @@
"react-dom": "^16.8 || ^17.0 || ^18.0"
}
},
"node_modules/vcard-js": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/vcard-js/-/vcard-js-1.2.2.tgz",
"integrity": "sha512-YShz0/tIXJ3gOg2o/OCNzuPCb7KTnhjn81cUaTZg5+elb99yVr+MRMkbD+vljTny6YuocPI0Dtb1ttG2Yf8oMg==",
"license": "ISC",
"dependencies": {
"quoted-printable": "^1.0.0",
"utf8": "^2.1.1"
}
},
"node_modules/victory-vendor": {
"version": "36.9.2",
"resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-36.9.2.tgz",

View File

@ -77,7 +77,8 @@
"sonner": "^1.7.1",
"tailwind-merge": "^2.5.5",
"tailwindcss-animate": "^1.0.7",
"vaul": "^0.9.6"
"vaul": "^0.9.6",
"vcard-js": "^1.2.2"
},
"devDependencies": {
"@types/imapflow": "^1.0.20",

8
types/vcard-js.d.ts vendored Normal file
View File

@ -0,0 +1,8 @@
declare module 'vcard-js' {
export class VCard {
parse(vcardString: string): void;
toString(): string;
getProperty(name: string): { value: string } | null;
setProperty(name: string, value: string): void;
}
}

View File

@ -2462,6 +2462,13 @@ quick-format-unescaped@^4.0.3:
resolved "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz"
integrity sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==
quoted-printable@^1.0.0:
version "1.0.1"
resolved "https://registry.npmjs.org/quoted-printable/-/quoted-printable-1.0.1.tgz"
integrity sha512-cihC68OcGiQOjGiXuo5Jk6XHANTHl1K4JLk/xlEJRTIXfy19Sg6XzB95XonYgr+1rB88bCpr7WZE7D7AlZow4g==
dependencies:
utf8 "^2.1.0"
react-datepicker@^8.3.0:
version "8.3.0"
resolved "https://registry.npmjs.org/react-datepicker/-/react-datepicker-8.3.0.tgz"
@ -2948,6 +2955,11 @@ utf7@>=1.0.2:
dependencies:
semver "~5.3.0"
utf8@^2.1.0, utf8@^2.1.1:
version "2.1.2"
resolved "https://registry.npmjs.org/utf8/-/utf8-2.1.2.tgz"
integrity sha512-QXo+O/QkLP/x1nyi54uQiG0XrODxdysuQvE5dtVqv7F5K2Qb6FsN+qbr6KhF5wQ20tfcV3VQp0/2x1e1MRSPWg==
util-deprecate@^1.0.2:
version "1.0.2"
resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz"
@ -2965,6 +2977,14 @@ vaul@^0.9.6:
dependencies:
"@radix-ui/react-dialog" "^1.1.1"
vcard-js@^1.2.2:
version "1.2.2"
resolved "https://registry.npmjs.org/vcard-js/-/vcard-js-1.2.2.tgz"
integrity sha512-YShz0/tIXJ3gOg2o/OCNzuPCb7KTnhjn81cUaTZg5+elb99yVr+MRMkbD+vljTny6YuocPI0Dtb1ttG2Yf8oMg==
dependencies:
quoted-printable "^1.0.0"
utf8 "^2.1.1"
victory-vendor@^36.6.8:
version "36.9.2"
resolved "https://registry.npmjs.org/victory-vendor/-/victory-vendor-36.9.2.tgz"