yanki 0.7.1 → 0.8.0
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 +105 -125
- package/dist/lib/index.js +1 -1
- package/dist/sync-files-norUev7R.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-norUev7R.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.0";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,34 @@ type CleanOptions = {
|
|
|
850
865
|
* button in the Anki app.
|
|
851
866
|
*/
|
|
852
867
|
ankiWeb: boolean;
|
|
868
|
+
cwd: string;
|
|
853
869
|
dryRun: boolean;
|
|
870
|
+
/**
|
|
871
|
+
* Exposed for Obsidian, currently only used for getting URL content hashes
|
|
872
|
+
* and inferring MIME types of URLs without extensions.
|
|
873
|
+
* Note that ankiConnectOptions ALSO has a fetch adapter option specifically
|
|
874
|
+
* for communicating with Anki-Connect.
|
|
875
|
+
*/
|
|
876
|
+
fetchAdapter: FetchAdapter | undefined;
|
|
877
|
+
fileAdapter: FileAdapter | undefined;
|
|
878
|
+
manageFilenames: ManageFilenames;
|
|
879
|
+
/** Only applies if manageFilenames is `true`. Will _not_ truncate user-specified file names in other cases. */
|
|
880
|
+
maxFilenameLength: number;
|
|
854
881
|
namespace: string;
|
|
882
|
+
/** Ensures that wiki-style links work correctly */
|
|
883
|
+
obsidianVault: string | undefined;
|
|
884
|
+
/** Sync image, video, and audio assets to Anki's media storage system */
|
|
885
|
+
syncMediaAssets: SyncMediaAssets;
|
|
855
886
|
};
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
887
|
+
|
|
888
|
+
type CleanOptions = Pick<GlobalOptions, 'ankiConnectOptions' | 'ankiWeb' | 'dryRun' | 'namespace'>;
|
|
889
|
+
declare const defaultCleanOptions: CleanOptions;
|
|
890
|
+
type CleanResult = Simplify<{
|
|
891
|
+
deletedDecks: string[];
|
|
892
|
+
deletedMedia: string[];
|
|
893
|
+
deletedNotes: YankiNote[];
|
|
861
894
|
duration: number;
|
|
862
|
-
|
|
863
|
-
};
|
|
895
|
+
} & Pick<GlobalOptions, 'ankiWeb' | 'dryRun' | 'namespace'>>;
|
|
864
896
|
/**
|
|
865
897
|
* Deletes all remote notes in Anki associated with the given namespace.
|
|
866
898
|
*
|
|
@@ -870,15 +902,12 @@ type CleanReport = {
|
|
|
870
902
|
* @param options
|
|
871
903
|
* @throws
|
|
872
904
|
*/
|
|
873
|
-
declare function cleanNotes(options?: PartialDeep<CleanOptions>): Promise<
|
|
874
|
-
declare function
|
|
905
|
+
declare function cleanNotes(options?: PartialDeep<CleanOptions>): Promise<CleanResult>;
|
|
906
|
+
declare function formatCleanResult(result: CleanResult, verbose?: boolean): string;
|
|
875
907
|
|
|
876
|
-
type ListOptions =
|
|
877
|
-
ankiConnectOptions: YankiConnectOptions;
|
|
878
|
-
namespace: string;
|
|
879
|
-
};
|
|
908
|
+
type ListOptions = Pick<GlobalOptions, 'ankiConnectOptions' | 'namespace'>;
|
|
880
909
|
declare const defaultListOptions: ListOptions;
|
|
881
|
-
type
|
|
910
|
+
type ListResult = {
|
|
882
911
|
duration: number;
|
|
883
912
|
namespace: string;
|
|
884
913
|
notes: YankiNote[];
|
|
@@ -888,107 +917,64 @@ type ListReport = {
|
|
|
888
917
|
* @param options
|
|
889
918
|
* @returns
|
|
890
919
|
*/
|
|
891
|
-
declare function listNotes(options?: PartialDeep<ListOptions>): Promise<
|
|
892
|
-
declare function
|
|
893
|
-
|
|
894
|
-
type
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
note: YankiNote;
|
|
901
|
-
}>;
|
|
920
|
+
declare function listNotes(options?: PartialDeep<ListOptions>): Promise<ListResult>;
|
|
921
|
+
declare function formatListResult(result: ListResult): string;
|
|
922
|
+
|
|
923
|
+
type LoadOptions = Pick<GlobalOptions, 'fetchAdapter' | 'fileAdapter' | 'namespace' | 'obsidianVault' | 'syncMediaAssets'>;
|
|
924
|
+
type LocalNote = {
|
|
925
|
+
filePath: string;
|
|
926
|
+
filePathOriginal: string;
|
|
927
|
+
markdown: string;
|
|
928
|
+
note: YankiNote;
|
|
902
929
|
};
|
|
903
|
-
|
|
904
|
-
type
|
|
930
|
+
|
|
931
|
+
type RenameNotesOptions = Pick<GlobalOptions, 'dryRun' | 'fileAdapter' | 'manageFilenames' | 'maxFilenameLength'>;
|
|
932
|
+
type RenameFilesResult = {
|
|
905
933
|
dryRun: boolean;
|
|
906
|
-
|
|
907
|
-
manageFilenames: boolean;
|
|
908
|
-
maxFilenameLength: number;
|
|
909
|
-
namespace: string;
|
|
910
|
-
obsidianVault: string | undefined;
|
|
934
|
+
notes: LocalNote[];
|
|
911
935
|
};
|
|
936
|
+
type RenameFilesOptions = Simplify<LoadOptions & RenameNotesOptions>;
|
|
912
937
|
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>;
|
|
938
|
+
declare function renameFiles(allLocalFilePaths: string[], options: Partial<RenameFilesOptions>): Promise<RenameFilesResult>;
|
|
923
939
|
|
|
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;
|
|
940
|
+
type SetStyleOptions = {
|
|
933
941
|
css: string;
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
type StyleReport = {
|
|
938
|
-
ankiWeb: boolean;
|
|
939
|
-
dryRun: boolean;
|
|
942
|
+
} & Pick<GlobalOptions, 'ankiConnectOptions' | 'ankiWeb' | 'dryRun'>;
|
|
943
|
+
declare const defaultSetStyleOptions: SetStyleOptions;
|
|
944
|
+
type SetStyleResult = Simplify<{
|
|
940
945
|
duration: number;
|
|
941
946
|
models: Array<{
|
|
942
947
|
action: 'unchanged' | 'updated';
|
|
943
948
|
name: string;
|
|
944
949
|
}>;
|
|
945
|
-
}
|
|
946
|
-
|
|
947
|
-
declare
|
|
950
|
+
} & Pick<GlobalOptions, 'ankiWeb' | 'dryRun'>>;
|
|
951
|
+
type GetStyleOptions = Pick<GlobalOptions, 'ankiConnectOptions'>;
|
|
952
|
+
declare const defaultGetStyleOptions: GetStyleOptions;
|
|
953
|
+
declare function getStyle(options: PartialDeep<GetStyleOptions>): Promise<string>;
|
|
954
|
+
declare function setStyle(options?: PartialDeep<SetStyleOptions>): Promise<SetStyleResult>;
|
|
955
|
+
declare function formatSetStyleResult(result: SetStyleResult, verbose?: boolean): string;
|
|
948
956
|
|
|
949
957
|
type SyncedNote = {
|
|
950
958
|
action: 'ankiUnreachable' | 'created' | 'deleted' | 'recreated' | 'unchanged' | 'updated';
|
|
951
|
-
filePath?: string;
|
|
952
|
-
filePathOriginal?: string;
|
|
953
959
|
note: YankiNote;
|
|
954
960
|
};
|
|
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;
|
|
961
|
+
type SyncOptions = Pick<GlobalOptions, 'ankiConnectOptions' | 'ankiWeb' | 'dryRun' | 'namespace'>;
|
|
962
|
+
type SyncNotesResult = Simplify<{
|
|
978
963
|
deletedDecks: string[];
|
|
979
|
-
|
|
964
|
+
deletedMedia: string[];
|
|
980
965
|
duration: number;
|
|
981
|
-
namespace: string;
|
|
982
966
|
synced: SyncedNote[];
|
|
983
|
-
}
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
967
|
+
} & Pick<GlobalOptions, 'ankiWeb' | 'dryRun' | 'namespace'>>;
|
|
968
|
+
|
|
969
|
+
type SyncFilesOptions = Simplify<Pick<GlobalOptions, 'fetchAdapter' | 'fileAdapter' | 'manageFilenames' | 'maxFilenameLength' | 'namespace' | 'obsidianVault' | 'syncMediaAssets'> & SyncOptions>;
|
|
970
|
+
declare const defaultSyncFilesOptions: SyncFilesOptions;
|
|
971
|
+
type SyncedFile = Simplify<{
|
|
972
|
+
filePath: string | undefined;
|
|
973
|
+
filePathOriginal: string | undefined;
|
|
974
|
+
} & SyncedNote>;
|
|
975
|
+
type SyncFilesResult = Simplify<{
|
|
976
|
+
synced: SyncedFile[];
|
|
977
|
+
} & Omit<SyncNotesResult, 'synced'>>;
|
|
992
978
|
/**
|
|
993
979
|
* Sync a list of local yanki files to Anki.
|
|
994
980
|
*
|
|
@@ -1001,25 +987,19 @@ declare function syncNotes(allLocalNotes: YankiNote[], options?: PartialDeep<Syn
|
|
|
1001
987
|
* @returns The synced files (with new IDs where applicable), plus some stats
|
|
1002
988
|
* about the sync @throws
|
|
1003
989
|
*/
|
|
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
|
-
};
|
|
990
|
+
declare function syncFiles(allLocalFilePaths: string[], options?: PartialDeep<SyncFilesOptions>): Promise<SyncFilesResult>;
|
|
991
|
+
declare function formatSyncFilesResult(result: SyncFilesResult, verbose?: boolean): string;
|
|
1014
992
|
|
|
1015
993
|
/**
|
|
1016
994
|
* Turns a markdown string into a YankiNote object.
|
|
1017
995
|
*/
|
|
1018
996
|
|
|
1019
|
-
type
|
|
1020
|
-
namespace
|
|
1021
|
-
|
|
1022
|
-
|
|
997
|
+
type GetNoteFromMarkdownOptions = {
|
|
998
|
+
/** Needed for the public API, but optional for more efficient use internally when the namespace is already validated. */
|
|
999
|
+
namespaceValidationAndSanitization: boolean;
|
|
1000
|
+
} & Pick<GlobalOptions, 'cwd' | 'fetchAdapter' | 'fileAdapter' | 'namespace' | 'obsidianVault' | 'syncMediaAssets'>;
|
|
1001
|
+
declare const defaultGetNoteFromMarkdownOptions: GetNoteFromMarkdownOptions;
|
|
1002
|
+
declare function getNoteFromMarkdown(markdown: string, options?: Partial<GetNoteFromMarkdownOptions>): Promise<YankiNote>;
|
|
1023
1003
|
|
|
1024
1004
|
declare function urlToHostAndPort(url: string): {
|
|
1025
1005
|
host: string;
|
|
@@ -1027,4 +1007,4 @@ declare function urlToHostAndPort(url: string): {
|
|
|
1027
1007
|
};
|
|
1028
1008
|
declare function hostAndPortToUrl(host: string, port: number): string;
|
|
1029
1009
|
|
|
1030
|
-
export { type CleanOptions, type
|
|
1010
|
+
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-norUev7R.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};
|