yanki 0.7.1 → 0.8.1
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.
- package/dist/bin/cli.js +9 -9
- package/dist/lib/index.d.ts +107 -125
- package/dist/lib/index.js +1 -1
- package/dist/sync-files-CfVaBCRP.js +230 -0
- package/package.json +13 -6
- package/readme.md +42 -31
- package/dist/sync-B_u0fKEU.js +0 -222
package/dist/bin/cli.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
var
|
|
3
|
-
`)):(process.stderr.write(
|
|
4
|
-
`))}).command("list [options]","Utility command to list Yanki-created notes in the Anki database.",e=>e.option(
|
|
5
|
-
`)):(process.stdout.write(
|
|
6
|
-
`))}).command("delete [options]","Utility command to manually delete Yanki-created notes in the Anki database. This is for advanced use cases, usually the `sync` command takes care of deleting files from Anki Database once they're removed from the local file system.",e=>e.option(
|
|
7
|
-
`)):(process.stderr.write(
|
|
8
|
-
`))}).command("style [options]","Utility command to set the CSS stylesheet for all present and future Yanki-created notes.",e=>e.option(
|
|
9
|
-
`)):(process.stderr.write(
|
|
10
|
-
`))}).demandCommand(1).alias("h","help").version(
|
|
2
|
+
var J=Object.defineProperty;var u=(e,t)=>J(e,"name",{value:t,configurable:!0});import{t as h,u as y,n as M,m as I,l as L,b as U,c as D,f as z,s as F,i as H}from"../sync-files-CfVaBCRP.js";import s from"chalk";import{globby as j}from"globby";import W from"node:fs/promises";import q from"node:path";import B from"node:os";import G from"yargs";import{hideBin as K}from"yargs/helpers";import"rehype-mathjax";import"rehype-parse";import"node:crypto";var Q="0.8.1";const R=process?.versions?.node!==void 0,c={verbose:!1,log(...e){if(!this.verbose)return;const t=s.gray("[Log]");R?console.warn(t,...e):console.log(t,...e)},logPrefixed(e,...t){this.info(s.blue(`[${e}]`),...t)},info(...e){if(!this.verbose)return;const t=s.green("[Info]");R?console.warn(t,...e):console.info(t,...e)},infoPrefixed(e,...t){this.info(s.blue(`[${e}]`),...t)},warn(...e){console.warn(s.yellow("[Warning]"),...e)},warnPrefixed(e,...t){this.warn(s.blue(`[${e}]`),...t)},error(...e){console.error(s.red("[Error]"),...e)},errorPrefixed(e,...t){this.error(s.blue(`[${e}]`),...t)}},g={"anki-auto-launch":{alias:"l",default:!1,describe:"Attempt to open the Anki desktop app if it's not already running. (Experimental, macOS only.)",type:"boolean"}},A={"anki-web":{alias:"w",default:!0,describe:'Automatically sync any changes to AnkiWeb after Yanki has finished syncing locally. If false, only local Anki data is updated and you must manually invoke a sync to AnkiWeb. This is the equivalent of pushing the "sync" button in the Anki app.',type:"boolean"}},w={"anki-connect":{default:"http://127.0.0.1:8765",describe:"Host and port of the Anki-Connect server. The default is usually fine. See the Anki-Connect documentation for more information.",type:"string"}},S={verbose:{default:!1,describe:"Enable verbose logging.",type:"boolean"}};function b(e){return{json:{default:!1,describe:e,type:"boolean"}}}u(b,"jsonOption");const C={"dry-run":{alias:"d",default:!1,describe:"Run without making any changes to the Anki database. See a report of what would have been done.",type:"boolean"}};function O(e){return{namespace:{alias:"n",default:h.namespace,describe:e,type:"string"}}}u(O,"namespaceOption");const E=B.homedir();function V(e){if(typeof e!="string")throw new TypeError(`Expected a string, got ${typeof e}`);return E?e.replace(/^~(?=$|\/|\\)/,E):e}u(V,"untildify");const k=u(e=>{const{code:t}=e.cause;throw t==="ECONNREFUSED"&&(c.error("Failed to connect to Anki. Make sure Anki is running and AnkiConnect is installed."),process.exitCode=1,process.exit()),e instanceof Error?e:new Error("Unknown error")},"ankiNotRunningErrorHandler"),$=G(K(process.argv));await $.scriptName("yanki").usage("$0 [command]","Run a Yanki command. Defaults to `sync` if a command is not provided.").command(["$0 <directory> [options]","sync <directory> [options]"],"Perform a one-way synchronization from a local directory of Markdown files to the Anki database. Any Markdown files in subdirectories are included as well.",e=>e.positional("directory",{demandOption:!0,describe:"The path to the local directory of Markdown files to sync.",type:"string"}).option(C).option(O("Advanced option for managing multiple Yanki synchronization groups. Case insensitive. See the readme for more information.")).option(w).option(g).option(A).option("manage-filenames",{alias:"m",choices:["off","prompt","response"],default:h.manageFilenames,describe:'Rename local note files to match their content. Useful if you want to feel have semantically reasonable note file names without managing them by hand. The `"prompt"` option will attempt to create the filename based on the "front" of the card, while `"response"` will prioritize the "back", "Cloze", or "type in the answer" portions of the card. Truncation, sanitization, and deduplication are taken care of.',type:"string"}).option("max-filename-length",{default:void 0,defaultDescription:String(h.maxFilenameLength),describe:"If `manage-filenames` is enabled, this option specifies the maximum length of the filename in characters.",type:"number"}).option("sync-media",{alias:"s",choices:["off","all","local","remote"],default:h.syncMediaAssets,describe:"Sync image, video, and audio assets to Anki's media storage system. Clean up is managed automatically. The `all` argument will save both local and remote assets to Anki, while `local` will only save local assets, `remote` will only save remote assets, and `off` will not save any assets.",type:"string"}).option(b("Output the sync report as JSON.")).option(S),async({ankiAutoLaunch:e,ankiConnect:t,ankiWeb:i,directory:o,dryRun:a,json:r,manageFilenames:n,maxFilenameLength:d,namespace:f,recursive:l=!0,syncMedia:m,verbose:p})=>{c.verbose=p;const v=V(o),P=l?`${v}/**/*.md`:`${v}/*.md`,x=await j(P,{absolute:!0});if(x.length===0){c.error(`No Markdown files found in "${v}".`),process.exitCode=1;return}n==="off"&&d!==void 0&&c.warn("Ignoring `max-filename-length` option because `manage-filenames` is not enabled.");const{host:Y,port:T}=y(t),N=await M(x,{ankiConnectOptions:{autoLaunch:e,host:Y,port:T},ankiWeb:i,dryRun:a,manageFilenames:n,maxFilenameLength:d,namespace:f,syncMediaAssets:m}).catch(k);r?(process.stdout.write(JSON.stringify(N,void 0,2)),process.stdout.write(`
|
|
3
|
+
`)):(process.stderr.write(I(N,p)),process.stderr.write(`
|
|
4
|
+
`))}).command("list [options]","Utility command to list Yanki-created notes in the Anki database.",e=>e.option(O("Advanced option to list notes in a specific namespace. Case insensitive. Notes from the default internal namespace are listed by default. Pass `'*'` to list all Yanki-created notes in the Anki database.")).options(w).options(g).option(b("Output the list of notes as JSON to stdout.")),async({ankiAutoLaunch:e,ankiConnect:t,json:i,namespace:o})=>{const{host:a,port:r}=y(t),n=await L({ankiConnectOptions:{autoLaunch:e,host:a,port:r},namespace:o}).catch(k);i?(process.stdout.write(JSON.stringify(n,void 0,2)),process.stdout.write(`
|
|
5
|
+
`)):(process.stdout.write(U(n)),process.stdout.write(`
|
|
6
|
+
`))}).command("delete [options]","Utility command to manually delete Yanki-created notes in the Anki database. This is for advanced use cases, usually the `sync` command takes care of deleting files from Anki Database once they're removed from the local file system.",e=>e.option(C).option(O("Advanced option to list notes in a specific namespace. Case insensitive. Notes from the default internal namespace are listed by default. If you've synced notes to multiple namespaces, Pass `'*'` to delete all Yanki-created notes in the Anki database.")).options(w).options(g).option(A).option(b("Output the list of deleted notes as JSON to stdout.")).option(S),async({ankiAutoLaunch:e,ankiConnect:t,ankiWeb:i,dryRun:o,json:a,namespace:r,verbose:n})=>{const{host:d,port:f}=y(t),l=await D({ankiConnectOptions:{autoLaunch:e,host:d,port:f},ankiWeb:i,dryRun:o,namespace:r}).catch(k);a?(process.stdout.write(JSON.stringify(l,void 0,2)),process.stdout.write(`
|
|
7
|
+
`)):(process.stderr.write(z(l,n)),process.stderr.write(`
|
|
8
|
+
`))}).command("style [options]","Utility command to set the CSS stylesheet for all present and future Yanki-created notes.",e=>e.option(C).option("css",{alias:"c",default:void 0,describe:"Path to the CSS stylesheet to set for all Yanki-created notes. If not provided, the default Anki stylesheet is used.",type:"string"}).options(w).options(g).option(A).option(b("Output the list of updated note types / models as JSON to stdout.")).option(S),async({ankiAutoLaunch:e,ankiConnect:t,ankiWeb:i,css:o,dryRun:a,json:r,verbose:n})=>{const{host:d,port:f}=y(t);let l;if(o!==void 0){if(q.extname(o)!==".css"){c.error("The provided CSS file must have a .css extension."),process.exitCode=1;return}try{l=await W.readFile(o,"utf8")}catch(p){p instanceof Error?c.error(`Error loading CSS file: ${p.message}`):c.error(`Unknown error loading CSS file: ${String(p)}`),process.exitCode=1;return}}const m=await F({ankiConnectOptions:{autoLaunch:e,host:d,port:f},ankiWeb:i,css:l??void 0,dryRun:a}).catch(k);r?(process.stdout.write(JSON.stringify(m,void 0,2)),process.stdout.write(`
|
|
9
|
+
`)):(process.stderr.write(H(m,n)),process.stderr.write(`
|
|
10
|
+
`))}).demandCommand(1).alias("h","help").version(Q).alias("v","version").help().wrap(process.stdout.isTTY?Math.min(120,$.terminalWidth()):0).parse();
|
package/dist/lib/index.d.ts
CHANGED
|
@@ -140,10 +140,11 @@ type DeckRequests = Request<'changeDeck', 6, {
|
|
|
140
140
|
|
|
141
141
|
type NoteModel = 'Basic (and reversed card)' | 'Basic (type in the answer)' | 'Basic' | 'Cloze' | ({} & string);
|
|
142
142
|
type NoteMedia = {
|
|
143
|
+
data?: string;
|
|
143
144
|
fields: string[];
|
|
144
|
-
|
|
145
|
+
path?: string;
|
|
145
146
|
skipHash?: false;
|
|
146
|
-
url
|
|
147
|
+
url?: string;
|
|
147
148
|
};
|
|
148
149
|
type Note = {
|
|
149
150
|
audio?: NoteMedia[];
|
|
@@ -266,11 +267,11 @@ type GraphicalRequests = Request<'guiBrowse', 6, {
|
|
|
266
267
|
type MediaRequests = Request<'retrieveMediaFile', 6, {
|
|
267
268
|
filename: string;
|
|
268
269
|
}, false | string> | Request<'storeMediaFile', 6, {
|
|
269
|
-
data
|
|
270
|
-
deleteExisting
|
|
270
|
+
data?: string;
|
|
271
|
+
deleteExisting?: boolean;
|
|
271
272
|
filename: string;
|
|
272
|
-
path
|
|
273
|
-
url
|
|
273
|
+
path?: string;
|
|
274
|
+
url?: string;
|
|
274
275
|
}, string> | Request<'deleteMediaFile', 6, {
|
|
275
276
|
filename: string;
|
|
276
277
|
}> | Request<'getMediaDirPath', 6, never, string> | Request<'getMediaFilesNames', 6, {
|
|
@@ -527,12 +528,13 @@ type StatisticRequests = Request<'cardReviews', 6, {
|
|
|
527
528
|
* external re-implementation when passing a custom fetch function to
|
|
528
529
|
* YankiClient.
|
|
529
530
|
*/
|
|
530
|
-
type
|
|
531
|
-
body
|
|
532
|
-
headers
|
|
533
|
-
method
|
|
534
|
-
mode
|
|
531
|
+
type YankiFetchAdapter = (input: string, init?: {
|
|
532
|
+
body?: string;
|
|
533
|
+
headers?: Record<string, string>;
|
|
534
|
+
method?: string;
|
|
535
|
+
mode?: RequestMode;
|
|
535
536
|
}) => Promise<{
|
|
537
|
+
headers: Headers | Record<string, string>;
|
|
536
538
|
json(): Promise<any>;
|
|
537
539
|
status: number;
|
|
538
540
|
} | undefined>;
|
|
@@ -567,7 +569,7 @@ type YankiConnectOptions = {
|
|
|
567
569
|
*
|
|
568
570
|
* @default fetch
|
|
569
571
|
*/
|
|
570
|
-
|
|
572
|
+
fetchAdapter: YankiFetchAdapter | undefined;
|
|
571
573
|
/**
|
|
572
574
|
* Host where the Anki-Connect service is running.
|
|
573
575
|
*
|
|
@@ -840,8 +842,21 @@ type YankiNote = Simplify<{
|
|
|
840
842
|
noteId: number | undefined;
|
|
841
843
|
} & Omit<ParamsForAction<'addNote'>['note'], 'fields' | 'modelName' | 'options'>>;
|
|
842
844
|
|
|
843
|
-
|
|
844
|
-
type
|
|
845
|
+
type FetchAdapter = YankiFetchAdapter;
|
|
846
|
+
type ManageFilenames = 'off' | 'prompt' | 'response';
|
|
847
|
+
type SyncMediaAssets = 'all' | 'local' | 'off' | 'remote';
|
|
848
|
+
type FileAdapter = {
|
|
849
|
+
readFile(filePath: string): Promise<string>;
|
|
850
|
+
readFileBuffer(filePath: string): Promise<Uint8Array>;
|
|
851
|
+
rename(oldPath: string, newPath: string): Promise<void>;
|
|
852
|
+
stat(filePath: string): Promise<{
|
|
853
|
+
ctimeMs: number;
|
|
854
|
+
mtimeMs: number;
|
|
855
|
+
size: number;
|
|
856
|
+
}>;
|
|
857
|
+
writeFile(filePath: string, data: string): Promise<void>;
|
|
858
|
+
};
|
|
859
|
+
type GlobalOptions = {
|
|
845
860
|
ankiConnectOptions: YankiConnectOptions;
|
|
846
861
|
/**
|
|
847
862
|
* Automatically sync any changes to AnkiWeb after Yanki has finished syncing
|
|
@@ -850,17 +865,36 @@ type CleanOptions = {
|
|
|
850
865
|
* button in the Anki app.
|
|
851
866
|
*/
|
|
852
867
|
ankiWeb: boolean;
|
|
868
|
+
/** Override where "/" should resolve to... useful in Obsidian to set the vault path as the "root" */
|
|
869
|
+
basePath: string | undefined;
|
|
870
|
+
cwd: string;
|
|
853
871
|
dryRun: boolean;
|
|
872
|
+
/**
|
|
873
|
+
* Exposed for Obsidian, currently only used for getting URL content hashes
|
|
874
|
+
* and inferring MIME types of URLs without extensions.
|
|
875
|
+
* Note that ankiConnectOptions ALSO has a fetch adapter option specifically
|
|
876
|
+
* for communicating with Anki-Connect.
|
|
877
|
+
*/
|
|
878
|
+
fetchAdapter: FetchAdapter | undefined;
|
|
879
|
+
fileAdapter: FileAdapter | undefined;
|
|
880
|
+
manageFilenames: ManageFilenames;
|
|
881
|
+
/** Only applies if manageFilenames is `true`. Will _not_ truncate user-specified file names in other cases. */
|
|
882
|
+
maxFilenameLength: number;
|
|
854
883
|
namespace: string;
|
|
884
|
+
/** Ensures that wiki-style links work correctly */
|
|
885
|
+
obsidianVault: string | undefined;
|
|
886
|
+
/** Sync image, video, and audio assets to Anki's media storage system */
|
|
887
|
+
syncMediaAssets: SyncMediaAssets;
|
|
855
888
|
};
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
889
|
+
|
|
890
|
+
type CleanOptions = Pick<GlobalOptions, 'ankiConnectOptions' | 'ankiWeb' | 'dryRun' | 'namespace'>;
|
|
891
|
+
declare const defaultCleanOptions: CleanOptions;
|
|
892
|
+
type CleanResult = Simplify<{
|
|
893
|
+
deletedDecks: string[];
|
|
894
|
+
deletedMedia: string[];
|
|
895
|
+
deletedNotes: YankiNote[];
|
|
861
896
|
duration: number;
|
|
862
|
-
|
|
863
|
-
};
|
|
897
|
+
} & Pick<GlobalOptions, 'ankiWeb' | 'dryRun' | 'namespace'>>;
|
|
864
898
|
/**
|
|
865
899
|
* Deletes all remote notes in Anki associated with the given namespace.
|
|
866
900
|
*
|
|
@@ -870,15 +904,12 @@ type CleanReport = {
|
|
|
870
904
|
* @param options
|
|
871
905
|
* @throws
|
|
872
906
|
*/
|
|
873
|
-
declare function cleanNotes(options?: PartialDeep<CleanOptions>): Promise<
|
|
874
|
-
declare function
|
|
907
|
+
declare function cleanNotes(options?: PartialDeep<CleanOptions>): Promise<CleanResult>;
|
|
908
|
+
declare function formatCleanResult(result: CleanResult, verbose?: boolean): string;
|
|
875
909
|
|
|
876
|
-
type ListOptions =
|
|
877
|
-
ankiConnectOptions: YankiConnectOptions;
|
|
878
|
-
namespace: string;
|
|
879
|
-
};
|
|
910
|
+
type ListOptions = Pick<GlobalOptions, 'ankiConnectOptions' | 'namespace'>;
|
|
880
911
|
declare const defaultListOptions: ListOptions;
|
|
881
|
-
type
|
|
912
|
+
type ListResult = {
|
|
882
913
|
duration: number;
|
|
883
914
|
namespace: string;
|
|
884
915
|
notes: YankiNote[];
|
|
@@ -888,107 +919,64 @@ type ListReport = {
|
|
|
888
919
|
* @param options
|
|
889
920
|
* @returns
|
|
890
921
|
*/
|
|
891
|
-
declare function listNotes(options?: PartialDeep<ListOptions>): Promise<
|
|
892
|
-
declare function
|
|
893
|
-
|
|
894
|
-
type
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
note: YankiNote;
|
|
901
|
-
}>;
|
|
922
|
+
declare function listNotes(options?: PartialDeep<ListOptions>): Promise<ListResult>;
|
|
923
|
+
declare function formatListResult(result: ListResult): string;
|
|
924
|
+
|
|
925
|
+
type LoadOptions = Pick<GlobalOptions, 'basePath' | 'fetchAdapter' | 'fileAdapter' | 'namespace' | 'obsidianVault' | 'syncMediaAssets'>;
|
|
926
|
+
type LocalNote = {
|
|
927
|
+
filePath: string;
|
|
928
|
+
filePathOriginal: string;
|
|
929
|
+
markdown: string;
|
|
930
|
+
note: YankiNote;
|
|
902
931
|
};
|
|
903
|
-
|
|
904
|
-
type
|
|
932
|
+
|
|
933
|
+
type RenameNotesOptions = Pick<GlobalOptions, 'dryRun' | 'fileAdapter' | 'manageFilenames' | 'maxFilenameLength'>;
|
|
934
|
+
type RenameFilesResult = {
|
|
905
935
|
dryRun: boolean;
|
|
906
|
-
|
|
907
|
-
manageFilenames: boolean;
|
|
908
|
-
maxFilenameLength: number;
|
|
909
|
-
namespace: string;
|
|
910
|
-
obsidianVault: string | undefined;
|
|
936
|
+
notes: LocalNote[];
|
|
911
937
|
};
|
|
938
|
+
type RenameFilesOptions = Simplify<LoadOptions & RenameNotesOptions>;
|
|
912
939
|
declare const defaultRenameFilesOptions: RenameFilesOptions;
|
|
913
|
-
|
|
914
|
-
* Also loads the notes from markdown and sets deck names...
|
|
915
|
-
* @param allLocalFilePaths
|
|
916
|
-
* @param options
|
|
917
|
-
* @param readFile
|
|
918
|
-
* @param writeFile
|
|
919
|
-
* @param rename
|
|
920
|
-
*/
|
|
921
|
-
declare function renameFiles(allLocalFilePaths: string[], options: Partial<RenameFilesOptions>, readFile?: (filePath: string) => Promise<string>, writeFile?: (filePath: string, data: string) => Promise<void>, // Not used, yet
|
|
922
|
-
rename?: (oldPath: string, newPath: string) => Promise<void>): Promise<RenameFilesReport>;
|
|
940
|
+
declare function renameFiles(allLocalFilePaths: string[], options: Partial<RenameFilesOptions>): Promise<RenameFilesResult>;
|
|
923
941
|
|
|
924
|
-
type
|
|
925
|
-
ankiConnectOptions: YankiConnectOptions;
|
|
926
|
-
/**
|
|
927
|
-
* Automatically sync any changes to AnkiWeb after Yanki has finished syncing
|
|
928
|
-
* locally. If false, only local Anki data is updated and you must manually
|
|
929
|
-
* invoke a sync to AnkiWeb. This is the equivalent of pushing the "sync"
|
|
930
|
-
* button in the Anki app.
|
|
931
|
-
*/
|
|
932
|
-
ankiWeb: boolean;
|
|
942
|
+
type SetStyleOptions = {
|
|
933
943
|
css: string;
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
type StyleReport = {
|
|
938
|
-
ankiWeb: boolean;
|
|
939
|
-
dryRun: boolean;
|
|
944
|
+
} & Pick<GlobalOptions, 'ankiConnectOptions' | 'ankiWeb' | 'dryRun'>;
|
|
945
|
+
declare const defaultSetStyleOptions: SetStyleOptions;
|
|
946
|
+
type SetStyleResult = Simplify<{
|
|
940
947
|
duration: number;
|
|
941
948
|
models: Array<{
|
|
942
949
|
action: 'unchanged' | 'updated';
|
|
943
950
|
name: string;
|
|
944
951
|
}>;
|
|
945
|
-
}
|
|
946
|
-
|
|
947
|
-
declare
|
|
952
|
+
} & Pick<GlobalOptions, 'ankiWeb' | 'dryRun'>>;
|
|
953
|
+
type GetStyleOptions = Pick<GlobalOptions, 'ankiConnectOptions'>;
|
|
954
|
+
declare const defaultGetStyleOptions: GetStyleOptions;
|
|
955
|
+
declare function getStyle(options: PartialDeep<GetStyleOptions>): Promise<string>;
|
|
956
|
+
declare function setStyle(options?: PartialDeep<SetStyleOptions>): Promise<SetStyleResult>;
|
|
957
|
+
declare function formatSetStyleResult(result: SetStyleResult, verbose?: boolean): string;
|
|
948
958
|
|
|
949
959
|
type SyncedNote = {
|
|
950
960
|
action: 'ankiUnreachable' | 'created' | 'deleted' | 'recreated' | 'unchanged' | 'updated';
|
|
951
|
-
filePath?: string;
|
|
952
|
-
filePathOriginal?: string;
|
|
953
961
|
note: YankiNote;
|
|
954
962
|
};
|
|
955
|
-
type SyncOptions =
|
|
956
|
-
|
|
957
|
-
/**
|
|
958
|
-
* Automatically sync any changes to AnkiWeb after Yanki has finished syncing
|
|
959
|
-
* locally. If false, only local Anki data is updated and you must manually
|
|
960
|
-
* invoke a sync to AnkiWeb. This is the equivalent of pushing the "sync"
|
|
961
|
-
* button in the Anki app.
|
|
962
|
-
*/
|
|
963
|
-
ankiWeb: boolean;
|
|
964
|
-
defaultDeckName: string;
|
|
965
|
-
dryRun: boolean;
|
|
966
|
-
filenameMode: FilenameMode;
|
|
967
|
-
/** Only applies to syncFiles */
|
|
968
|
-
manageFilenames: boolean;
|
|
969
|
-
/** Only applies if manageFilenames is not `false`. Will _not_ truncate user-specified file names in other cases. */
|
|
970
|
-
maxFilenameLength: number;
|
|
971
|
-
namespace: string;
|
|
972
|
-
/** Ensures that wiki-style links work correctly */
|
|
973
|
-
obsidianVault: string | undefined;
|
|
974
|
-
};
|
|
975
|
-
declare const defaultSyncOptions: SyncOptions;
|
|
976
|
-
type SyncReport = {
|
|
977
|
-
ankiWeb: boolean;
|
|
963
|
+
type SyncOptions = Pick<GlobalOptions, 'ankiConnectOptions' | 'ankiWeb' | 'dryRun' | 'namespace'>;
|
|
964
|
+
type SyncNotesResult = Simplify<{
|
|
978
965
|
deletedDecks: string[];
|
|
979
|
-
|
|
966
|
+
deletedMedia: string[];
|
|
980
967
|
duration: number;
|
|
981
|
-
namespace: string;
|
|
982
968
|
synced: SyncedNote[];
|
|
983
|
-
}
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
969
|
+
} & Pick<GlobalOptions, 'ankiWeb' | 'dryRun' | 'namespace'>>;
|
|
970
|
+
|
|
971
|
+
type SyncFilesOptions = Simplify<Pick<GlobalOptions, 'basePath' | 'fetchAdapter' | 'fileAdapter' | 'manageFilenames' | 'maxFilenameLength' | 'namespace' | 'obsidianVault' | 'syncMediaAssets'> & SyncOptions>;
|
|
972
|
+
declare const defaultSyncFilesOptions: SyncFilesOptions;
|
|
973
|
+
type SyncedFile = Simplify<{
|
|
974
|
+
filePath: string | undefined;
|
|
975
|
+
filePathOriginal: string | undefined;
|
|
976
|
+
} & SyncedNote>;
|
|
977
|
+
type SyncFilesResult = Simplify<{
|
|
978
|
+
synced: SyncedFile[];
|
|
979
|
+
} & Omit<SyncNotesResult, 'synced'>>;
|
|
992
980
|
/**
|
|
993
981
|
* Sync a list of local yanki files to Anki.
|
|
994
982
|
*
|
|
@@ -1001,25 +989,19 @@ declare function syncNotes(allLocalNotes: YankiNote[], options?: PartialDeep<Syn
|
|
|
1001
989
|
* @returns The synced files (with new IDs where applicable), plus some stats
|
|
1002
990
|
* about the sync @throws
|
|
1003
991
|
*/
|
|
1004
|
-
declare function syncFiles(allLocalFilePaths: string[], options?: PartialDeep<
|
|
1005
|
-
declare function
|
|
1006
|
-
|
|
1007
|
-
/**
|
|
1008
|
-
* Helpers for working with the Markdown AST.
|
|
1009
|
-
*/
|
|
1010
|
-
|
|
1011
|
-
type AstFromMarkdownOptions = {
|
|
1012
|
-
obsidianVault?: string;
|
|
1013
|
-
};
|
|
992
|
+
declare function syncFiles(allLocalFilePaths: string[], options?: PartialDeep<SyncFilesOptions>): Promise<SyncFilesResult>;
|
|
993
|
+
declare function formatSyncFilesResult(result: SyncFilesResult, verbose?: boolean): string;
|
|
1014
994
|
|
|
1015
995
|
/**
|
|
1016
996
|
* Turns a markdown string into a YankiNote object.
|
|
1017
997
|
*/
|
|
1018
998
|
|
|
1019
|
-
type
|
|
1020
|
-
namespace
|
|
1021
|
-
|
|
1022
|
-
|
|
999
|
+
type GetNoteFromMarkdownOptions = {
|
|
1000
|
+
/** Needed for the public API, but optional for more efficient use internally when the namespace is already validated. */
|
|
1001
|
+
namespaceValidationAndSanitization: boolean;
|
|
1002
|
+
} & Pick<GlobalOptions, 'basePath' | 'cwd' | 'fetchAdapter' | 'fileAdapter' | 'namespace' | 'obsidianVault' | 'syncMediaAssets'>;
|
|
1003
|
+
declare const defaultGetNoteFromMarkdownOptions: GetNoteFromMarkdownOptions;
|
|
1004
|
+
declare function getNoteFromMarkdown(markdown: string, options?: Partial<GetNoteFromMarkdownOptions>): Promise<YankiNote>;
|
|
1023
1005
|
|
|
1024
1006
|
declare function urlToHostAndPort(url: string): {
|
|
1025
1007
|
host: string;
|
|
@@ -1027,4 +1009,4 @@ declare function urlToHostAndPort(url: string): {
|
|
|
1027
1009
|
};
|
|
1028
1010
|
declare function hostAndPortToUrl(host: string, port: number): string;
|
|
1029
1011
|
|
|
1030
|
-
export { type CleanOptions, type
|
|
1012
|
+
export { type CleanOptions, type CleanResult, type FetchAdapter, type FileAdapter, type GetNoteFromMarkdownOptions, type GetStyleOptions, type ListOptions, type RenameFilesOptions, type RenameFilesResult, type SetStyleOptions, type SetStyleResult, type SyncFilesOptions, type SyncFilesResult, type YankiNote, cleanNotes, defaultCleanOptions, defaultGetNoteFromMarkdownOptions, defaultGetStyleOptions, defaultListOptions, defaultRenameFilesOptions, defaultSetStyleOptions, defaultSyncFilesOptions, formatCleanResult, formatListResult, formatSetStyleResult, formatSyncFilesResult, getNoteFromMarkdown, getStyle, hostAndPortToUrl, listNotes, renameFiles, setStyle, syncFiles, urlToHostAndPort };
|
package/dist/lib/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{c as
|
|
1
|
+
import{c as i,d as n,o as r,g as m,a as f,e as p,h as u,k as d,f as S,b as y,i as F,m as O,p as c,j as R,q as N,l as g,r as k,s as h,n as w,u as A}from"../sync-files-CfVaBCRP.js";import"rehype-mathjax";import"rehype-parse";import"node:path";import"node:crypto";export{i as cleanNotes,n as defaultCleanOptions,r as defaultGetNoteFromMarkdownOptions,m as defaultGetStyleOptions,f as defaultListOptions,p as defaultRenameFilesOptions,u as defaultSetStyleOptions,d as defaultSyncFilesOptions,S as formatCleanResult,y as formatListResult,F as formatSetStyleResult,O as formatSyncFilesResult,c as getNoteFromMarkdown,R as getStyle,N as hostAndPortToUrl,g as listNotes,k as renameFiles,h as setStyle,w as syncFiles,A as urlToHostAndPort};
|