carnet panel contact
This commit is contained in:
parent
0d8a099aef
commit
ef6f08b6bc
@ -11,6 +11,7 @@ import { useMediaQuery } from "@/hooks/use-media-query";
|
|||||||
import { ContactsView } from '@/components/carnet/contacts-view';
|
import { ContactsView } from '@/components/carnet/contacts-view';
|
||||||
import { X, Menu } from "lucide-react";
|
import { X, Menu } from "lucide-react";
|
||||||
import { ContactDetails } from '@/components/carnet/contact-details';
|
import { ContactDetails } from '@/components/carnet/contact-details';
|
||||||
|
import { VCard } from 'vcard-js';
|
||||||
|
|
||||||
// Layout modes
|
// Layout modes
|
||||||
export enum PaneLayout {
|
export enum PaneLayout {
|
||||||
@ -163,93 +164,21 @@ export default function CarnetPage() {
|
|||||||
|
|
||||||
const parseVCard = (content: string): Contact[] => {
|
const parseVCard = (content: string): Contact[] => {
|
||||||
try {
|
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
|
return {
|
||||||
const vcardSections = content.split('BEGIN:VCARD').filter(section => section.trim());
|
id: vcard.getProperty('UID')?.value || Math.random().toString(36).substr(2, 9),
|
||||||
console.log('Found vCard sections:', vcardSections.length);
|
fullName: vcard.getProperty('FN')?.value || '',
|
||||||
|
email: vcard.getProperty('EMAIL')?.value || '',
|
||||||
return vcardSections.map(section => {
|
phone: vcard.getProperty('TEL')?.value || '',
|
||||||
const lines = section.split('\n').filter(line => line.trim());
|
organization: vcard.getProperty('ORG')?.value || '',
|
||||||
console.log('Processing vCard section with lines:', lines.length);
|
address: vcard.getProperty('ADR')?.value || '',
|
||||||
|
notes: vcard.getProperty('NOTE')?.value || '',
|
||||||
const contact: Partial<Contact> = {
|
group: vcard.getProperty('CATEGORIES')?.value || ''
|
||||||
id: Math.random().toString(36).substr(2, 9),
|
|
||||||
fullName: '',
|
|
||||||
email: '',
|
|
||||||
phone: '',
|
|
||||||
organization: '',
|
|
||||||
address: '',
|
|
||||||
notes: ''
|
|
||||||
};
|
};
|
||||||
|
|
||||||
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) {
|
} catch (error) {
|
||||||
console.error('Error parsing VCF content:', error);
|
console.error('Error parsing VCF content:', error);
|
||||||
@ -548,21 +477,18 @@ export default function CarnetPage() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const generateVCard = (contact: Contact): string => {
|
const generateVCard = (contact: Contact): string => {
|
||||||
const vcard = [
|
const vcard = new 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');
|
|
||||||
|
|
||||||
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) {
|
if (isLoading) {
|
||||||
|
|||||||
1
node_modules/.bin/quoted-printable
generated
vendored
Symbolic link
1
node_modules/.bin/quoted-printable
generated
vendored
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../quoted-printable/bin/quoted-printable
|
||||||
28
node_modules/.package-lock.json
generated
vendored
28
node_modules/.package-lock.json
generated
vendored
@ -4603,6 +4603,18 @@
|
|||||||
"integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==",
|
"integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==",
|
||||||
"license": "MIT"
|
"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": {
|
"node_modules/react": {
|
||||||
"version": "18.3.1",
|
"version": "18.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
|
||||||
@ -5487,6 +5499,12 @@
|
|||||||
"semver": "~5.3.0"
|
"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": {
|
"node_modules/util-deprecate": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
"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"
|
"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": {
|
"node_modules/victory-vendor": {
|
||||||
"version": "36.9.2",
|
"version": "36.9.2",
|
||||||
"resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-36.9.2.tgz",
|
"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
20
node_modules/quoted-printable/LICENSE-MIT.txt
generated
vendored
Normal 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
151
node_modules/quoted-printable/README.md
generated
vendored
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
# quoted-printable [](https://travis-ci.org/mathiasbynens/quoted-printable) [](https://coveralls.io/r/mathiasbynens/quoted-printable) [](https://gemnasium.com/mathiasbynens/quoted-printable)
|
||||||
|
|
||||||
|
_quoted-printable_ is a character encoding–agnostic 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). [Here’s 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. Here’s 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 that’s being used. Here’s 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, you’ll be able to use `quoted-printable` on the command line. Note that while the _quoted-printable_ library itself is character encoding–agnostic, 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 that’s 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
|
||||||
|
|
||||||
|
| [](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
116
node_modules/quoted-printable/bin/quoted-printable
generated
vendored
Executable 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 don’t actively support. However, we don’t 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
58
node_modules/quoted-printable/man/quoted-printable.1
generated
vendored
Normal 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
57
node_modules/quoted-printable/package.json
generated
vendored
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
{
|
||||||
|
"name": "quoted-printable",
|
||||||
|
"version": "1.0.1",
|
||||||
|
"description": "A robust & character encoding–agnostic 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
153
node_modules/quoted-printable/quoted-printable.js
generated
vendored
Normal 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)) {
|
||||||
|
// There’s 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) {
|
||||||
|
// It’s possible to encode the character without exceeding the line
|
||||||
|
// length limit.
|
||||||
|
result.push(
|
||||||
|
handleTrailingCharacters(buffer)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// It’s 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
20
node_modules/utf8/LICENSE-MIT.txt
generated
vendored
Normal 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
119
node_modules/utf8/README.md
generated
vendored
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
# utf8.js [](https://travis-ci.org/mathiasbynens/utf8.js) [](https://coveralls.io/r/mathiasbynens/utf8.js) [](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). [Here’s 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 that’s 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? Haven’t 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
|
||||||
|
|
||||||
|
| [](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
39
node_modules/utf8/package.json
generated
vendored
Normal 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
244
node_modules/utf8/utf8.js
generated
vendored
Normal 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, it’s 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
6
node_modules/vcard-js/.npmignore
generated
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
/out
|
||||||
|
node_modules
|
||||||
|
npm-debug.log
|
||||||
|
.*.swp
|
||||||
|
.direcotry
|
||||||
|
*~
|
||||||
89
node_modules/vcard-js/README.md
generated
vendored
Normal file
89
node_modules/vcard-js/README.md
generated
vendored
Normal 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
1
node_modules/vcard-js/index.js
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require('./lib/VCard');
|
||||||
713
node_modules/vcard-js/lib/VCard.js
generated
vendored
Normal file
713
node_modules/vcard-js/lib/VCard.js
generated
vendored
Normal 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
31
node_modules/vcard-js/package.json
generated
vendored
Normal 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
21
node_modules/vcard-js/test/helloWorld.js
generated
vendored
Normal 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
73
node_modules/vcard-js/test/mix.vcf
generated
vendored
Normal 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
498
node_modules/vcard-js/test/mix.vcf.json
generated
vendored
Normal 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
67
node_modules/vcard-js/test/mix.vcf.txt
generated
vendored
Normal 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
66
node_modules/vcard-js/test/test.js
generated
vendored
Normal 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
31
package-lock.json
generated
@ -76,7 +76,8 @@
|
|||||||
"sonner": "^1.7.1",
|
"sonner": "^1.7.1",
|
||||||
"tailwind-merge": "^2.5.5",
|
"tailwind-merge": "^2.5.5",
|
||||||
"tailwindcss-animate": "^1.0.7",
|
"tailwindcss-animate": "^1.0.7",
|
||||||
"vaul": "^0.9.6"
|
"vaul": "^0.9.6",
|
||||||
|
"vcard-js": "^1.2.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/imapflow": "^1.0.20",
|
"@types/imapflow": "^1.0.20",
|
||||||
@ -5225,6 +5226,18 @@
|
|||||||
"integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==",
|
"integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==",
|
||||||
"license": "MIT"
|
"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": {
|
"node_modules/react": {
|
||||||
"version": "18.3.1",
|
"version": "18.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
|
||||||
@ -6109,6 +6122,12 @@
|
|||||||
"semver": "~5.3.0"
|
"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": {
|
"node_modules/util-deprecate": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
"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"
|
"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": {
|
"node_modules/victory-vendor": {
|
||||||
"version": "36.9.2",
|
"version": "36.9.2",
|
||||||
"resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-36.9.2.tgz",
|
"resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-36.9.2.tgz",
|
||||||
|
|||||||
@ -77,7 +77,8 @@
|
|||||||
"sonner": "^1.7.1",
|
"sonner": "^1.7.1",
|
||||||
"tailwind-merge": "^2.5.5",
|
"tailwind-merge": "^2.5.5",
|
||||||
"tailwindcss-animate": "^1.0.7",
|
"tailwindcss-animate": "^1.0.7",
|
||||||
"vaul": "^0.9.6"
|
"vaul": "^0.9.6",
|
||||||
|
"vcard-js": "^1.2.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/imapflow": "^1.0.20",
|
"@types/imapflow": "^1.0.20",
|
||||||
|
|||||||
8
types/vcard-js.d.ts
vendored
Normal file
8
types/vcard-js.d.ts
vendored
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
20
yarn.lock
20
yarn.lock
@ -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"
|
resolved "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz"
|
||||||
integrity sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==
|
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:
|
react-datepicker@^8.3.0:
|
||||||
version "8.3.0"
|
version "8.3.0"
|
||||||
resolved "https://registry.npmjs.org/react-datepicker/-/react-datepicker-8.3.0.tgz"
|
resolved "https://registry.npmjs.org/react-datepicker/-/react-datepicker-8.3.0.tgz"
|
||||||
@ -2948,6 +2955,11 @@ utf7@>=1.0.2:
|
|||||||
dependencies:
|
dependencies:
|
||||||
semver "~5.3.0"
|
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:
|
util-deprecate@^1.0.2:
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz"
|
resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz"
|
||||||
@ -2965,6 +2977,14 @@ vaul@^0.9.6:
|
|||||||
dependencies:
|
dependencies:
|
||||||
"@radix-ui/react-dialog" "^1.1.1"
|
"@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:
|
victory-vendor@^36.6.8:
|
||||||
version "36.9.2"
|
version "36.9.2"
|
||||||
resolved "https://registry.npmjs.org/victory-vendor/-/victory-vendor-36.9.2.tgz"
|
resolved "https://registry.npmjs.org/victory-vendor/-/victory-vendor-36.9.2.tgz"
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user