/* THIS IS A GENERATED/BUNDLED FILE BY ESBUILD if you want to view the source, please visit the github repository of this plugin */ var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __commonJS = (cb, mod) => function __require() { return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; }; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // node_modules/foldline/foldline.js var require_foldline = __commonJS({ "node_modules/foldline/foldline.js"(exports, module2) { var CRLF = "\r\n"; var SP = " "; var MAX_LINE_LENGTH = 998; var DEFAULT_LINE_LENGTH = 78; var MIN_LINE_LENGTH = 2; function foldLine(input, maxLength, hardWrap) { if (maxLength != null && maxLength < MIN_LINE_LENGTH) { throw new Error("Maximum length must not be less than " + MIN_LINE_LENGTH); } if (maxLength != null && maxLength > MAX_LINE_LENGTH) { throw new Error("Maximum length must not exceed " + MAX_LINE_LENGTH); } maxLength = maxLength || DEFAULT_LINE_LENGTH; input = input.replace(/[\r\n]+/g, ""); if (input.length <= maxLength) { return input; } var output = ""; var index = 0; var nextIndex = 0; var length = input.length; var line = 0; var trim = 0; while (index < length) { if (!hardWrap && ~(nextIndex = input.lastIndexOf(SP, index + maxLength))) { if (nextIndex > index) { output += input.slice(index, nextIndex) + CRLF + SP; index = nextIndex; } else { output += input.slice(index, index + maxLength - trim) + CRLF + SP; index = index + maxLength - trim; hardWrap = true; } } else { output += input.slice(index, index + maxLength - trim) + CRLF + SP; index = index + maxLength - trim; } if (length - index < maxLength) { output += input.slice(index); break; } if (line === 0) { trim = 1; } line++; } return output; } foldLine.unfold = function unfold(input) { return input.replace(/\r\n\s/gm, ""); }; module2.exports = foldLine; } }); // node_modules/camelcase/index.js var require_camelcase = __commonJS({ "node_modules/camelcase/index.js"(exports, module2) { "use strict"; var preserveCamelCase = (string) => { let isLastCharLower = false; let isLastCharUpper = false; let isLastLastCharUpper = false; for (let i = 0; i < string.length; i++) { const character = string[i]; if (isLastCharLower && /[a-zA-Z]/.test(character) && character.toUpperCase() === character) { string = string.slice(0, i) + "-" + string.slice(i); isLastCharLower = false; isLastLastCharUpper = isLastCharUpper; isLastCharUpper = true; i++; } else if (isLastCharUpper && isLastLastCharUpper && /[a-zA-Z]/.test(character) && character.toLowerCase() === character) { string = string.slice(0, i - 1) + "-" + string.slice(i - 1); isLastLastCharUpper = isLastCharUpper; isLastCharUpper = false; isLastCharLower = true; } else { isLastCharLower = character.toLowerCase() === character && character.toUpperCase() !== character; isLastLastCharUpper = isLastCharUpper; isLastCharUpper = character.toUpperCase() === character && character.toLowerCase() !== character; } } return string; }; var camelCase = (input, options) => { if (!(typeof input === "string" || Array.isArray(input))) { throw new TypeError("Expected the input to be `string | string[]`"); } options = Object.assign({ pascalCase: false }, options); const postProcess = (x) => options.pascalCase ? x.charAt(0).toUpperCase() + x.slice(1) : x; if (Array.isArray(input)) { input = input.map((x) => x.trim()).filter((x) => x.length).join("-"); } else { input = input.trim(); } if (input.length === 0) { return ""; } if (input.length === 1) { return options.pascalCase ? input.toUpperCase() : input.toLowerCase(); } const hasUpperCase = input !== input.toLowerCase(); if (hasUpperCase) { input = preserveCamelCase(input); } input = input.replace(/^[_.\- ]+/, "").toLowerCase().replace(/[_.\- ]+(\w|$)/g, (_, p1) => p1.toUpperCase()).replace(/\d+(\w|$)/g, (m) => m.toUpperCase()); return postProcess(input); }; module2.exports = camelCase; module2.exports.default = camelCase; } }); // node_modules/vcf/lib/property.js var require_property = __commonJS({ "node_modules/vcf/lib/property.js"(exports, module2) { function Property(field, value, params) { if (!(this instanceof Property)) return new Property(value); if (params != null) Object.assign(this, params); this._field = field; this._data = value; Object.defineProperty(this, "_field", { enumerable: false }); Object.defineProperty(this, "_data", { enumerable: false }); } Property.fromJSON = function(data) { var field = data[0]; var params = data[1]; if (!/text/i.test(data[2])) params.value = data[2]; var value = Array.isArray(data[3]) ? data[3].join(";") : data[3]; return new Property(field, value, params); }; function capitalDashCase(value) { return value.replace(/([A-Z])/g, "-$1").toUpperCase(); } Property.prototype = { constructor: Property, /** * Check whether the property is of a given type * @param {String} type * @return {Boolean} */ is: function(type) { type = (type + "").toLowerCase(); return Array.isArray(this.type) ? this.type.indexOf(type) >= 0 : this.type === type; }, /** * Check whether the property is empty * @return {Boolean} */ isEmpty: function() { return this._data == null && Object.keys(this).length === 0; }, /** * Clone the property * @return {Property} */ clone: function() { return new Property(this._field, this._data, this); }, /** * Format the property as vcf with given version * @param {String} version * @return {String} */ toString: function(version) { var propName = (this.group ? this.group + "." : "") + capitalDashCase(this._field); var keys = Object.keys(this); var params = []; for (var i = 0; i < keys.length; i++) { if (keys[i] === "group") continue; switch (propName) { case "TEL": case "ADR": case "EMAIL": if (version === "2.1") { if (Array.isArray(this[keys[i]])) params.push(this[keys[i]].join(";")); else params.push(this[keys[i]]); } else params.push(capitalDashCase(keys[i]) + "=" + this[keys[i]]); break; default: params.push(capitalDashCase(keys[i]) + "=" + this[keys[i]]); } } if (version === "2.1" || version === "3.0") return propName + (params.length ? ";" + params.join(";").toUpperCase() : params.toString().toUpperCase()) + ":" + (Array.isArray(this._data) ? this._data.join(";") : this._data); else return propName + (params.length ? ";" + params.join(";") : params) + ":" + (Array.isArray(this._data) ? this._data.join(";") : this._data); }, /** * Get the property's value * @return {String} */ valueOf: function() { return this._data; }, /** * Format the property as jCard data * @return {Array} */ toJSON: function() { var params = Object.assign({}, this); if (params.value === "text") { params.value = void 0; delete params.value; } var data = [this._field, params, this.value || "text"]; switch (this._field) { default: data.push(this._data); break; case "adr": case "n": data.push(this._data.split(";")); } return data; } }; module2.exports = Property; } }); // node_modules/vcf/lib/parse-lines.js var require_parse_lines = __commonJS({ "node_modules/vcf/lib/parse-lines.js"(exports, module2) { var camelCase = require_camelcase(); var Property = require_property(); function set(object, key, value) { if (Array.isArray(object[key])) { object[key].push(value); } else if (object[key] != null) { object[key] = [object[key], value]; } else { object[key] = value; } } function createParams(params, param) { var parts = param.split("="); var k = camelCase(parts[0]); var value = parts[1]; if (value == null || value === "") { value = parts[0]; k = "type"; } if (k === "type") { if (value[0] === '"' && value[value.length - 1] === '"' && value.indexOf(",") !== -1) value = value.slice(1, -1); value.toLowerCase().split(",").forEach(function(value2) { set(params, k, value2); }); return params; } set(params, k, value); return params; } function parseLines(lines) { var data = {}; var line = null; var pattern = /^([^;:]+)((?:;(?:[^;:]+))*)(?:\:([\s\S]+))?$/i; var len = lines.length - 1; for (var i = 1; i < len; i++) { line = lines[i]; var match = pattern.exec(line); if (!match) continue; var name = match[1].split("."); var property = name.pop(); var group = name.pop(); var value = match[3]; var params = match[2] ? match[2].replace(/^;|;$/g, "").split(";") : []; var propParams = params.reduce(createParams, group ? { group } : {}); var propName = camelCase(property); var propVal = new Property(propName, value, propParams); set(data, propName, propVal); } return data; } module2.exports = parseLines; } }); // node_modules/vcf/lib/vcard.js var require_vcard = __commonJS({ "node_modules/vcf/lib/vcard.js"(exports, module2) { function vCard() { if (!(this instanceof vCard)) return new vCard(); this.version = vCard.versions[vCard.versions.length - 1]; this.data = {}; } vCard.mimeType = "text/vcard"; vCard.extension = ".vcf"; vCard.versions = ["2.1", "3.0", "4.0"]; vCard.EOL = "\r\n"; vCard.foldLine = require_foldline(); vCard.normalize = function(input) { return (input + "").replace(/^[\s\r\n]+|[\s\r\n]+$/g, "").replace(/(\r\n)[\x09\x20]?(\r\n)|$/g, "$1").replace(/\r\n[\x20\x09]/g, ""); }; vCard.isSupported = function(version) { return /^\d\.\d$/.test(version) && vCard.versions.indexOf(version) !== -1; }; vCard.parse = function(value) { var objects = (value + "").split(/(?=BEGIN\:VCARD)/gi); var cards = []; for (var i = 0; i < objects.length; i++) { cards.push(new vCard().parse(objects[i])); } return cards; }; vCard.parseLines = require_parse_lines(); vCard.fromJSON = function(jcard) { jcard = typeof jcard === "string" ? JSON.parse(jcard) : jcard; if (jcard == null || !Array.isArray(jcard)) return new vCard(); if (!/vcard/i.test(jcard[0])) throw new Error("Object not in jCard format"); var card = new vCard(); jcard[1].forEach(function(prop) { card.addProperty(vCard.Property.fromJSON(prop)); }); return card; }; vCard.format = function(card, version) { version = version || card.version || vCard.versions[vCard.versions.length - 1]; if (!vCard.isSupported(version)) throw new Error('Unsupported vCard version "' + version + '"'); var vcf3 = []; vcf3.push("BEGIN:VCARD"); vcf3.push("VERSION:" + version); var props = Object.keys(card.data); var prop = ""; for (var i = 0; i < props.length; i++) { if (props[i] === "version") continue; prop = card.data[props[i]]; if (Array.isArray(prop)) { for (var k = 0; k < prop.length; k++) { if (prop[k].isEmpty()) continue; vcf3.push(vCard.foldLine(prop[k].toString(version), 75)); } } else if (!prop.isEmpty()) { vcf3.push(vCard.foldLine(prop.toString(version), 75)); } } vcf3.push("END:VCARD"); return vcf3.join(vCard.EOL); }; vCard.Property = require_property(); vCard.prototype = { constructor: vCard, /** * Get a vCard property * @param {String} key * @return {Object|Array} */ get: function(key) { if (this.data[key] == null) { return this.data[key]; } if (Array.isArray(this.data[key])) { return this.data[key].map(function(prop) { return prop.clone(); }); } else { return this.data[key].clone(); } }, /** * Set a vCard property * @param {String} key * @param {String} value * @param {Object} params */ set: function(key, value, params) { return this.setProperty(new vCard.Property(key, value, params)); }, /** * Add a vCard property * @param {String} key * @param {String} value * @param {Object} params */ add: function(key, value, params) { var prop = new vCard.Property(key, value, params); this.addProperty(prop); return this; }, /** * Set a vCard property from an already * constructed vCard.Property * @param {vCard.Property} prop */ setProperty: function(prop) { this.data[prop._field] = prop; return this; }, /** * Add a vCard property from an already * constructed vCard.Property * @param {vCard.Property} prop */ addProperty: function(prop) { var key = prop._field; if (Array.isArray(this.data[key])) { this.data[key].push(prop); } else if (this.data[key] != null) { this.data[key] = [this.data[key], prop]; } else { this.data[key] = prop; } return this; }, /** * Parse a vcf formatted vCard * @param {String} value * @return {vCard} */ parse: function(value) { var lines = vCard.normalize(value).split(/\r\n/g); var begin = lines[0]; var version = lines[1]; var end = lines[lines.length - 1]; const regexp_version = /VERSION:\d\.\d/i; if (!/BEGIN:VCARD/i.test(begin)) throw new SyntaxError('Invalid vCard: Expected "BEGIN:VCARD" but found "' + begin + '"'); if (!/END:VCARD/i.test(end)) throw new SyntaxError('Invalid vCard: Expected "END:VCARD" but found "' + end + '"'); if (!regexp_version.test(version)) { if (!(version = lines.find((line) => regexp_version.test(line)))) throw new SyntaxError('Invalid vCard: Expected "VERSION:\\d.\\d" but none found'); } this.version = version.substring(8, 11); if (!vCard.isSupported(this.version)) throw new Error('Unsupported version "' + this.version + '"'); this.data = vCard.parseLines(lines); return this; }, /** * Format the vCard as vcf with given version * @param {String} version * @param {String} charset * @return {String} */ toString: function(version, charset) { version = version || this.version; return vCard.format(this, version); }, /** * Format the card as jCard * @param {String} version='4.0' * @return {Array} jCard */ toJCard: function(version) { version = version || "4.0"; var keys = Object.keys(this.data); var data = [["version", {}, "text", version]]; var prop = null; for (var i = 0; i < keys.length; i++) { if (keys[i] === "version") continue; prop = this.data[keys[i]]; if (Array.isArray(prop)) { for (var k = 0; k < prop.length; k++) { data.push(prop[k].toJSON()); } } else { data.push(prop.toJSON()); } } return ["vcard", data]; }, /** * Format the card as jCard * @return {Array} jCard */ toJSON: function() { return this.toJCard(this.version); } }; module2.exports = vCard; } }); // src/main.ts var main_exports = {}; __export(main_exports, { default: () => ContactsPlugin }); module.exports = __toCommonJS(main_exports); var import_obsidian2 = require("obsidian"); // src/vcard.ts var vcf = require_vcard(); var VCard = class { constructor(card) { var _a, _b, _c, _d, _e; this.version = card.version; this.fn = (_a = card.get("fn")) == null ? void 0 : _a.valueOf().replace(/\\,/g, ","); this.nickname = (_c = (_b = card.get("nickname")) == null ? void 0 : _b.valueOf()) != null ? _c : void 0; this.organization = this.parseOrganization(card.get("org")); this.title = (_e = (_d = card.get("title")) == null ? void 0 : _d.valueOf()) != null ? _e : void 0; this.telephones = this.parseTelephones(card.get("tel")); this.addresses = this.parseAddresses(card.get("adr")); this.emails = this.parseEmails(card.get("email")); this.birthdate = this.parseBirthdate(card.get("bday")); this.URLs = this.parseURLs(card.get("url")); this.notes = this.parseNotes(card.get("note")); this.xabuid = this.parseXAbuid(card.get("xAbuid")); if (this.fn == void 0) { console.debug(`Found vCard without name: ${JSON.stringify(this, null, 2)}`); } } getFilename() { var _a; return (_a = this.fn) != null ? _a : "NO_NAME"; } toMarkdown(enabledFields) { var _a; let markdown = `## \u{1F464} ${this.fn} [Open in Contacts](addressbook://${(_a = this.xabuid) == null ? void 0 : _a.replace(":", "%3A")}) `; this.getVCardFields().forEach((field) => { var _a2; if (!enabledFields.includes(field)) return; markdown += (_a2 = this.fieldToMarkdown(field)) != null ? _a2 : ""; }); return markdown.trim(); } fieldToMarkdown(field) { var _a, _b, _c, _d, _e; if (typeof this[field] === "undefined") return void 0; switch (field) { case "nickname": return `- Nickname: ${this.nickname} `; case "notes": return `- \u{1F4DD} Notes: ${this.notes} `; case "birthdate": return `- \u{1F382} Birthday: ${(_a = this.birthdate) == null ? void 0 : _a.toLocaleDateString()} `; case "organization": return `- \u{1F3E2} Organization: ${this.organization} `; case "title": return `- \u{1F454} Title: ${this.title} `; case "emails": return (_b = this.emails) == null ? void 0 : _b.map((mail) => { return `- \u{1F4E7} [${mail}](mailto:${mail}) `; }).join(""); case "URLs": return (_c = this.URLs) == null ? void 0 : _c.map((URL) => { return `- \u{1F310} Website: [${URL}](${URL}) `; }).join(""); case "telephones": return (_d = this.telephones) == null ? void 0 : _d.map(([type, tel]) => { let emotes = ``; const types = type.split(","); switch (types[0]) { case "cell": emotes += "\u{1F4F1}"; break; case "home": emotes += "\u{1F3E0}"; break; case "work": emotes += "\u{1F3E2}"; break; default: emotes += "\u260E\uFE0F"; } switch (types[1]) { case "voice": emotes += "\u{1F4DE}"; break; case "fax": emotes += "\u{1F4E0}"; break; default: } return `- ${emotes} [${tel}](tel:${tel.replace(" ", "")}) `; }).join(""); case "addresses": return (_e = this.addresses) == null ? void 0 : _e.map(([type, adr]) => { let emotes = ``; switch (type) { case "home": emotes += "\u{1F3E0}"; break; case "work": emotes += "\u{1F3E2}"; break; default: emotes += "\u260E\uFE0F"; } let [_, __, street, city, ___, postcode, country] = adr.valueOf().split(";"); return `- ${emotes} ${type} address: ${street} ${postcode} ${city} ${country} `; }).join(""); default: console.error(`Error: Unknown field or markdown convertion: ${field}`); return void 0; } } parseBirthdate(bday) { let birthdate = void 0; if (bday) { birthdate = new Date(Date.parse(bday.valueOf())); } return birthdate; } parseURLs(URLs) { let links = void 0; if (URLs) { links = new Array(); if (!Array.isArray(URLs)) { URLs = [URLs]; } for (let url of URLs) { links.push(url.valueOf()); } } return links; } parseNotes(notes) { var _a; let notesString = void 0; if (notes) { notesString = (_a = notes.valueOf()) == null ? void 0 : _a.split("\\n").map((line) => line.endsWith("\\") ? line.slice(0, line.length - 2) : line).join("\n "); } return notesString; } parseXAbuid(xabuid) { let xabuidString = void 0; if (xabuid) { xabuidString = xabuid.valueOf(); } return xabuidString; } parseEmails(email) { let emails = void 0; if (email) { emails = new Array(); if (!Array.isArray(email)) { email = [email]; } for (let mail of email) { emails.push(mail.valueOf()); } } return emails; } parseAddresses(adr) { var _a, _b, _c, _d, _e; let addresses = void 0; if (adr) { addresses = new Array(); if (!Array.isArray(adr)) { adr = [adr]; } for (let address of adr) { let type; if (typeof address.type == "string") type = (_b = (_a = address.type) == null ? void 0 : _a.toLowerCase()) != null ? _b : "home"; else if (Array.isArray(address.type)) type = (_e = (_d = (_c = address.type) == null ? void 0 : _c[0]) == null ? void 0 : _d.toLowerCase()) != null ? _e : "home"; addresses.push([type, address.valueOf()]); } } return addresses; } parseTelephones(tel) { var _a, _b, _c, _d, _e, _f; let telephones = void 0; if (tel) { telephones = new Array(); if (!Array.isArray(tel)) { tel = [tel]; } for (let telephone of tel) { let type = ((_c = (_b = (_a = telephone.type) == null ? void 0 : _a[0]) == null ? void 0 : _b.toLowerCase()) != null ? _c : "phone") + "," + ((_f = (_e = (_d = telephone.type) == null ? void 0 : _d[1]) == null ? void 0 : _e.toLowerCase()) != null ? _f : "voice"); telephones.push([type, telephone.valueOf()]); } } return telephones; } parseOrganization(org) { let organization = void 0; if (org) { organization = org.valueOf().replace(";", ", ").replace(/\\,/g, ","); } return organization; } static getVCardFields() { const JSON_VCARD = ["vcard", [["version", {}, "text", "4.0"], ["fn", {}, "text", "name"]]]; const inst = new VCard(vcf.fromJSON(JSON_VCARD)); return inst.getVCardFields(); } getVCardFields() { return Object.getOwnPropertyNames(this).filter((prop) => prop !== "constructor" && typeof this[prop] !== "function" && prop !== "version" && prop !== "fn"); } }; // src/osascriptService.ts var { spawn } = require("child_process"); var OsaScriptService = class { async executeScript(JXA_script) { return new Promise((resolve, reject) => { const osascript = spawn("osascript", ["-l", "JavaScript", "-e", JXA_script]); let output = ""; osascript.stdout.on("data", (data) => { output += data.toString("utf-8"); }); osascript.stderr.on("data", (data) => { const errorMsg = data.toString("utf-8"); reject(new Error(`Error executing JXA script: ${errorMsg}`)); }); osascript.on("close", (code) => { if (code === 0) { resolve(output); } else { reject(new Error(`Error executing JXA script: ${output}`)); } }); }); } }; // src/contactsService.ts var vcf2 = require_vcard(); var ContactsService = class { constructor(groupName, enabledContactFields, osaScriptService = new OsaScriptService()) { this.GROUP_NOT_DEFINED_ERROR = "GROUP NOT DEFINED"; this.groupName = groupName; this.enabledContactFields = enabledContactFields; this.osaScriptService = osaScriptService; } async loadContacts() { let vCards = await this.getVCards(); vCards = vCards.filter((vcard) => { return vcard.fn != void 0; }); const filenameToMarkdown = /* @__PURE__ */ new Map(); for (let vcard of vCards) { filenameToMarkdown.set(vcard.getFilename(), vcard.toMarkdown(this.enabledContactFields)); } return filenameToMarkdown; } async getNumberOfContacts() { const JXA_SCRIPT = ` let Contacts = Application('Contacts'); Contacts.includeStandardAdditions = true; let groups = Contacts.groups.whose({ name: '${this.groupName}'}); if (groups.length === 0 || groups === undefined || groups === null) throw new Error('${this.GROUP_NOT_DEFINED_ERROR}'); groups[0].people.length; `; let resultPromise = this.osaScriptService.executeScript(JXA_SCRIPT).then((resultStr) => { let resultInt = parseInt(resultStr); if (isNaN(resultInt)) { throw new Error(`Non-numeric result from JXA script: ${resultStr}`); } return resultInt; }); return await resultPromise; } async getVCards() { const JXA_SCRIPT = ` ObjC.import('Foundation'); const stdout = $.NSFileHandle.fileHandleWithStandardOutput; let Contacts = Application('Contacts'); Contacts.includeStandardAdditions = true; let groups = Contacts.groups.whose({ name: '${this.groupName}'}); if (groups.length === 0 || groups === undefined || groups === null) throw new Error('${this.GROUP_NOT_DEFINED_ERROR}'); for (let vcard of groups[0].people.vcard()) { // Write to stdout const nsString = $.NSString.alloc.initWithUTF8String(vcard); const data = nsString.dataUsingEncoding($.NSUTF8StringEncoding); stdout.writeData(data); } `; const vCardRegex = /BEGIN:VCARD[\s\S]*?END:VCARD/g; let resultPromise = this.osaScriptService.executeScript(JXA_SCRIPT).then((vCardStr) => { let matches = vCardStr.match(vCardRegex); let vCards = []; for (let match of matches != null ? matches : []) { const card = new vcf2().parse(match); const vCardObj = new VCard(card); vCards.push(vCardObj); } return vCards; }); return await resultPromise; } }; // src/fileService.ts var import_obsidian = require("obsidian"); var ContentSeperator = class { constructor(startTag, startText, stopTag, stopText, commented = true) { this.startTag = startTag; this.startText = startText; this.endTag = stopTag; this.endText = stopText; this.commented = commented; this.commentStart = commented ? "" : ""; } buildContentString(content) { return `${this.commentStart} ${this.startTag} ${this.startText} ${this.commentEnd} ${content} ${this.commentStart} ${this.endTag} ${this.endText} ${this.commentEnd}`; } }; var FileService = class { async createFolder(folderPath, app) { if (await app.vault.adapter.exists((0, import_obsidian.normalizePath)(folderPath)) == false) await app.vault.createFolder(folderPath); } async saveFile(filePath, content, app) { return app.vault.create(filePath, content); } async updateFile(file, updatedContent, seperator, app) { return app.vault.process(file, (oldContent) => { let oldLines = oldContent.split("\n"); let startIndex = oldLines.findIndex((line) => line.contains(seperator.startTag)); let stopIndex = oldLines.findIndex((line) => line.contains(seperator.endTag)); let newLines = Array(); for (let i = Math.min(0, startIndex); i < oldLines.length; i++) { if (i == startIndex) { newLines.push(updatedContent); i = stopIndex; continue; } newLines.push(oldLines[i]); } return newLines.join("\n"); }); } }; // src/main.ts var SettingTab = class extends import_obsidian2.PluginSettingTab { constructor(app, plugin) { super(app, plugin); this.plugin = plugin; } display() { const { containerEl } = this; containerEl.empty(); new import_obsidian2.Setting(containerEl).setName("Contacts folder").setDesc("Select the folder in which your contacts will stored").addText((text) => text.setPlaceholder("Contacts").setValue(this.plugin.settings.contactsFolder).onChange(async (value) => { this.plugin.settings.contactsFolder = value; await this.plugin.saveSettings(); })); new import_obsidian2.Setting(containerEl).setName("Contacts group").setDesc('Enter the name of the group ("Smart List") in which your contacts are stored in the MacOS Contacts app').addText((text) => text.setPlaceholder("Obsidian").setValue(this.plugin.settings.contactsGroup).onChange(async (value) => { this.plugin.settings.contactsGroup = value; await this.plugin.saveSettings(); })); new import_obsidian2.Setting(containerEl).setName("Configure the shown contact fields below").setDesc("To update the shown contact fields, re-sync your contacts"); for (let attribute of VCard.getVCardFields()) { new import_obsidian2.Setting(containerEl).setName(`${attribute}`).addToggle((toggle) => { toggle.setValue(this.plugin.settings.enabledContactFields.includes(attribute)); toggle.onChange(async (value) => { this.plugin.settings.enabledContactFields = this.toggleEnabledField(attribute, value); await this.plugin.saveSettings(); }); }); } } toggleEnabledField(field, value) { let enabledFields = this.plugin.settings.enabledContactFields.split(","); if (value) { enabledFields.push(field); } else { enabledFields = enabledFields.filter((enabledField) => enabledField != field); } return enabledFields.join(","); } }; var DEFAULT_SETTINGS = { contactsGroup: "Obsidian", contactsFolder: "Contacts", autogenerationStartTag: "START", autogenerationStartText: "Content BELOW this line is AUTOGENERATED and will be REPLACED.", autogenerationEndTag: "END", autogenerationEndText: "Content ABOVE this line is AUTOGENERATED and will be REPLACED.", enabledContactFields: "nickname,emails,title,organization,telephones,addresses,birthdate,URLs,notes" }; var ContactsPlugin = class extends import_obsidian2.Plugin { async onload() { await this.loadSettings(); this.addCommand({ id: "sync-contacts", name: "Sync contacts", callback: async () => { if (!import_obsidian2.Platform.isMacOS) return new import_obsidian2.Notice("Error: This plugin only works on MacOS"); new import_obsidian2.Notice("Syncing..."); let loadContactsLogic = new ContactsService(this.settings.contactsGroup, this.settings.enabledContactFields); let numContactsPromise = loadContactsLogic.getNumberOfContacts().then((numContacts2) => { new import_obsidian2.Notice(`Found ${numContacts2} Contacts in group ${this.settings.contactsGroup}`); return numContacts2; }); let fileService = new FileService(); let createFolderPromise = fileService.createFolder(this.settings.contactsFolder, this.app); let contentSeperator = new ContentSeperator( this.settings.autogenerationStartTag, this.settings.autogenerationStartText, this.settings.autogenerationEndTag, this.settings.autogenerationEndText ); let [numContacts, _] = await Promise.all([numContactsPromise, createFolderPromise]); let markdownResults = await loadContactsLogic.loadContacts(); let successfulContacts = 0; let promises = []; for (let [filename, markdown] of markdownResults) { let filePath = (0, import_obsidian2.normalizePath)(`${this.settings.contactsFolder}/${filename}.md`); let file = this.app.vault.getAbstractFileByPath(filePath); let newContactInfo = contentSeperator.buildContentString(markdown); if (file instanceof import_obsidian2.TFolder) { console.error(`Error: ${filePath} is a folder`); new import_obsidian2.Notice(`Error: ${filePath} is a folder`); } else if (file === null) { promises.push( fileService.saveFile(filePath, newContactInfo, this.app).then((_2) => successfulContacts++).catch((error) => console.error(`Error syncing ${filename} ${error}`)) ); } else if (file instanceof import_obsidian2.TFile) { promises.push( // extract the old contact info and replace it with the new data fileService.updateFile(file, newContactInfo, new ContentSeperator(this.settings.autogenerationStartTag, this.settings.autogenerationStartText, this.settings.autogenerationEndTag, this.settings.autogenerationEndText), this.app).then((_2) => successfulContacts++).catch((error) => console.error(`Error syncing ${filename} ${error}`)) ); } } await Promise.all(promises).catch((error) => { new import_obsidian2.Notice("Error syncing contacts!"); console.error(error); }).finally(() => { new import_obsidian2.Notice(`Successfully synced ${successfulContacts} of ${numContacts} Contacts`); console.info(`Successfully synced ${successfulContacts} of ${numContacts} Contacts`); }); } }); this.addSettingTab(new SettingTab(this.app, this)); } async loadSettings() { this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData()); } async saveSettings() { await this.saveData(this.settings); } }; /* nosourcemap */