yanki 2.0.12 → 2.0.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,2 @@
1
+ import e from"node:process";import t from"node:fs";import n from"node:path";import{promisify as r}from"node:util";import i,{execFile as a}from"node:child_process";import{fileURLToPath as o}from"node:url";import s,{constants as c}from"node:fs/promises";import l from"node:os";import{Buffer as u}from"node:buffer";let d;function f(){try{return t.statSync(`/.dockerenv`),!0}catch{return!1}}function ee(){try{return t.readFileSync(`/proc/self/cgroup`,`utf8`).includes(`docker`)}catch{return!1}}function p(){return d===void 0&&(d=f()||ee()),d}let m;const h=()=>{try{return t.statSync(`/run/.containerenv`),!0}catch{return!1}};function g(){return m===void 0&&(m=h()||p()),m}const _=()=>{if(e.platform!==`linux`)return!1;if(l.release().toLowerCase().includes(`microsoft`))return!g();try{if(t.readFileSync(`/proc/version`,`utf8`).toLowerCase().includes(`microsoft`))return!g()}catch{}return t.existsSync(`/proc/sys/fs/binfmt_misc/WSLInterop`)||t.existsSync(`/run/WSL`)?!g():!1};var v=e.env.__IS_WSL_TEST__?_:_();const y=r(i.execFile),b=()=>`${e.env.SYSTEMROOT||e.env.windir||String.raw`C:\Windows`}\\System32\\WindowsPowerShell\\v1.0\\powershell.exe`,x=async(e,t={})=>{let{powerShellPath:n,...r}=t,i=x.encodeCommand(e);return y(n??b(),[...x.argumentsPrefix,i],{encoding:`utf8`,...r})};x.argumentsPrefix=[`-NoProfile`,`-NonInteractive`,`-ExecutionPolicy`,`Bypass`,`-EncodedCommand`],x.encodeCommand=e=>u.from(e,`utf16le`).toString(`base64`),x.escapeArgument=e=>`'${String(e).replaceAll(`'`,`''`)}'`;function S(e){for(let t of e.split(`
2
+ `)){if(/^\s*#/.test(t))continue;let e=/^\s*root\s*=\s*(?<mountPoint>"[^"]*"|'[^']*'|[^#]*)/.exec(t);if(e)return e.groups.mountPoint.trim().replaceAll(/^["']|["']$/g,``)}}const C=r(i.execFile),te=(()=>{let e=`/mnt/`,t;return async function(){if(t)return t;let n=`/etc/wsl.conf`,r=!1;try{await s.access(n,c.F_OK),r=!0}catch{}if(!r)return e;let i=S(await s.readFile(n,{encoding:`utf8`}));return i===void 0?e:(t=i,t=t.endsWith(`/`)?t:`${t}/`,t)}})(),w=v?async()=>`${await te()}c/Windows/System32/WindowsPowerShell/v1.0/powershell.exe`:b;let T;const E=async()=>(T??=(async()=>{try{let e=await w();return await s.access(e,c.X_OK),!0}catch{return!1}})(),T),D=async()=>{let e=await w(),t=String.raw`(Get-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\Shell\Associations\UrlAssociations\http\UserChoice").ProgId`,{stdout:n}=await x(t,{powerShellPath:e});return n.trim()},O=async e=>{if(/^[a-z]+:\/\//i.test(e))return e;try{let{stdout:t}=await C(`wslpath`,[`-aw`,e],{encoding:`utf8`});return t.trim()}catch{return e}};function k(e,t,n){let r=n=>Object.defineProperty(e,t,{value:n,enumerable:!0,writable:!0});return Object.defineProperty(e,t,{configurable:!0,enumerable:!0,get(){let e=n();return r(e),e},set(e){r(e)}}),e}const A=r(a);async function j(){if(e.platform!==`darwin`)throw Error(`macOS only`);let{stdout:t}=await A(`defaults`,[`read`,`com.apple.LaunchServices/com.apple.launchservices.secure`,`LSHandlers`]),n=/LSHandlerRoleAll = "(?!-)(?<id>[^"]+?)";\s+?LSHandlerURLScheme = (?:http|https);/.exec(t)?.groups.id??`com.apple.Safari`;return n===`com.apple.safari`?`com.apple.Safari`:n}const M=r(a);async function N(t,{humanReadableOutput:n=!0,signal:r}={}){if(e.platform!==`darwin`)throw Error(`macOS only`);let i=n?[]:[`-ss`],a={};r&&(a.signal=r);let{stdout:o}=await M(`osascript`,[`-e`,t,i],a);return o.trim()}async function P(e){return N(`tell application "Finder" to set app_path to application file id "${e}" as string\ntell application "System Events" to get value of property list item "CFBundleName" of property list file (app_path & ":Contents:Info.plist")`)}const F=r(a),I={MSEdgeHTM:{name:`Edge`,id:`com.microsoft.edge`},MSEdgeBHTML:{name:`Edge Beta`,id:`com.microsoft.edge.beta`},MSEdgeDHTML:{name:`Edge Dev`,id:`com.microsoft.edge.dev`},AppXq0fevzme2pys62n3e0fbqa7peapykr8v:{name:`Edge`,id:`com.microsoft.edge.old`},ChromeHTML:{name:`Chrome`,id:`com.google.chrome`},ChromeBHTML:{name:`Chrome Beta`,id:`com.google.chrome.beta`},ChromeDHTML:{name:`Chrome Dev`,id:`com.google.chrome.dev`},ChromiumHTM:{name:`Chromium`,id:`org.chromium.Chromium`},BraveHTML:{name:`Brave`,id:`com.brave.Browser`},BraveBHTML:{name:`Brave Beta`,id:`com.brave.Browser.beta`},BraveDHTML:{name:`Brave Dev`,id:`com.brave.Browser.dev`},BraveSSHTM:{name:`Brave Nightly`,id:`com.brave.Browser.nightly`},FirefoxURL:{name:`Firefox`,id:`org.mozilla.firefox`},OperaStable:{name:`Opera`,id:`com.operasoftware.Opera`},VivaldiHTM:{name:`Vivaldi`,id:`com.vivaldi.Vivaldi`},"IE.HTTP":{name:`Internet Explorer`,id:`com.microsoft.ie`}},L=new Map(Object.entries(I));var R=class extends Error{};async function z(e=F){let{stdout:t}=await e(`reg`,[`QUERY`,` HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\Shell\\Associations\\UrlAssociations\\http\\UserChoice`,`/v`,`ProgId`]),n=/ProgId\s*REG_SZ\s*(?<id>\S+)/.exec(t);if(!n)throw new R(`Cannot find Windows browser in stdout: ${JSON.stringify(t)}`);let{id:r}=n.groups,i=r.lastIndexOf(`.`),a=r.lastIndexOf(`-`),o=i===-1?void 0:r.slice(0,i),s=a===-1?void 0:r.slice(0,a);return I[r]??I[o]??I[s]??{name:r,id:r}}const B=r(a),V=e=>e.toLowerCase().replaceAll(/(?:^|\s|-)\S/g,e=>e.toUpperCase());async function H(){if(e.platform===`darwin`){let e=await j();return{name:await P(e),id:e}}if(e.platform===`linux`){let{stdout:e}=await B(`xdg-mime`,[`query`,`default`,`x-scheme-handler/http`]),t=e.trim();return{name:V(t.replace(/.desktop$/,``).replace(`-`,` `)),id:t}}if(e.platform===`win32`)return z();throw Error(`Only macOS, Linux, and Windows are supported`)}const U=!!(e.env.SSH_CONNECTION||e.env.SSH_CLIENT||e.env.SSH_TTY),W=Symbol(`fallbackAttempt`),G=import.meta.url?n.dirname(o(import.meta.url)):``,K=n.join(G,`xdg-open`),{platform:q,arch:J}=e,Y=async(e,t)=>{if(e.length===0)return;let n=[];for(let r of e)try{return await t(r)}catch(e){n.push(e)}throw AggregateError(n,`Failed to open in all supported apps`)},X=async t=>{t={wait:!1,background:!1,newInstance:!1,allowNonzeroExitCode:!1,...t};let n=t[W]===!0;if(delete t[W],Array.isArray(t.app))return Y(t.app,e=>X({...t,app:e,[W]:!0}));let{name:r,arguments:a=[]}=t.app??{};if(a=[...a],Array.isArray(r))return Y(r,e=>X({...t,app:{name:e,arguments:a},[W]:!0}));if(r===`browser`||r===`browserPrivate`){let e={"com.google.chrome":`chrome`,"google-chrome.desktop":`chrome`,"com.brave.browser":`brave`,"org.mozilla.firefox":`firefox`,"firefox.desktop":`firefox`,"com.microsoft.msedge":`edge`,"com.microsoft.edge":`edge`,"com.microsoft.edgemac":`edge`,"microsoft-edge.desktop":`edge`,"com.apple.safari":`safari`},n={chrome:`--incognito`,brave:`--incognito`,firefox:`--private-window`,edge:`--inPrivate`},i;if(v){let e=await D();i=L.get(e)??{}}else i=await H();if(i.id in e){let o=e[i.id.toLowerCase()];if(r===`browserPrivate`){if(o===`safari`)throw Error(`Safari doesn't support opening in private mode via command line`);a.push(n[o])}return X({...t,app:{name:$[o],arguments:a}})}throw Error(`${i.name} is not supported as a default browser`)}let o,l=[],u={},d=!1;if(v&&!g()&&!U&&!r&&(d=await E()),q===`darwin`)o=`open`,t.wait&&l.push(`--wait-apps`),t.background&&l.push(`--background`),t.newInstance&&l.push(`--new`),r&&l.push(`-a`,r);else if(q===`win32`||d){o=await w(),l.push(...x.argumentsPrefix),v||(u.windowsVerbatimArguments=!0),v&&t.target&&(t.target=await O(t.target));let e=[`$ProgressPreference = 'SilentlyContinue';`,`Start`];t.wait&&e.push(`-Wait`),r?(e.push(x.escapeArgument(r)),t.target&&a.push(t.target)):t.target&&e.push(x.escapeArgument(t.target)),a.length>0&&(a=a.map(e=>x.escapeArgument(e)),e.push(`-ArgumentList`,a.join(`,`))),t.target=x.encodeCommand(e.join(` `)),t.wait||(u.stdio=`ignore`)}else{if(r)o=r;else{let t=!G||G===`/`,n=!1;try{await s.access(K,c.X_OK),n=!0}catch{}o=e.versions.electron??(q===`android`||t||!n)?`xdg-open`:K}a.length>0&&l.push(...a),t.wait||(u.stdio=`ignore`,u.detached=!0)}q===`darwin`&&a.length>0&&l.push(`--args`,...a),t.target&&l.push(t.target);let f=i.spawn(o,l,u);return t.wait?new Promise((e,n)=>{f.once(`error`,n),f.once(`close`,r=>{if(!t.allowNonzeroExitCode&&r!==0){n(Error(`Exited with code ${r}`));return}e(f)})}):n?new Promise((e,t)=>{f.once(`error`,t),f.once(`spawn`,()=>{f.once(`close`,n=>{if(f.off(`error`,t),n!==0){t(Error(`Exited with code ${n}`));return}f.unref(),e(f)})})}):(f.unref(),new Promise((e,t)=>{f.once(`error`,t),f.once(`spawn`,()=>{f.off(`error`,t),e(f)})}))},ne=(e,t)=>{if(typeof e!=`string`&&!Array.isArray(e))throw TypeError("Expected a valid `name`");let{arguments:n=[]}=t??{};if(n!=null&&!Array.isArray(n))throw TypeError("Expected `appArguments` as Array type");return X({...t,app:{name:e,arguments:n}})};function Z(e){if(typeof e==`string`||Array.isArray(e))return e;let{[J]:t}=e;if(!t)throw Error(`${J} is not supported`);return t}function Q({[q]:e},{wsl:t}={}){if(t&&v)return Z(t);if(!e)throw Error(`${q} is not supported`);return Z(e)}const $={browser:`browser`,browserPrivate:`browserPrivate`};k($,`chrome`,()=>Q({darwin:`google chrome`,win32:`chrome`,linux:[`google-chrome`,`google-chrome-stable`,`chromium`,`chromium-browser`]},{wsl:{ia32:`/mnt/c/Program Files (x86)/Google/Chrome/Application/chrome.exe`,x64:[`/mnt/c/Program Files/Google/Chrome/Application/chrome.exe`,`/mnt/c/Program Files (x86)/Google/Chrome/Application/chrome.exe`]}})),k($,`brave`,()=>Q({darwin:`brave browser`,win32:`brave`,linux:[`brave-browser`,`brave`]},{wsl:{ia32:`/mnt/c/Program Files (x86)/BraveSoftware/Brave-Browser/Application/brave.exe`,x64:[`/mnt/c/Program Files/BraveSoftware/Brave-Browser/Application/brave.exe`,`/mnt/c/Program Files (x86)/BraveSoftware/Brave-Browser/Application/brave.exe`]}})),k($,`firefox`,()=>Q({darwin:`firefox`,win32:String.raw`C:\Program Files\Mozilla Firefox\firefox.exe`,linux:`firefox`},{wsl:`/mnt/c/Program Files/Mozilla Firefox/firefox.exe`})),k($,`edge`,()=>Q({darwin:`microsoft edge`,win32:`msedge`,linux:[`microsoft-edge`,`microsoft-edge-dev`]},{wsl:`/mnt/c/Program Files (x86)/Microsoft/Edge/Application/msedge.exe`})),k($,`safari`,()=>Q({darwin:`Safari`}));export{ne as openApp};
package/dist/lib/index.js CHANGED
@@ -91,7 +91,7 @@ function truncateOnWordBoundary(text, maxLength, truncationString = "...", wordB
91
91
  return `${words.join(wordBoundary).slice(0, maxLengthSafe)}${truncationString}`;
92
92
  }
93
93
  function cleanClassName(className) {
94
- return className.toLowerCase().replaceAll(/* @__PURE__ */ new RegExp("[^\\dA-Za-z]", "gv"), " ").trim().replaceAll(/* @__PURE__ */ new RegExp(" +", "gv"), "-");
94
+ return className.toLowerCase().replaceAll(new RegExp("[^\\dA-Za-z]", "gv"), " ").trim().replaceAll(new RegExp(" +", "gv"), "-");
95
95
  }
96
96
  function emptyIsUndefined(text) {
97
97
  if (text === void 0) return;
@@ -106,8 +106,8 @@ function emptyIsUndefined(text) {
106
106
  function css$1(strings, ...values) {
107
107
  return trimLeadingIndentation(strings, ...values);
108
108
  }
109
- const NEWLINE_REGEX$1 = /* @__PURE__ */ new RegExp("\\r?\\n", "v");
110
- const LEADING_WHITESPACE_REGEX = /* @__PURE__ */ new RegExp("^(\\s+)", "v");
109
+ const NEWLINE_REGEX$1 = new RegExp("\\r?\\n", "v");
110
+ const LEADING_WHITESPACE_REGEX = new RegExp("^(\\s+)", "v");
111
111
  function trimLeadingIndentation(strings, ...values) {
112
112
  const lines = strings.reduce((result, text, i) => `${result}${text}${String(values[i] ?? "")}`, "").split(NEWLINE_REGEX$1).filter((line) => line.trim() !== "");
113
113
  const leadingSpace = LEADING_WHITESPACE_REGEX.exec(lines[0] ?? "")?.[0] ?? "";
@@ -235,8 +235,7 @@ const MEDIA_SUPPORTED_AUDIO_VIDEO_EXTENSIONS = [
235
235
  ];
236
236
  /**
237
237
  * Anki seems happy to open PDF files and download markdown files that have been
238
- * added to the assets folder...
239
- * https://help.obsidian.md/Files+and+folders/Accepted+file+formats
238
+ * added to the assets folder... https://obsidian.md/help/file-formats
240
239
  */
241
240
  const MEDIA_SUPPORTED_FILE_EXTENSIONS = ["md", "pdf"];
242
241
  const MEDIA_SUPPORTED_EXTENSIONS = [
@@ -247,7 +246,7 @@ const MEDIA_SUPPORTED_EXTENSIONS = [
247
246
  //#endregion
248
247
  //#region src/lib/utilities/platform.ts
249
248
  const ENVIRONMENT = typeof window === "undefined" ? typeof process === "undefined" ? "other" : "node" : "browser";
250
- ENVIRONMENT === "browser" ? (/* @__PURE__ */ new RegExp("windows", "iv")).test(navigator.userAgent) || (/* @__PURE__ */ new RegExp("mac", "iv")).test(navigator.userAgent) || (/* @__PURE__ */ new RegExp("linux", "iv")).test(navigator.userAgent) || (/* @__PURE__ */ new RegExp("ubuntu", "iv")).test(navigator.userAgent) : ENVIRONMENT === "node" && (process.platform === "win32" || process.platform === "darwin" || process.platform);
249
+ ENVIRONMENT === "browser" ? new RegExp("windows", "iv").test(navigator.userAgent) || new RegExp("mac", "iv").test(navigator.userAgent) || new RegExp("linux", "iv").test(navigator.userAgent) || new RegExp("ubuntu", "iv").test(navigator.userAgent) : ENVIRONMENT === "node" && (process.platform === "win32" || process.platform === "darwin" || process.platform);
251
250
  //#endregion
252
251
  //#region src/lib/shared/types.ts
253
252
  const defaultGlobalOptions = {
@@ -308,7 +307,10 @@ async function fileExists(absoluteFilePath, fileAdapter) {
308
307
  }
309
308
  async function getFileContentHash(absoluteFilePath, fileAdapter, mode = MEDIA_DEFAULT_HASH_MODE_FILE) {
310
309
  switch (mode) {
311
- case "content": return (await sha256(await fileAdapter.readFileBuffer(absoluteFilePath))).slice(0, 16);
310
+ case "content": {
311
+ const fileContent = await fileAdapter.readFileBuffer(absoluteFilePath);
312
+ return (await sha256(fileContent)).slice(0, 16);
313
+ }
312
314
  case "metadata": {
313
315
  const { mtimeMs, size } = await fileAdapter.stat(absoluteFilePath);
314
316
  const stringToHash = `${mtimeMs ?? ""}${size ?? ""}`;
@@ -320,88 +322,88 @@ async function getFileContentHash(absoluteFilePath, fileAdapter, mode = MEDIA_DE
320
322
  }
321
323
  //#endregion
322
324
  //#region src/lib/utilities/namespace.ts
323
- const CONSECUTIVE_HYPHENS_REGEX = /* @__PURE__ */ new RegExp("-+", "gv");
324
- const ASTERISK_REGEX = /* @__PURE__ */ new RegExp("\\*", "v");
325
+ const CONSECUTIVE_HYPHENS_REGEX = new RegExp("-+", "gv");
326
+ const ASTERISK_REGEX = new RegExp("\\*", "v");
325
327
  const FORBIDDEN_CHARACTERS = [
326
- [/* @__PURE__ */ new RegExp(":", "v"), "Colon"],
327
- [/* @__PURE__ */ new RegExp("\\u{0000}", "v"), "Null"],
328
- [/* @__PURE__ */ new RegExp("\\u{0001}", "v"), "Start of Heading"],
329
- [/* @__PURE__ */ new RegExp("\\u{0002}", "v"), "Start of Text"],
330
- [/* @__PURE__ */ new RegExp("\\u{0003}", "v"), "End of Text"],
331
- [/* @__PURE__ */ new RegExp("\\u{0004}", "v"), "End of Transmission"],
332
- [/* @__PURE__ */ new RegExp("\\u{0005}", "v"), "Enquiry"],
333
- [/* @__PURE__ */ new RegExp("\\u{0006}", "v"), "Acknowledge"],
334
- [/* @__PURE__ */ new RegExp("\\u{0007}", "v"), "Bell"],
335
- [/* @__PURE__ */ new RegExp("\\u{0008}", "v"), "Backspace"],
336
- [/* @__PURE__ */ new RegExp("\\u{0009}", "v"), "Horizontal Tab"],
337
- [/* @__PURE__ */ new RegExp("\\u{000A}", "v"), "Line Feed"],
338
- [/* @__PURE__ */ new RegExp("\\u{000B}", "v"), "Vertical Tab"],
339
- [/* @__PURE__ */ new RegExp("\\u{000C}", "v"), "Form Feed"],
340
- [/* @__PURE__ */ new RegExp("\\u{000D}", "v"), "Carriage Return"],
341
- [/* @__PURE__ */ new RegExp("\\u{000E}", "v"), "Shift Out"],
342
- [/* @__PURE__ */ new RegExp("\\u{000F}", "v"), "Shift In"],
343
- [/* @__PURE__ */ new RegExp("\\u{0010}", "v"), "Data Link Escape"],
344
- [/* @__PURE__ */ new RegExp("\\u{0011}", "v"), "Device Control 1"],
345
- [/* @__PURE__ */ new RegExp("\\u{0012}", "v"), "Device Control 2"],
346
- [/* @__PURE__ */ new RegExp("\\u{0013}", "v"), "Device Control 3"],
347
- [/* @__PURE__ */ new RegExp("\\u{0014}", "v"), "Device Control 4"],
348
- [/* @__PURE__ */ new RegExp("\\u{0015}", "v"), "Negative Acknowledge"],
349
- [/* @__PURE__ */ new RegExp("\\u{0016}", "v"), "Synchronous Idle"],
350
- [/* @__PURE__ */ new RegExp("\\u{0017}", "v"), "End of Transmission Block"],
351
- [/* @__PURE__ */ new RegExp("\\u{0018}", "v"), "Cancel"],
352
- [/* @__PURE__ */ new RegExp("\\u{0019}", "v"), "End of Medium"],
353
- [/* @__PURE__ */ new RegExp("\\u{001A}", "v"), "Substitute"],
354
- [/* @__PURE__ */ new RegExp("\\u{001B}", "v"), "Escape"],
355
- [/* @__PURE__ */ new RegExp("\\u{001C}", "v"), "File Separator"],
356
- [/* @__PURE__ */ new RegExp("\\u{001D}", "v"), "Group Separator"],
357
- [/* @__PURE__ */ new RegExp("\\u{001E}", "v"), "Record Separator"],
358
- [/* @__PURE__ */ new RegExp("\\u{001F}", "v"), "Unit Separator"],
359
- [/* @__PURE__ */ new RegExp("\\u{007F}", "v"), "Delete"],
360
- [/* @__PURE__ */ new RegExp("\\u{0080}", "v"), "Padding Character"],
361
- [/* @__PURE__ */ new RegExp("\\u{0081}", "v"), "High Octet Preset"],
362
- [/* @__PURE__ */ new RegExp("\\u{0082}", "v"), "Break Permitted Here"],
363
- [/* @__PURE__ */ new RegExp("\\u{0083}", "v"), "No Break Here"],
364
- [/* @__PURE__ */ new RegExp("\\u{0084}", "v"), "Index"],
365
- [/* @__PURE__ */ new RegExp("\\u{0085}", "v"), "Next Line"],
366
- [/* @__PURE__ */ new RegExp("\\u{0086}", "v"), "Start of Selected Area"],
367
- [/* @__PURE__ */ new RegExp("\\u{0087}", "v"), "End of Selected Area"],
368
- [/* @__PURE__ */ new RegExp("\\u{0088}", "v"), "Character Tabulation Set"],
369
- [/* @__PURE__ */ new RegExp("\\u{0089}", "v"), "Character Tabulation with Justification"],
370
- [/* @__PURE__ */ new RegExp("\\u{008A}", "v"), "Line Tabulation Set"],
371
- [/* @__PURE__ */ new RegExp("\\u{008B}", "v"), "Partial Line Forward"],
372
- [/* @__PURE__ */ new RegExp("\\u{008C}", "v"), "Partial Line Backward"],
373
- [/* @__PURE__ */ new RegExp("\\u{008D}", "v"), "Reverse Line Feed"],
374
- [/* @__PURE__ */ new RegExp("\\u{008E}", "v"), "Single Shift Two"],
375
- [/* @__PURE__ */ new RegExp("\\u{008F}", "v"), "Single Shift Three"],
376
- [/* @__PURE__ */ new RegExp("\\u{0090}", "v"), "Device Control String"],
377
- [/* @__PURE__ */ new RegExp("\\u{0091}", "v"), "Private Use One"],
378
- [/* @__PURE__ */ new RegExp("\\u{0092}", "v"), "Private Use Two"],
379
- [/* @__PURE__ */ new RegExp("\\u{0093}", "v"), "Set Transmit State"],
380
- [/* @__PURE__ */ new RegExp("\\u{0094}", "v"), "Cancel Character"],
381
- [/* @__PURE__ */ new RegExp("\\u{0095}", "v"), "Message Waiting"],
382
- [/* @__PURE__ */ new RegExp("\\u{0096}", "v"), "Start of Protected Area"],
383
- [/* @__PURE__ */ new RegExp("\\u{0097}", "v"), "End of Protected Area"],
384
- [/* @__PURE__ */ new RegExp("\\u{0098}", "v"), "Start of String"],
385
- [/* @__PURE__ */ new RegExp("\\u{0099}", "v"), "Single Graphic Character Introducer"],
386
- [/* @__PURE__ */ new RegExp("\\u{009A}", "v"), "Single Character Introducer"],
387
- [/* @__PURE__ */ new RegExp("\\u{009B}", "v"), "Control Sequence Introducer"],
388
- [/* @__PURE__ */ new RegExp("\\u{009C}", "v"), "String Terminator"],
389
- [/* @__PURE__ */ new RegExp("\\u{009D}", "v"), "Operating System Command"],
390
- [/* @__PURE__ */ new RegExp("\\u{009E}", "v"), "Privacy Message"],
391
- [/* @__PURE__ */ new RegExp("\\u{009F}", "v"), "Application Program Command"],
392
- [/* @__PURE__ */ new RegExp("\\u{00A0}", "v"), "Non-breaking Space"],
393
- [/* @__PURE__ */ new RegExp("\\u{00AD}", "v"), "Soft Hyphen"],
394
- [/* @__PURE__ */ new RegExp("\\u{200B}", "v"), "Zero-width Space"],
395
- [/* @__PURE__ */ new RegExp("\\u{200C}", "v"), "Zero-width Non-joiner"],
396
- [/* @__PURE__ */ new RegExp("\\u{200D}", "v"), "Zero-width Joiner"],
397
- [/* @__PURE__ */ new RegExp("\\u{200E}", "v"), "Left-to-right Mark"],
398
- [/* @__PURE__ */ new RegExp("\\u{200F}", "v"), "Right-to-left Mark"],
399
- [/* @__PURE__ */ new RegExp("\\u{202A}", "v"), "Left-to-right Embedding"],
400
- [/* @__PURE__ */ new RegExp("\\u{202B}", "v"), "Right-to-left Embedding"],
401
- [/* @__PURE__ */ new RegExp("\\u{202C}", "v"), "Pop Directional Formatting"],
402
- [/* @__PURE__ */ new RegExp("\\u{202D}", "v"), "Left-to-right Override"],
403
- [/* @__PURE__ */ new RegExp("\\u{202E}", "v"), "Right-to-left Override"],
404
- [/* @__PURE__ */ new RegExp("\\u{FEFF}", "v"), "Byte Order Mark (BOM)"]
328
+ [new RegExp(":", "v"), "Colon"],
329
+ [new RegExp("\\u{0000}", "v"), "Null"],
330
+ [new RegExp("\\u{0001}", "v"), "Start of Heading"],
331
+ [new RegExp("\\u{0002}", "v"), "Start of Text"],
332
+ [new RegExp("\\u{0003}", "v"), "End of Text"],
333
+ [new RegExp("\\u{0004}", "v"), "End of Transmission"],
334
+ [new RegExp("\\u{0005}", "v"), "Enquiry"],
335
+ [new RegExp("\\u{0006}", "v"), "Acknowledge"],
336
+ [new RegExp("\\u{0007}", "v"), "Bell"],
337
+ [new RegExp("\\u{0008}", "v"), "Backspace"],
338
+ [new RegExp("\\u{0009}", "v"), "Horizontal Tab"],
339
+ [new RegExp("\\u{000A}", "v"), "Line Feed"],
340
+ [new RegExp("\\u{000B}", "v"), "Vertical Tab"],
341
+ [new RegExp("\\u{000C}", "v"), "Form Feed"],
342
+ [new RegExp("\\u{000D}", "v"), "Carriage Return"],
343
+ [new RegExp("\\u{000E}", "v"), "Shift Out"],
344
+ [new RegExp("\\u{000F}", "v"), "Shift In"],
345
+ [new RegExp("\\u{0010}", "v"), "Data Link Escape"],
346
+ [new RegExp("\\u{0011}", "v"), "Device Control 1"],
347
+ [new RegExp("\\u{0012}", "v"), "Device Control 2"],
348
+ [new RegExp("\\u{0013}", "v"), "Device Control 3"],
349
+ [new RegExp("\\u{0014}", "v"), "Device Control 4"],
350
+ [new RegExp("\\u{0015}", "v"), "Negative Acknowledge"],
351
+ [new RegExp("\\u{0016}", "v"), "Synchronous Idle"],
352
+ [new RegExp("\\u{0017}", "v"), "End of Transmission Block"],
353
+ [new RegExp("\\u{0018}", "v"), "Cancel"],
354
+ [new RegExp("\\u{0019}", "v"), "End of Medium"],
355
+ [new RegExp("\\u{001A}", "v"), "Substitute"],
356
+ [new RegExp("\\u{001B}", "v"), "Escape"],
357
+ [new RegExp("\\u{001C}", "v"), "File Separator"],
358
+ [new RegExp("\\u{001D}", "v"), "Group Separator"],
359
+ [new RegExp("\\u{001E}", "v"), "Record Separator"],
360
+ [new RegExp("\\u{001F}", "v"), "Unit Separator"],
361
+ [new RegExp("\\u{007F}", "v"), "Delete"],
362
+ [new RegExp("\\u{0080}", "v"), "Padding Character"],
363
+ [new RegExp("\\u{0081}", "v"), "High Octet Preset"],
364
+ [new RegExp("\\u{0082}", "v"), "Break Permitted Here"],
365
+ [new RegExp("\\u{0083}", "v"), "No Break Here"],
366
+ [new RegExp("\\u{0084}", "v"), "Index"],
367
+ [new RegExp("\\u{0085}", "v"), "Next Line"],
368
+ [new RegExp("\\u{0086}", "v"), "Start of Selected Area"],
369
+ [new RegExp("\\u{0087}", "v"), "End of Selected Area"],
370
+ [new RegExp("\\u{0088}", "v"), "Character Tabulation Set"],
371
+ [new RegExp("\\u{0089}", "v"), "Character Tabulation with Justification"],
372
+ [new RegExp("\\u{008A}", "v"), "Line Tabulation Set"],
373
+ [new RegExp("\\u{008B}", "v"), "Partial Line Forward"],
374
+ [new RegExp("\\u{008C}", "v"), "Partial Line Backward"],
375
+ [new RegExp("\\u{008D}", "v"), "Reverse Line Feed"],
376
+ [new RegExp("\\u{008E}", "v"), "Single Shift Two"],
377
+ [new RegExp("\\u{008F}", "v"), "Single Shift Three"],
378
+ [new RegExp("\\u{0090}", "v"), "Device Control String"],
379
+ [new RegExp("\\u{0091}", "v"), "Private Use One"],
380
+ [new RegExp("\\u{0092}", "v"), "Private Use Two"],
381
+ [new RegExp("\\u{0093}", "v"), "Set Transmit State"],
382
+ [new RegExp("\\u{0094}", "v"), "Cancel Character"],
383
+ [new RegExp("\\u{0095}", "v"), "Message Waiting"],
384
+ [new RegExp("\\u{0096}", "v"), "Start of Protected Area"],
385
+ [new RegExp("\\u{0097}", "v"), "End of Protected Area"],
386
+ [new RegExp("\\u{0098}", "v"), "Start of String"],
387
+ [new RegExp("\\u{0099}", "v"), "Single Graphic Character Introducer"],
388
+ [new RegExp("\\u{009A}", "v"), "Single Character Introducer"],
389
+ [new RegExp("\\u{009B}", "v"), "Control Sequence Introducer"],
390
+ [new RegExp("\\u{009C}", "v"), "String Terminator"],
391
+ [new RegExp("\\u{009D}", "v"), "Operating System Command"],
392
+ [new RegExp("\\u{009E}", "v"), "Privacy Message"],
393
+ [new RegExp("\\u{009F}", "v"), "Application Program Command"],
394
+ [new RegExp("\\u{00A0}", "v"), "Non-breaking Space"],
395
+ [new RegExp("\\u{00AD}", "v"), "Soft Hyphen"],
396
+ [new RegExp("\\u{200B}", "v"), "Zero-width Space"],
397
+ [new RegExp("\\u{200C}", "v"), "Zero-width Non-joiner"],
398
+ [new RegExp("\\u{200D}", "v"), "Zero-width Joiner"],
399
+ [new RegExp("\\u{200E}", "v"), "Left-to-right Mark"],
400
+ [new RegExp("\\u{200F}", "v"), "Right-to-left Mark"],
401
+ [new RegExp("\\u{202A}", "v"), "Left-to-right Embedding"],
402
+ [new RegExp("\\u{202B}", "v"), "Right-to-left Embedding"],
403
+ [new RegExp("\\u{202C}", "v"), "Pop Directional Formatting"],
404
+ [new RegExp("\\u{202D}", "v"), "Left-to-right Override"],
405
+ [new RegExp("\\u{202E}", "v"), "Right-to-left Override"],
406
+ [new RegExp("\\u{FEFF}", "v"), "Byte Order Mark (BOM)"]
405
407
  ];
406
408
  /**
407
409
  * Convenience
@@ -508,8 +510,8 @@ function getFileExtensionForMimeType(mimeType) {
508
510
  }
509
511
  //#endregion
510
512
  //#region src/lib/utilities/path.ts
511
- const WINDOWS_DRIVE_LETTER_REGEX = /* @__PURE__ */ new RegExp("^[A-Z]:", "iv");
512
- const QUERY_FRAGMENT_START_REGEX = /* @__PURE__ */ new RegExp("[#^]", "v");
513
+ const WINDOWS_DRIVE_LETTER_REGEX = new RegExp("^[A-Z]:", "iv");
514
+ const QUERY_FRAGMENT_START_REGEX = new RegExp("[#^]", "v");
513
515
  /**
514
516
  * The browserify polyfill doesn't implement win32 absolute path detection...
515
517
  *
@@ -520,7 +522,7 @@ const QUERY_FRAGMENT_START_REGEX = /* @__PURE__ */ new RegExp("[#^]", "v");
520
522
  function isAbsolute(filePath) {
521
523
  return isAbsolutePath.posix(filePath) || isAbsolutePath.win32(filePath);
522
524
  }
523
- const RE_WINDOWS_EXTENDED_LENGTH_PATH = /* @__PURE__ */ new RegExp("^\\\\\\\\\\?\\\\.+", "v");
525
+ const RE_WINDOWS_EXTENDED_LENGTH_PATH = new RegExp("^\\\\\\\\\\?\\\\.+", "v");
524
526
  /**
525
527
  * Converts all paths to cross-platform 'mixed' style with forward slashes.
526
528
  * Warns on unsupported Windows extended length paths.
@@ -576,27 +578,26 @@ function getBaseAndQueryParts(filePath) {
576
578
  return [path.join(directoryPath, base), query];
577
579
  }
578
580
  /**
579
- * Get every plausible base and anchor interpretation of a file path whose name
580
- * may contain anchor delimiter characters (`#`, `^`), ordered from the longest
581
- * literal file name (no anchor at all) to the shortest (anchor starts at the
582
- * first delimiter in the file name, matching Obsidian's anchor syntax).
583
- * Delimiters in directory names are never treated as anchor starts.
584
- *
585
- * File names may legitimately contain these characters, so callers should try
586
- * candidates in order against a list of real files instead of assuming the
587
- * first delimiter starts an anchor.
581
+ * Get every plausible base and anchor interpretation of a local link target
582
+ * that may contain anchor delimiter characters (`#`, `^`), ordered from the
583
+ * longest literal path (no anchor at all) to the shortest (anchor starts at the
584
+ * first delimiter, matching Obsidian's anchor syntax).
585
+ *
586
+ * This operates on the unnormalized link target and deliberately considers
587
+ * delimiters before slashes. A slash after a delimiter belongs to the anchor,
588
+ * not the file path. File and directory names may also legitimately contain
589
+ * these characters, so callers must normalize only each candidate's `filePath`
590
+ * and try candidates in order against a list of real files.
588
591
  * https://github.com/kitschpatrol/yanki/issues/20
589
592
  */
590
- function getBaseAndQueryCandidates(filePath) {
591
- const directoryPath = path.dirname(filePath);
592
- const fileName = path.basename(filePath);
593
+ function getLocalPathCandidates(linkTarget) {
593
594
  const candidates = [{
594
- base: path.join(directoryPath, fileName),
595
- query: void 0
595
+ anchor: void 0,
596
+ filePath: linkTarget
596
597
  }];
597
- for (let index = fileName.length - 1; index >= 0; index--) if (QUERY_FRAGMENT_START_REGEX.test(fileName.charAt(index))) candidates.push({
598
- base: path.join(directoryPath, fileName.slice(0, index)),
599
- query: fileName.slice(index)
598
+ for (let index = linkTarget.length - 1; index >= 0; index--) if (QUERY_FRAGMENT_START_REGEX.test(linkTarget.charAt(index))) candidates.push({
599
+ anchor: linkTarget.slice(index),
600
+ filePath: linkTarget.slice(0, index)
600
601
  });
601
602
  return candidates;
602
603
  }
@@ -608,8 +609,8 @@ function getQuery(filePath) {
608
609
  }
609
610
  //#endregion
610
611
  //#region src/lib/utilities/url.ts
611
- const DRIVE_LETTER_REGEX = /* @__PURE__ */ new RegExp("^[a-z]:", "iv");
612
- const FILE_PREFIX_REGEX = /* @__PURE__ */ new RegExp("^file:", "iv");
612
+ const DRIVE_LETTER_REGEX = new RegExp("^[a-z]:", "iv");
613
+ const FILE_PREFIX_REGEX = new RegExp("^file:", "iv");
613
614
  function safeDecodeURI(text) {
614
615
  try {
615
616
  return decodeURI(text);
@@ -789,7 +790,7 @@ async function getContentHash(absolutePathOrUrl, fileAdapter, fetchAdapter) {
789
790
  }
790
791
  //#endregion
791
792
  //#region src/lib/parse/rehype-mathjax-anki.ts
792
- const CONSECUTIVE_BRACES_REGEX = /* @__PURE__ */ new RegExp("([\\{\\}])(?=[\\{\\}])", "gv");
793
+ const CONSECUTIVE_BRACES_REGEX = new RegExp("([\\{\\}])(?=[\\{\\}])", "gv");
793
794
  function sanitizeBraces(value) {
794
795
  return value.replaceAll(CONSECUTIVE_BRACES_REGEX, "$1 ");
795
796
  }
@@ -843,7 +844,7 @@ const plugin$2 = function() {
843
844
  };
844
845
  //#endregion
845
846
  //#region src/lib/parse/rehype-utilities.ts
846
- const DIMENSION_CHARS_REGEX = /* @__PURE__ */ new RegExp("^[\\dx]+$", "v");
847
+ const DIMENSION_CHARS_REGEX = new RegExp("^[\\dx]+$", "v");
847
848
  const highlighter = createHighlighterCoreSync({
848
849
  engine: createJavaScriptRegexEngine(),
849
850
  langs: [
@@ -919,9 +920,7 @@ async function mdastToHtml(mdast, options) {
919
920
  case "localFileUrl":
920
921
  absolutePathOrUrl = node.properties.src;
921
922
  break;
922
- case "remoteHttpUrl":
923
- absolutePathOrUrl = node.properties.src;
924
- break;
923
+ case "remoteHttpUrl": absolutePathOrUrl = node.properties.src;
925
924
  }
926
925
  treeMutationPromises.push(async () => {
927
926
  const extension = await getAnkiMediaFilenameExtension(absolutePathOrUrl, srcType === "obsidianVaultUrl" ? void 0 : fetchAdapter);
@@ -1691,8 +1690,8 @@ function formatListResult(result) {
1691
1690
  }
1692
1691
  //#endregion
1693
1692
  //#region src/lib/utilities/filenames.ts
1694
- const CLOZE_CONTENT_REGEX = /* @__PURE__ */ new RegExp("\\{\\{\\w\\d*\\s?:{0,2}([^:\\}]+)", "v");
1695
- const FILENAME_INCREMENT_SUFFIX_REGEX = /* @__PURE__ */ new RegExp("\\s\\(\\d+\\)$", "v");
1693
+ const CLOZE_CONTENT_REGEX = new RegExp("\\{\\{\\w\\d*\\s?:{0,2}([^:\\}]+)", "v");
1694
+ const FILENAME_INCREMENT_SUFFIX_REGEX = new RegExp("\\s\\(\\d+\\)$", "v");
1696
1695
  function getSafeTitleForNote(note, manageFilenames, maxLength) {
1697
1696
  if (manageFilenames === "off") throw new Error("manageFilenames must not be off");
1698
1697
  switch (note.modelName) {
@@ -1731,7 +1730,7 @@ function getSafeFilename(text, maxLength) {
1731
1730
  let basicSafeFilename = filenamify(getFirstLineOfHtmlAsPlainText(text).trim(), {
1732
1731
  maxLength: Number.MAX_SAFE_INTEGER,
1733
1732
  replacement: " "
1734
- }).replaceAll(/* @__PURE__ */ new RegExp("\\s+", "gv"), " ").trim();
1733
+ }).replaceAll(new RegExp("\\s+", "gv"), " ").trim();
1735
1734
  if (basicSafeFilename.length === 0) basicSafeFilename = MEDIA_DEFAULT_EMPTY_FILENAME;
1736
1735
  basicSafeFilename = basicSafeFilename.normalize("NFC");
1737
1736
  if (maxLength === void 0) return basicSafeFilename;
@@ -1774,7 +1773,7 @@ function getTemporarilyUniqueFilePath(filePath) {
1774
1773
  }
1775
1774
  //#endregion
1776
1775
  //#region src/lib/utilities/resolve-link.ts
1777
- const MD_EXTENSION_REGEX = /* @__PURE__ */ new RegExp("\\.md$", "v");
1776
+ const MD_EXTENSION_REGEX = new RegExp("\\.md$", "v");
1778
1777
  const defaultResolveLinkOptions = {
1779
1778
  allFilePaths: [],
1780
1779
  basePath: void 0,
@@ -1813,48 +1812,25 @@ const defaultResolveLinkOptions = {
1813
1812
  * parameters)
1814
1813
  */
1815
1814
  function resolveLink(filePathOrUrl, options) {
1816
- const { allFilePaths, basePath, convertFilePathsToProtocol, cwd, obsidianVaultName, type } = deepmerge(defaultResolveLinkOptions, options ?? {});
1815
+ const resolvedOptions = deepmerge(defaultResolveLinkOptions, options ?? {});
1816
+ const { allFilePaths, convertFilePathsToProtocol, cwd, obsidianVaultName } = resolvedOptions;
1817
1817
  if (convertFilePathsToProtocol === "obsidian" && obsidianVaultName === void 0) console.warn(`convertFilePathsToProtocol is 'obsidian', but no obsidianVaultName provided`);
1818
- let currentPathOrUrl = filePathOrUrl;
1819
- for (;;) {
1820
- const decodedUrl = safeDecodeURI(currentPathOrUrl) ?? currentPathOrUrl;
1821
- const sourceType = getSrcType(decodedUrl);
1822
- if (sourceType === "localFileName") {
1823
- const resolvedUrl = resolveNameLink(normalize(decodedUrl), cwd, allFilePaths ?? []) ?? resolveWithBasePath(decodedUrl, {
1824
- basePath,
1825
- cwd
1826
- });
1827
- if (getSrcType(resolvedUrl) === "localFilePath") {
1828
- currentPathOrUrl = resolvedUrl;
1829
- continue;
1830
- }
1831
- console.warn(`Failed to convert local file wiki-style name to path: ${currentPathOrUrl} --> ${resolvedUrl}`);
1832
- return resolvedUrl;
1833
- }
1834
- if (sourceType === "localFileUrl") {
1835
- const resolvedUrl = normalize(fileUrlToPath(currentPathOrUrl));
1836
- if (getSrcType(resolvedUrl) === "localFilePath") {
1837
- currentPathOrUrl = resolvedUrl;
1838
- continue;
1839
- }
1840
- console.warn(`Failed to convert file URL to path: ${currentPathOrUrl} --> ${resolvedUrl}`);
1841
- return resolvedUrl;
1818
+ const decodedUrl = safeDecodeURI(filePathOrUrl) ?? filePathOrUrl;
1819
+ switch (getSrcType(decodedUrl)) {
1820
+ case "localFileName": {
1821
+ const resolvedNameLink = resolveNameLink(decodedUrl, cwd, allFilePaths ?? []);
1822
+ return resolvedNameLink === void 0 ? resolveLocalFilePath(decodedUrl, resolvedOptions) : resolveMatchedLocalLink(resolvedNameLink, resolvedOptions);
1842
1823
  }
1843
- switch (sourceType) {
1844
- case "localFilePath": return resolveLocalFilePath(decodedUrl, {
1845
- allFilePaths,
1846
- basePath,
1847
- convertFilePathsToProtocol,
1848
- cwd,
1849
- obsidianVaultName,
1850
- type
1851
- });
1852
- case "obsidianVaultUrl": return currentPathOrUrl;
1853
- case "remoteHttpUrl": return currentPathOrUrl;
1854
- case "unsupportedProtocolUrl":
1855
- console.warn(`Unsupported URL protocol: ${currentPathOrUrl}`);
1856
- return currentPathOrUrl;
1824
+ case "localFilePath": return resolveLocalFilePath(decodedUrl, resolvedOptions);
1825
+ case "localFileUrl": {
1826
+ const encodedFilePath = fileUrlToPath(filePathOrUrl);
1827
+ return resolveLocalFilePath(safeDecodeURI(encodedFilePath) ?? encodedFilePath, resolvedOptions);
1857
1828
  }
1829
+ case "obsidianVaultUrl":
1830
+ case "remoteHttpUrl": return filePathOrUrl;
1831
+ case "unsupportedProtocolUrl":
1832
+ console.warn(`Unsupported URL protocol: ${filePathOrUrl}`);
1833
+ return filePathOrUrl;
1858
1834
  }
1859
1835
  }
1860
1836
  /**
@@ -1863,28 +1839,33 @@ function resolveLink(filePathOrUrl, options) {
1863
1839
  * `max-depth` lint rule).
1864
1840
  */
1865
1841
  function resolveLocalFilePath(decodedUrl, options) {
1866
- const { allFilePaths, basePath, convertFilePathsToProtocol, cwd, obsidianVaultName, type } = options;
1867
- const resolvedUrl = resolveWithBasePath(normalize(decodedUrl), {
1842
+ const { allFilePaths, basePath, cwd } = options;
1843
+ const candidates = getLocalPathCandidates(decodedUrl);
1844
+ for (const { anchor, filePath } of candidates) {
1845
+ const resolvedBase = resolveWithBasePath(normalize(filePath), {
1846
+ basePath,
1847
+ cwd
1848
+ });
1849
+ const matchedPath = (path.extname(resolvedBase) === "" ? [`${resolvedBase}.md`] : [resolvedBase, `${resolvedBase}.md`]).find((candidate) => pathExistsInAllFiles(candidate, allFilePaths ?? []));
1850
+ if (matchedPath !== void 0) return resolveMatchedLocalLink({
1851
+ anchor,
1852
+ filePath: matchedPath
1853
+ }, options);
1854
+ }
1855
+ return resolveWithBasePath(normalize(candidates.at(-1)?.filePath ?? decodedUrl), {
1868
1856
  basePath,
1869
1857
  cwd
1870
1858
  });
1871
- let matchedPath;
1872
- let matchedQuery;
1873
- for (const { base, query } of getBaseAndQueryCandidates(resolvedUrl)) {
1874
- matchedPath = (path.extname(base) === "" ? [`${base}.md`] : [base, `${base}.md`]).find((candidate) => pathExistsInAllFiles(candidate, allFilePaths ?? []));
1875
- if (matchedPath !== void 0) {
1876
- matchedQuery = query;
1877
- break;
1878
- }
1879
- }
1880
- if (matchedPath !== void 0) {
1881
- if (convertFilePathsToProtocol !== "none" && (type === "link" || type === "embed" && [".md", ".pdf"].includes(path.extname(matchedPath)))) {
1882
- if (convertFilePathsToProtocol === "obsidian" && obsidianVaultName !== void 0) return createObsidianVaultLink(`${matchedPath}${matchedQuery ?? ""}`, basePath ?? "", obsidianVaultName);
1883
- if (convertFilePathsToProtocol === "file") return createFileLink(`${matchedPath}${matchedQuery ?? ""}`);
1884
- }
1885
- return matchedPath;
1859
+ }
1860
+ /** Render a matched local file and its still-unmodified Obsidian anchor. */
1861
+ function resolveMatchedLocalLink(link, options) {
1862
+ const { anchor, filePath } = link;
1863
+ const { basePath, convertFilePathsToProtocol, obsidianVaultName, type } = options;
1864
+ if (convertFilePathsToProtocol !== "none" && (type === "link" || type === "embed" && [".md", ".pdf"].includes(path.extname(filePath)))) {
1865
+ if (convertFilePathsToProtocol === "obsidian" && obsidianVaultName !== void 0) return createObsidianVaultLink(link, basePath ?? "", obsidianVaultName);
1866
+ if (convertFilePathsToProtocol === "file") return createFileLink(`${filePath}${anchor ?? ""}`);
1886
1867
  }
1887
- return getBase(resolvedUrl);
1868
+ return filePath;
1888
1869
  }
1889
1870
  /**
1890
1871
  * Convert from a (usually wiki-style) named link to an absolute path to an
@@ -1904,14 +1885,18 @@ function resolveLocalFilePath(decodedUrl, options) {
1904
1885
  * @param allFilePaths Array of absolute paths to all other files in the paths
1905
1886
  * to be considered. (POSIX-style paths.)
1906
1887
  *
1907
- * @returns Absolute path to the best matching file with the name provided, or
1908
- * undefined if there's no valid match. (POSIX-style paths.)
1888
+ * @returns The absolute path to the best matching file and its unmodified
1889
+ * anchor, or undefined if there's no valid match. (POSIX-style path.)
1909
1890
  */
1910
1891
  function resolveNameLink(name, cwd, allFilePaths) {
1911
1892
  if (allFilePaths.length === 0) return;
1912
- for (const { base, query } of getBaseAndQueryCandidates(name)) {
1913
- const match = findBestNameMatch(path.extname(base) === "" ? `${base}.md` : base, cwd, allFilePaths);
1914
- if (match !== void 0) return `${match}${query ?? ""}`;
1893
+ for (const { anchor, filePath } of getLocalPathCandidates(name)) {
1894
+ const normalizedBase = normalize(filePath);
1895
+ const match = findBestNameMatch(path.extname(normalizedBase) === "" ? `${normalizedBase}.md` : normalizedBase, cwd, allFilePaths);
1896
+ if (match !== void 0) return {
1897
+ anchor,
1898
+ filePath: match
1899
+ };
1915
1900
  }
1916
1901
  }
1917
1902
  /**
@@ -1965,9 +1950,9 @@ function pathExistsInAllFiles(filePath, allFilePaths) {
1965
1950
  function createFileLink(absolutePath) {
1966
1951
  return `file://${absolutePath}`;
1967
1952
  }
1968
- function createObsidianVaultLink(absolutePath, basePath, obsidianVault) {
1969
- const relativePath = stripBasePath(absolutePath, basePath);
1970
- return `obsidian://open?vault=${encodeURIComponent(obsidianVault)}&file=${encodeURIComponent(relativePath)}`;
1953
+ function createObsidianVaultLink(link, basePath, obsidianVault) {
1954
+ const linkPath = `${stripBasePath(link.filePath, basePath)}${link.anchor ?? ""}`;
1955
+ return `obsidian://open?vault=${encodeURIComponent(obsidianVault)}&file=${encodeURIComponent(linkPath)}`;
1971
1956
  }
1972
1957
  //#endregion
1973
1958
  //#region src/lib/parse/remark-resolve-links.ts
@@ -2321,7 +2306,7 @@ const plugin = function() {
2321
2306
  };
2322
2307
  //#endregion
2323
2308
  //#region src/lib/parse/remark-utilities.ts
2324
- const CLOZE_NUMBER_PREFIX_REGEX = /* @__PURE__ */ new RegExp("^[\\(\\|]?(\\d{1,2})(?:[\\s\\).\\|]|$)(.*)$", "v");
2309
+ const CLOZE_NUMBER_PREFIX_REGEX = new RegExp("^[\\(\\|]?(\\d{1,2})(?:[\\s\\).\\|]|$)(.*)$", "v");
2325
2310
  const defaultAstFromMarkdownOptions = { ...defaultGlobalOptions };
2326
2311
  async function getAstFromMarkdown(markdown, options) {
2327
2312
  const { allFilePaths, basePath, cwd, obsidianVault, resolveUrls } = deepmerge(defaultAstFromMarkdownOptions, options ?? {});
@@ -2878,7 +2863,7 @@ function formatSetStyleResult(result, verbose = false) {
2878
2863
  }
2879
2864
  //#endregion
2880
2865
  //#region src/lib/model/frontmatter.ts
2881
- const NEWLINE_REGEX = /* @__PURE__ */ new RegExp("\\r?\\n", "v");
2866
+ const NEWLINE_REGEX = new RegExp("\\r?\\n", "v");
2882
2867
  /**
2883
2868
  * Update the noteId in the frontmatter of a markdown string.
2884
2869
  *
@@ -2906,7 +2891,8 @@ async function setNoteIdInFrontmatter(markdown, noteId) {
2906
2891
  ...lines
2907
2892
  ].join("\n");
2908
2893
  }
2909
- const parsedFrontmatter = await parse(lines.slice(frontmatterStart + 1, frontmatterEnd).join("\n")) ?? {};
2894
+ const frontmatter = lines.slice(frontmatterStart + 1, frontmatterEnd).join("\n");
2895
+ const parsedFrontmatter = await parse(frontmatter) ?? {};
2910
2896
  if (noteId === void 0) {
2911
2897
  delete parsedFrontmatter.noteId;
2912
2898
  if (Object.keys(parsedFrontmatter).length === 0) {
@@ -805,7 +805,7 @@ Same as `PartialDeep`, but accepts only `object`s as inputs. Internal helper for
805
805
  */
806
806
  type PartialObjectDeep<ObjectType extends object, Options extends Required<PartialDeepOptions>> = { [KeyType in keyof ObjectType]?: _PartialDeep<ObjectType[KeyType], Options>; };
807
807
  //#endregion
808
- //#region node_modules/.pnpm/yanki-connect@4.0.7/node_modules/yanki-connect/dist/index.d.ts
808
+ //#region node_modules/.pnpm/yanki-connect@4.0.8/node_modules/yanki-connect/dist/index.d.ts
809
809
  //#region src/types/deck.d.ts
810
810
  type DeckStats = {
811
811
  deck_id: number;