# Plugin: CodeScript Toolkit

**URL:** <https://forum.obsidian.md/t/plugin-codescript-toolkit/94399>\
**Category:** Plugins\
**Tags:** plugin-release\
**Created:** [January 6, 2025, 6:59pm UTC](https://forum.obsidian.md/t/plugin-codescript-toolkit/94399 "2025-01-06T18:59:47Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![mnaoumov](https://forum.obsidian.md/user_avatar/forum.obsidian.md/mnaoumov/32/22325_2.png) [@mnaoumov](https://forum.obsidian.md/u/mnaoumov)\
**Post date:** [January 6, 2025, 6:59pm UTC](https://forum.obsidian.md/t/plugin-codescript-toolkit/94399/1 "2025-01-06T18:59:47Z")

</div>

> **[GitHub - mnaoumov/obsidian-codescript-toolkit: Plugin for Obsidian that allows to do a lot of...](https://github.com/mnaoumov/obsidian-codescript-toolkit)**
>
> Plugin for Obsidian that allows to do a lot of things with JavaScript/TypeScript scripts from inside the Obsidian itself

(formerly known as `Fix Require Modules`)

This plugin is meant for the developers and other code writers. If you find the purpose of the plugin is not clear enough, I would be more than welcome to accept the PR to improve the `README`

---

<div class="post-metadata">

**Author:** ![Yurcee](https://forum.obsidian.md/user_avatar/forum.obsidian.md/yurcee/32/53074_2.png) [@Yurcee](https://forum.obsidian.md/u/Yurcee)\
**Post date:** [January 30, 2025, 12:32am UTC](https://forum.obsidian.md/t/plugin-codescript-toolkit/94399/2 "2025-01-30T00:32:32Z")

</div>

Started porting my Templater scripts and User Plugins js scripts over to be used by your plugin today.

Reasons for doing so:

- Templater’s annoying ‘Create’ and ‘Insert’ duplications. I always want to use ‘Insert’ and have to double check which one to fire when script is not among those added a key combo (running out of combos on Windows too) or not pinned on Command Palette (I don’t like it too long).
  - I also was in the habit of naming ‘Template’ my Templater scripts that are not even Templates – what a stupid thing to do – enough is enough…

- User Plugins have some quirks and bugs I am tired of working around or unable to do so.
- Too lazy to compile my own plugins and I certainly don’t want to take on 20-30 extra plugins when they are scripts doing usually simple enough custom stuff only.

On a personal note, Mikhael is one of my most liked developers, not only for his intuitive solutions, but his all-around availability.

I recommend checking out his other actively maintained plugins as well.

Cheers

---

<div class="post-metadata">

**Author:** ![mnaoumov](https://forum.obsidian.md/user_avatar/forum.obsidian.md/mnaoumov/32/22325_2.png) [@mnaoumov](https://forum.obsidian.md/u/mnaoumov)\
**Post date:** [January 30, 2025, 12:49am UTC](https://forum.obsidian.md/t/plugin-codescript-toolkit/94399/3 "2025-01-30T00:49:46Z")

</div>

It is possible to avoid duplication between `Create` and `Insert` using one template with according check

---

<div class="post-metadata">

**Author:** ![Yurcee](https://forum.obsidian.md/user_avatar/forum.obsidian.md/yurcee/32/53074_2.png) [@Yurcee](https://forum.obsidian.md/u/Yurcee)\
**Post date:** [January 30, 2025, 1:01am UTC](https://forum.obsidian.md/t/plugin-codescript-toolkit/94399/4 "2025-01-30T01:01:35Z")

</div>

Not sure I follow you. A conditional? How would Templater know what I would want to use the script as? Never heard of this.

This is how I differentiate them:  
 ![{48FFE2A1-C1EC-41F7-9033-E04FC643F717}](https://forum.obsidian.md/uploads/default/original/3X/e/1/e1a1d86bc035ff886e3ade119acc8dc3ca27bc35.png)  
So I can see the ones with the (not yet learnt shortcut), that they are the Insert ones.

---

<div class="post-metadata">

**Author:** ![mnaoumov](https://forum.obsidian.md/user_avatar/forum.obsidian.md/mnaoumov/32/22325_2.png) [@mnaoumov](https://forum.obsidian.md/u/mnaoumov)\
**Post date:** [January 30, 2025, 1:42am UTC](https://forum.obsidian.md/t/plugin-codescript-toolkit/94399/5 "2025-01-30T01:42:34Z")

</div>

You are right. I confused with another thing I used. Sorry

---

<div class="post-metadata">

**Author:** ![Yurcee](https://forum.obsidian.md/user_avatar/forum.obsidian.md/yurcee/32/53074_2.png) [@Yurcee](https://forum.obsidian.md/u/Yurcee)\
**Post date:** [January 30, 2025, 11:24pm UTC](https://forum.obsidian.md/t/plugin-codescript-toolkit/94399/6 "2025-01-30T23:24:09Z")

</div>

I was not very keen to use Templater as I didn’t want to take on a liability and Obsidian API is enough.  
But I was still trying to find a way to use the Templater functionality.  
Once I managed to find a solution with Claude (VSCode Copilot), I had it write up a guide.

@mnaoumov Please comment if you find anything wrong in it:

### Guide: Adding Templater Functionality to TypeScript Scripts

##### Key Components:

1. **Interface Definition**

Here’s a comprehensive list of available Templater functions we can add to the interface:

```typescript
interface TemplaterPlugin {
    templater: {
        current_functions_object: {
            app: any;
            date: {
                now: (format: string) => Promise<string>;
                tomorrow: (format?: string) => Promise<string>;
                yesterday: (format?: string) => Promise<string>;
                weekday: (format?: string, weekday?: number) => Promise<string>;
            };
            file: {
                path: (full?: boolean) => string;
                folder: (full?: boolean) => string;
                title: string;
                selection: () => string;
                tags: string[];
                creation_date: (format?: string) => Promise<string>;
                last_modified_date: (format?: string) => Promise<string>;
                move: (path: string) => Promise<void>;
                rename: (newName: string) => Promise<void>;
                find_tfile: (path: string) => TFile | null;
                include: (path: string) => Promise<string>;
                cursor: (order?: number) => number;
                cursor_append: (content: string) => void;
                exists: (path: string) => boolean;
                create_new: (template: string, filename: string, open?: boolean) => Promise<void>;
            };
            frontmatter: {
                [key: string]: any;
            };
            system: {
                clipboard: () => Promise<string>;
                prompt: (prompt_text: string, default_value?: string, throw_on_cancel?: boolean) => Promise<string>;
                suggester: <T>(
                    text_items: ((item: T) => string) | string[],
                    items: T[],
                    throw_on_cancel?: boolean,
                    placeholder?: string,
                    limit?: boolean
                ) => Promise<T>;
            };
            web: {
                daily_quote: () => Promise<string>;
                random_picture: () => Promise<string>;
                request: (url: string) => Promise<any>;
            };
            obsidian: {
                // Access to Obsidian API
                [key: string]: any;
            };
            user: {
                // Custom user scripts
                [key: string]: any;
            };
        };
    };
}

```

Key Functions Available:

1. **Date Functions** :

2. **File Operations** :

3. **System Interactions** :

4. **Web Functions** :

5. **Meta Functions** :

Example Usage:

```typescript
// Get user input
const userInput = await tp.system.prompt("Enter value");

// Use suggester for selection
const selected = await tp.system.suggester(
    items => items.display,
    items
);

// Include another template
const content = await tp.file.include("path/to/template.md");

// Create new file from template
await tp.file.create_new("template.md", "New File", true);

```

1. **Accessing Templater**

```typescript
const templaterPlugin = app.plugins.plugins['templater-obsidian'] as any;
const tp = templaterPlugin?.templater?.current_functions_object;

// Check availability
if (!tp?.date?.now) {
    console.error("Required Templater functions not found!");
    return;
}

```

##### Common Templater Functions:

```typescript
// Dates
const getDate = async () => await tp.date.now("YYYY-MM-DD[T]HH:mm");

// Files
const getCurrentFile = () => tp.file.find_tfile(tp.file.path(true));

// System
const userInput = await tp.system.prompt("Enter value");
const selected = await tp.system.suggester(
    items => items.display, 
    items
);

```

##### Best Practices:

1. Always wrap in error handling:

```typescript
try {
    const date = await tp.date.now(format);
} catch (error) {
    console.error("Templater error:", error);
    // Provide fallback
    return moment().format(format);
}

```

1. Check for plugin availability:

```typescript
if (!app.plugins.plugins['templater-obsidian']) {
    console.error("Templater plugin not found!");
    return;
}

```

1. Use Promise wrapper for mobile compatibility:

```typescript
return new Promise<void>(async (resolve) => {
    try {
        // Templater code here
    } catch (error) {
        console.error('Error:', error);
    } finally {
        resolve();
    }
});

```

##### Example Template:

```typescript
import { App, Plugin, TFile } from 'obsidian';

interface TemplaterPlugin {
    templater: {
        current_functions_object: {
            // Add needed functions
        };
    };
}

async function yourFunction(app: App): Promise<void> {
    return new Promise<void>(async (resolve) => {
        try {
            const templaterPlugin = app.plugins.plugins['templater-obsidian'] as any;
            const tp = templaterPlugin?.templater?.current_functions_object;
            
            if (!tp) {
                console.error("Templater not found!");
                return resolve();
            }

            // Your code using tp functions

        } catch (error) {
            console.error('Error:', error);
        } finally {
            resolve();
        }
    });
}

// ...existing Plugin class and invoke function...

```

##### Common Gotchas:

Templater functions are async - use await  
Functions might be unavailable - always check  
Mobile needs Promise wrapper  
Use fallbacks for critical functions

---

<div class="post-metadata">

**Author:** ![mnaoumov](https://forum.obsidian.md/user_avatar/forum.obsidian.md/mnaoumov/32/22325_2.png) [@mnaoumov](https://forum.obsidian.md/u/mnaoumov)\
**Post date:** [January 31, 2025, 12:36am UTC](https://forum.obsidian.md/t/plugin-codescript-toolkit/94399/7 "2025-01-31T00:36:37Z")

</div>

@Yurcee there are many places that I would consider wrong here

1. Typings of `TemplaterPlugin` are not correct. I will provide the correct typings in a bit
2. You are not using those typings later on

```ts
const templaterPlugin = app.plugins.plugins['templater-obsidian'] as TemplaterPlugin;

```

1. I would not recommend using `TemplaterPlugin` outside of `Templater`. For example, it won’t be initialized if you try to use it before any templates were running.

2. `Use Promise wrapper for mobile compatibility` is an anti-pattern, it’s quite bad to use `async` inside `Promise` constructor

The correct way is

```ts
const asyncFn = async () => {
  // ...
};
const promise = asyncFn();
return promise;

```

---

<div class="post-metadata">

**Author:** ![mnaoumov](https://forum.obsidian.md/user_avatar/forum.obsidian.md/mnaoumov/32/22325_2.png) [@mnaoumov](https://forum.obsidian.md/u/mnaoumov)\
**Post date:** [January 31, 2025, 1:10am UTC](https://forum.obsidian.md/t/plugin-codescript-toolkit/94399/8 "2025-01-31T01:10:36Z")

</div>

```ts
import * as obsidian from 'obsidian';
import {
  App,
  TFile,
  TFolder,
} from 'obsidian';

enum RunMode {
  CreateNewFromTemplate,
  AppendActiveFile,
  OverwriteFile,
  OverwriteActiveFile,
  DynamicProcessor,
  StartupTemplate,
}

interface TemplaterPlugin {
  templater: {
    current_functions_object: {
      app: App;
      config: {
        active_file: TFile;
        run_mode: RunMode;
        target_file: TFile;
        template_file: TFile;
      };
      date: {
        // default format is 'YYYY-MM-DD'
        now(format?: string, offset?: number | string, reference?: string, reference_format?: string): string;
        tomorrow(format?: string): string;
        weekday(format?: string, weekday?: number, reference?: string, reference_format?: string): string;
        yesterday(format?: string): string;
      };
      file: {
        content: string;
        tags: string[];
        title: string;
        create_new(template: TFile | string, filename?: string, open_new?: boolean, folder?: TFolder | string): Promise<TFile | undefined>;
        // default format is 'YYYY-MM-DD HH:mm'
        creation_date(format?: string): string;
        cursor(order?: number): string;
        cursor_append(content: string): string | undefined;
        exists(filepath: string): Promise<boolean>;
        find_tfile(filename: string): TFile | null;
        folder(absolute?: boolean): string;
        include(include_link: string | TFile): Promise<string>;
        // default format is 'YYYY-MM-DD HH:mm'
        last_modified_date(format?: string): string;
        move(new_path: string, file_to_move?: TFile): Promise<string>;
        path(relative: boolean): string;
        rename(new_title: string): Promise<string>;
        selection(): string;
      };
      frontmatter: Record<string, unknown>;
      hooks: {
        on_all_templates_executed(callback_function: () => unknown): void;
      };
      obsidian: typeof obsidian;
      system: {
        clipboard(): Promise<string | null>;
        prompt(prompt_text?: string, default_value?: string, throw_on_cancel?: boolean, multiline?: boolean): Promise<string | null>;
        suggester<T>(text_items: string[] | ((item: T) => string), items: T[], throw_on_cancel?: boolean, placeholder?: string, limit?: number): Promise<T>;
      };
      user: Record<string, unknown>;
      web: {
        daily_quote(): Promise<string>;
        random_picture(size?: string, query?: string, include_size?: boolean): Promise<string>;
        request(url: string, path?: string): Promise<string>;
      };
    };
  };
}

```

---

<div class="post-metadata">

**Author:** ![Yurcee](https://forum.obsidian.md/user_avatar/forum.obsidian.md/yurcee/32/53074_2.png) [@Yurcee](https://forum.obsidian.md/u/Yurcee)\
**Post date:** [January 31, 2025, 1:24am UTC](https://forum.obsidian.md/t/plugin-codescript-toolkit/94399/9 "2025-01-31T01:24:36Z")

</div>

> [@mnaoumov](#):
>
> before any templates were running

Yeah, that’s why an empty Templater template is advisable to run for this purpose on startup. I mean even for normal js scripts, for Templater function availability.

> [@mnaoumov](#):
>
> `Use Promise wrapper for mobile compatibility` is an anti-pattern

Then I’ll need to fix that for mobile compatibility even for scripts I didn’t use Templater for (so far only one and I kept the non-Templater version ts file for backup). That’s important, yes, even for Templater js.

Thanks very much for commenting on this on short notice.

Cheers

---

<div class="post-metadata">

**Author:** ![Yurcee](https://forum.obsidian.md/user_avatar/forum.obsidian.md/yurcee/32/53074_2.png) [@Yurcee](https://forum.obsidian.md/u/Yurcee)\
**Post date:** [January 31, 2025, 8:02pm UTC](https://forum.obsidian.md/t/plugin-codescript-toolkit/94399/10 "2025-01-31T20:02:49Z")

</div>

As far as I can see, currently, only one startup script is allowed:

 ![{4E027E7A-8182-4B75-AE28-9EAB47C5D1AE}](https://forum.obsidian.md/uploads/default/original/3X/9/7/9720625a9579cb0a1e6a54615645b892eaae0d91.png)

Would be better (if it’s possbile) if we just specified the folder and anything in that folder would be loaded on startup.  
(My example scripts on the screenshot are not actual startup files – I just added two random files there.)

---

<div class="post-metadata">

**Author:** ![mnaoumov](https://forum.obsidian.md/user_avatar/forum.obsidian.md/mnaoumov/32/22325_2.png) [@mnaoumov](https://forum.obsidian.md/u/mnaoumov)\
**Post date:** [January 31, 2025, 8:17pm UTC](https://forum.obsidian.md/t/plugin-codescript-toolkit/94399/11 "2025-01-31T20:17:15Z")

</div>

Yes, you have only one startup script, but you can call from it all others

**`startup/main.ts`**

```ts
import { invoke as freezeDataView } from './Freeze DataView.ts';
import { invoke as redoLastCommand } from './RedoLastCommand.ts';

export async function invoke(app: App): Promise<void> {
  await freezeDataView(app);
  await redoLastCommand(app);
}

```

---

<div class="post-metadata">

**Author:** ![Yurcee](https://forum.obsidian.md/user_avatar/forum.obsidian.md/yurcee/32/53074_2.png) [@Yurcee](https://forum.obsidian.md/u/Yurcee)\
**Post date:** [January 31, 2025, 8:17pm UTC](https://forum.obsidian.md/t/plugin-codescript-toolkit/94399/12 "2025-01-31T20:17:48Z")

</div>

Will do, thanks!

---

<div class="post-metadata">

**Author:** ![mnaoumov](https://forum.obsidian.md/user_avatar/forum.obsidian.md/mnaoumov/32/22325_2.png) [@mnaoumov](https://forum.obsidian.md/u/mnaoumov)\
**Post date:** [January 31, 2025, 8:21pm UTC](https://forum.obsidian.md/t/plugin-codescript-toolkit/94399/13 "2025-01-31T20:21:29Z")

</div>

This way, you will have a better control over the execution order.

And additionally, this forum is not the best place for the BUG/FEATURE REQUESTS. For better maintainability, they are better be added to `GitHub`

---

<div class="post-metadata">

**Author:** ![Yurcee](https://forum.obsidian.md/user_avatar/forum.obsidian.md/yurcee/32/53074_2.png) [@Yurcee](https://forum.obsidian.md/u/Yurcee)\
**Post date:** [January 31, 2025, 8:23pm UTC](https://forum.obsidian.md/t/plugin-codescript-toolkit/94399/14 "2025-01-31T20:23:02Z")

</div>

> [@mnaoumov](#):
>
> this forum is not the best place

Right.  
Was just trying to raise awareness of the plugin a bit more.

Cheers

---

<div class="post-metadata">

**Author:** ![Abisheik](https://forum.obsidian.md/user_avatar/forum.obsidian.md/abisheik/32/46914_2.png) [@Abisheik](https://forum.obsidian.md/u/Abisheik)\
**Post date:** [July 16, 2025, 9:00pm UTC](https://forum.obsidian.md/t/plugin-codescript-toolkit/94399/15 "2025-07-16T21:00:58Z")

</div>

This plugin needs way more eyes on it, I feel. You can literally make Obsidian do anything you want with it. Plus the developer is so responsive on GitHub; literally every feature I’ve wanted has been added\[1\].

* * *

1. And _very_ quickly from the times I’ve posted the feature requests, too.

---

<div class="post-metadata">

**Author:** ![Abisheik](https://forum.obsidian.md/user_avatar/forum.obsidian.md/abisheik/32/46914_2.png) [@Abisheik](https://forum.obsidian.md/u/Abisheik)\
**Post date:** [July 16, 2025, 9:04pm UTC](https://forum.obsidian.md/t/plugin-codescript-toolkit/94399/16 "2025-07-16T21:04:50Z")

</div>

I’ve used this plugin to replace QuickAdd, Templater, Dataview, and Advanced URI for myself so far. And also used it to copy some functions from Supercharged Links into it so I could use them to get Supercharged Links styling on links in some plugin views that are unsupported by Supercharged Links. It’s amazing.

---

<div class="post-metadata">

**Author:** ![Yurcee](https://forum.obsidian.md/user_avatar/forum.obsidian.md/yurcee/32/53074_2.png) [@Yurcee](https://forum.obsidian.md/u/Yurcee)\
**Post date:** [July 31, 2025, 4:16pm UTC](https://forum.obsidian.md/t/plugin-codescript-toolkit/94399/17 "2025-07-31T16:16:25Z")

</div>

> [@Abisheik](#):
>
> to replace QuickAdd, Templater, Dataview,

Indeed, Dataview basically works on top of the Obsidian metadatacache and not friendly with string (context) searches. I stopped using `dv.io.load` a long time ago and use Obsidian API only (which the 2025 bots know about or can scour the docs) and basically made my own search script with any prop filter without Dataview.  
It’s just that average users cannot go down this path and I speak from experience that even when you give them a complete tutorial how to do something, they do not even answer. I mean I hardly ever use the built-in search of Obsidian anymore.  
Every single time a more complex search is to be entered, you’re gonna check the Help how to do it and you cannot even see what you are adding in that small bar…? Wow, I mean it’s 2025…

So again, thanks to the developer I have 50 custom scripts with modals for my own PKM.

---

<div class="post-metadata">

**Author:** ![Abisheik](https://forum.obsidian.md/user_avatar/forum.obsidian.md/abisheik/32/46914_2.png) [@Abisheik](https://forum.obsidian.md/u/Abisheik)\
**Post date:** [July 31, 2025, 5:33pm UTC](https://forum.obsidian.md/t/plugin-codescript-toolkit/94399/18 "2025-07-31T17:33:43Z")

</div>

> [@Yurcee](#):
>
> basically made my own search script with any prop filter without Dataview.

Ah, interesting. The direction I went was moving all inline [key:: value] pairs to frontmatter\[1\] and editing my scripts that add inline (key:: value) pairs to instead add the properties to frontmatter/YAML\[2\] and then add a more human readable text “inline”\[3\].

So, now I can use the regular Obsidian search.

```query
[Spent (dollars)] restaurant

```

* * *

1. Programmatically, of course. 

2. Via app.metadataCache.getFileCache and app.fileManager.processFrontMatter. 

3. Just to the content of the note.

---

<div class="post-metadata">

**Author:** ![LVNACY](https://forum.obsidian.md/user_avatar/forum.obsidian.md/lvnacy/32/77970_2.png) [@LVNACY](https://forum.obsidian.md/u/LVNACY)\
**Post date:** [August 8, 2025, 9:17pm UTC](https://forum.obsidian.md/t/plugin-codescript-toolkit/94399/19 "2025-08-08T21:17:30Z")

</div>

To some extent, I think I can grasp how to replace Templater with this plugin. Is the migration from dataview simple? I use dataview predominantly to manage tasks and render dashboard elements. I’ve been holding out for Datacore, but if this plugin can replace the dataview plugin without a whole lot of work, I’ll just migrate to using only this.

---

<div class="post-metadata">

**Author:** ![Abisheik](https://forum.obsidian.md/user_avatar/forum.obsidian.md/abisheik/32/46914_2.png) [@Abisheik](https://forum.obsidian.md/u/Abisheik)\
**Post date:** [August 8, 2025, 9:43pm UTC](https://forum.obsidian.md/t/plugin-codescript-toolkit/94399/20 "2025-08-08T21:43:54Z")

</div>

I guess that depends on your proficiency with TypeScript or JavaScript… It took me a couple _weeks_ to replace everything and I definitely didn’t re-make _all_ of Dataview’s things; just my own uses of it/DataviewJS… Had to make various scripts and functions… Here’s my script that renders a table in markdown, for example. CodeScript Toolkit’s `code-button` blocks in `raw` mode are great.

```js
async function renderTable(container, thisFile, heading, cols, rows) {
	const wrapper = document.createElement('div');
	wrapper.style.marginBottom = '1.5em';
	if (heading.length) await MarkdownRenderer.render(app, heading, wrapper, thisFile.path, null);

	const md = [
		`| ${cols.join(' | ')} |`,
		`| ${cols.map(() => '---').join(' | ')} |`,
		...rows.map(r => `| ${r.join(' | ')} |`)
	].join('\n');

	const tableDiv = document.createElement('div');
	await MarkdownRenderer.render(app, md, tableDiv, thisFile.path, null);
	wrapper.appendChild(tableDiv);
	container?.appendChild(wrapper);
}
exports.renderTable = renderTable;

```

[Next page](https://forum.obsidian.md/t/plugin-codescript-toolkit/94399.md?page=2)
