mirror of
https://github.com/mara-li/obsidian-my-thesaurus.git
synced 2026-07-22 05:38:22 +00:00
Initial commit
This commit is contained in:
commit
05464c396a
26 changed files with 1387 additions and 0 deletions
10
.editorconfig
Normal file
10
.editorconfig
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
# top-most EditorConfig file
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
|
end_of_line = lf
|
||||||
|
insert_final_newline = true
|
||||||
|
indent_style = tab
|
||||||
|
indent_size = 4
|
||||||
|
tab_width = 4
|
||||||
104
.github/ISSUE_TEMPLATE/bug.yml
vendored
Normal file
104
.github/ISSUE_TEMPLATE/bug.yml
vendored
Normal file
|
|
@ -0,0 +1,104 @@
|
||||||
|
name: "Bug report"
|
||||||
|
description: Fill a bug report
|
||||||
|
title: "[Bug]: "
|
||||||
|
labels: ["bug"]
|
||||||
|
|
||||||
|
body:
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: Thanks for taking the time to fill out this bug report.
|
||||||
|
- type: checkboxes
|
||||||
|
attributes:
|
||||||
|
label: Issue validation
|
||||||
|
description: |
|
||||||
|
- Thanks to check if your issue is relative to the repository. Any non relative or duplicate issue will be closed.
|
||||||
|
- Please, check the documentation and the configuration files before submitting your request.
|
||||||
|
- Issue not in English will be closed.
|
||||||
|
options:
|
||||||
|
- label: "I checked the issue to prevent duplicate"
|
||||||
|
required: true
|
||||||
|
- label: "I checked my configurations files and the documentation"
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: describe-bug
|
||||||
|
attributes:
|
||||||
|
label: Describe the bug
|
||||||
|
description: A clear and concise description of what the bug is.
|
||||||
|
placeholder: "Tell us what you see! And don't forget the error"
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: repro-bug
|
||||||
|
attributes:
|
||||||
|
label: How to reproduce ?
|
||||||
|
description: Step to reproduce the behavior
|
||||||
|
placeholder: |
|
||||||
|
1. Go to '...'
|
||||||
|
2. Click on '....'
|
||||||
|
3. Scroll down to '....'
|
||||||
|
4. See error
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
|
- type: textarea
|
||||||
|
id: minimal-repro
|
||||||
|
attributes:
|
||||||
|
label: Minimal Reproducible Example
|
||||||
|
description: Please provide a minimal reproducible example.
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Configuration
|
||||||
|
description: |
|
||||||
|
Open the configuration settings with any text editor. The settings are located in `.obsidian/plugins/<%= data.id %>`
|
||||||
|
render: JSON
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: logs
|
||||||
|
attributes:
|
||||||
|
label: Relevant log output
|
||||||
|
description: |
|
||||||
|
Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks. You can open the Obsidian's console with "CTRL+MAJ+I."
|
||||||
|
render: bash session
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Anything else?
|
||||||
|
description: |
|
||||||
|
Links? References? Anything that will give us more context about the issue you are encountering!
|
||||||
|
Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in.
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |
|
||||||
|
## Environment
|
||||||
|
Please fill out the following information about your environment. If you are unsure about any of them, just leave it blank.
|
||||||
|
- type: dropdown
|
||||||
|
id: version
|
||||||
|
attributes:
|
||||||
|
label: OS
|
||||||
|
description: Check your OS
|
||||||
|
multiple: true
|
||||||
|
options:
|
||||||
|
- IOS
|
||||||
|
- Android
|
||||||
|
- MacOS
|
||||||
|
- Windows
|
||||||
|
- Linux
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Obsidian information
|
||||||
|
description: |
|
||||||
|
Please copy and paste the information about your Obsidian version using the command "show debug info" in the obsidian's commands palette.
|
||||||
|
render: bash session
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: input
|
||||||
|
id: plugin-version
|
||||||
|
attributes:
|
||||||
|
label: Plugin version
|
||||||
|
description: Please copy and paste the version of the plugin you are using.
|
||||||
|
placeholder: "1.0.0"
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
80
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
Normal file
80
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
Normal file
|
|
@ -0,0 +1,80 @@
|
||||||
|
name: "Feature request"
|
||||||
|
description: "Suggest an idea for this project"
|
||||||
|
title: "[FR]: "
|
||||||
|
labels: ["enhancement"]
|
||||||
|
assignees:
|
||||||
|
- Mara-Li
|
||||||
|
body:
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: Thanks for taking the time to fill out this Feature request!
|
||||||
|
- type: checkboxes
|
||||||
|
attributes:
|
||||||
|
label: Issue validation
|
||||||
|
description: |
|
||||||
|
- Thanks to check if your issue is relative to the repository. Any non relative or duplicate issue will be closed.
|
||||||
|
- Please, check the documentation and the configuration files before submitting your request.
|
||||||
|
- Issue not in English will be closed.
|
||||||
|
options:
|
||||||
|
- label: "I checked the issue to prevent duplicate"
|
||||||
|
required: true
|
||||||
|
- label: "I checked my configurations files and the documentation"
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: describe-request
|
||||||
|
attributes:
|
||||||
|
label: Is your feature related to a problem ?
|
||||||
|
description: If you found a solution with the inherent limit I had with Obsidian, please, add it here!
|
||||||
|
placeholder: "Tell me the original problem"
|
||||||
|
- type: textarea
|
||||||
|
id: describe-solution
|
||||||
|
attributes:
|
||||||
|
label: What solution do you want to see ?
|
||||||
|
description: Describe your idea here!
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: alternative
|
||||||
|
attributes:
|
||||||
|
label: Describe the alternative you've considered
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Anything else?
|
||||||
|
description: |
|
||||||
|
Links? References? Anything that will give us more context about the issue you are encountering!
|
||||||
|
Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in.
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |
|
||||||
|
## Environment
|
||||||
|
Please fill out the following information about your environment. If you are unsure about any of them, just leave it blank.
|
||||||
|
- type: dropdown
|
||||||
|
id: version
|
||||||
|
attributes:
|
||||||
|
label: OS
|
||||||
|
description: Check your OS
|
||||||
|
multiple: true
|
||||||
|
options:
|
||||||
|
- IOS
|
||||||
|
- Android
|
||||||
|
- MacOS
|
||||||
|
- Windows
|
||||||
|
- Linux
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Obsidian information
|
||||||
|
description: |
|
||||||
|
Please copy and paste the information about your Obsidian version using the command "show debug info" in the obsidian's commands palette.
|
||||||
|
render: bash session
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: input
|
||||||
|
id: plugin-version
|
||||||
|
attributes:
|
||||||
|
label: Plugin version
|
||||||
|
description: Please copy and paste the version of the plugin you are using.
|
||||||
|
placeholder: "1.0.0"
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
16
.github/workflows/auto_assign.yml
vendored
Normal file
16
.github/workflows/auto_assign.yml
vendored
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
name: Auto Assign
|
||||||
|
on:
|
||||||
|
issues:
|
||||||
|
types: [opened, edited, labeled, unlabeled]
|
||||||
|
pull_request:
|
||||||
|
types: [opened, edited, labeled, unlabeled]
|
||||||
|
jobs:
|
||||||
|
auto-assign:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: wow-actions/auto-assign@v3
|
||||||
|
with:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
reviewers: ${{github.repository_owner}}
|
||||||
|
assignees: ${{github.repository_owner}}
|
||||||
|
skipKeywords: wip, draft
|
||||||
41
.github/workflows/ci.yaml
vendored
Normal file
41
.github/workflows/ci.yaml
vendored
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
name: Release obsidian plugin
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
bump:
|
||||||
|
default: false
|
||||||
|
description: "Bump version based on semantic release"
|
||||||
|
type: boolean
|
||||||
|
required: false
|
||||||
|
beta:
|
||||||
|
default: false
|
||||||
|
description: "Make a beta release"
|
||||||
|
type: boolean
|
||||||
|
required: false
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- "*"
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
release:
|
||||||
|
if: (github.event_name == 'push') || (github.event_name == 'workflow_dispatch' && !inputs.bump)
|
||||||
|
uses: mara-li/reusable-workflows/.github/workflows/obsidian-plugin-release.yaml@main
|
||||||
|
|
||||||
|
with:
|
||||||
|
PLUGIN_NAME: <%= data.id %>
|
||||||
|
CACHE: "<%= data.packageManager %>"
|
||||||
|
secrets:
|
||||||
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
bump-version-and-release:
|
||||||
|
if: ${{ inputs.bump }}
|
||||||
|
uses: mara-li/reusable-workflows/.github/workflows/obsidian-plugin-bump-version.yaml@main
|
||||||
|
with:
|
||||||
|
PLUGIN_NAME: <%= data.id %>
|
||||||
|
BETA: ${{ inputs.beta }}
|
||||||
|
CACHE: "<%= data.packageManager %>"
|
||||||
|
secrets:
|
||||||
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
26
.gitignore
vendored
Normal file
26
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
# vscode
|
||||||
|
.vscode
|
||||||
|
|
||||||
|
# Intellij
|
||||||
|
*.iml
|
||||||
|
.idea
|
||||||
|
|
||||||
|
# npm
|
||||||
|
node_modules
|
||||||
|
|
||||||
|
# Don't include the compiled main.js file in the repo.
|
||||||
|
# They should be uploaded to GitHub releases instead.
|
||||||
|
main.js
|
||||||
|
styles.css
|
||||||
|
!src/styles.css
|
||||||
|
|
||||||
|
# Exclude sourcemaps
|
||||||
|
*.map
|
||||||
|
|
||||||
|
# obsidian
|
||||||
|
data.json
|
||||||
|
.hotreload
|
||||||
|
|
||||||
|
# Exclude macOS Finder (System Explorer) View States
|
||||||
|
.DS_Store
|
||||||
|
.env
|
||||||
3
.npmrc
Normal file
3
.npmrc
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
tag-version-prefix=""
|
||||||
|
auto-install-peers=true
|
||||||
|
enable-pre-post-scripts=true
|
||||||
33
README.md
Normal file
33
README.md
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
# <%= data.name %>
|
||||||
|
|
||||||
|
<%= data.description %>
|
||||||
|
|
||||||
|
## ⚙️ Usage
|
||||||
|
|
||||||
|
|
||||||
|
## 📥 Installation
|
||||||
|
|
||||||
|
- [ ] From Obsidian's community plugins
|
||||||
|
- [x] Using BRAT with `https://github.com/<%= data.author.name%>/<% data.id%>`
|
||||||
|
- [x] From the release page:
|
||||||
|
- Download the latest release
|
||||||
|
- Unzip `<%= data.id %>.zip` in `.obsidian/plugins/` path
|
||||||
|
- In Obsidian settings, reload the plugin
|
||||||
|
- Enable the plugin
|
||||||
|
|
||||||
|
|
||||||
|
### 🎼 Languages
|
||||||
|
|
||||||
|
- [x] English
|
||||||
|
- [ ] French
|
||||||
|
|
||||||
|
To add a translation:
|
||||||
|
1. Fork the repository
|
||||||
|
2. Add the translation in the `src/i18n/locales` folder with the name of the language (ex: `fr.json`).
|
||||||
|
- You can get your locale language from Obsidian using [obsidian translation](https://github.com/obsidianmd/obsidian-translations) or using the commands (in templater for example) : `{{TEMPLATE_PLACEHOLDER LOCALE}}`
|
||||||
|
- Copy the content of the [`en.json`](./src/i18n/locales/en.json) file in the new file
|
||||||
|
- Translate the content
|
||||||
|
3. Edit `i18n/i18next.ts` :
|
||||||
|
- Add `import * as <lang> from "./locales/<lang>.json";`
|
||||||
|
- Edit the `ressource` part with adding : `<lang> : {translation: <lang>}`
|
||||||
|
|
||||||
130
biome.json
Normal file
130
biome.json
Normal file
|
|
@ -0,0 +1,130 @@
|
||||||
|
{
|
||||||
|
"$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
|
||||||
|
"organizeImports": {
|
||||||
|
"enabled": true
|
||||||
|
},
|
||||||
|
"linter": {
|
||||||
|
"enabled": true,
|
||||||
|
"rules": {
|
||||||
|
"recommended": false,
|
||||||
|
"complexity": {
|
||||||
|
"noExtraBooleanCast": "error",
|
||||||
|
"noMultipleSpacesInRegularExpressionLiterals": "error",
|
||||||
|
"noUselessCatch": "error",
|
||||||
|
"noWith": "error"
|
||||||
|
},
|
||||||
|
"style": {
|
||||||
|
"noVar": "error",
|
||||||
|
"useFilenamingConvention": "error",
|
||||||
|
"useImportType": "error",
|
||||||
|
"useNamingConvention": {
|
||||||
|
"level": "warn",
|
||||||
|
"options": {
|
||||||
|
"strictCase": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"useTemplate": "warn",
|
||||||
|
"useConst": "error"
|
||||||
|
},
|
||||||
|
"correctness": {
|
||||||
|
"noConstAssign": "error",
|
||||||
|
"noConstantCondition": "error",
|
||||||
|
"noEmptyCharacterClassInRegex": "error",
|
||||||
|
"noEmptyPattern": "error",
|
||||||
|
"noGlobalObjectCalls": "error",
|
||||||
|
"noInnerDeclarations": "error",
|
||||||
|
"noInvalidConstructorSuper": "error",
|
||||||
|
"noNewSymbol": "error",
|
||||||
|
"noNonoctalDecimalEscape": "error",
|
||||||
|
"noPrecisionLoss": "error",
|
||||||
|
"noSelfAssign": "error",
|
||||||
|
"noSetterReturn": "error",
|
||||||
|
"noSwitchDeclarations": "error",
|
||||||
|
"noUndeclaredVariables": "error",
|
||||||
|
"noUnreachable": "error",
|
||||||
|
"noUnreachableSuper": "error",
|
||||||
|
"noUnsafeFinally": "error",
|
||||||
|
"noUnsafeOptionalChaining": "error",
|
||||||
|
"noUnusedLabels": "error",
|
||||||
|
"noUnusedVariables": "warn",
|
||||||
|
"noUnusedImports": "warn",
|
||||||
|
"useIsNan": "error",
|
||||||
|
"useValidForDirection": "error",
|
||||||
|
"useYield": "error"
|
||||||
|
},
|
||||||
|
"suspicious": {
|
||||||
|
"noAssignInExpressions": "error",
|
||||||
|
"noAsyncPromiseExecutor": "error",
|
||||||
|
"noCatchAssign": "error",
|
||||||
|
"noClassAssign": "error",
|
||||||
|
"noCompareNegZero": "error",
|
||||||
|
"noControlCharactersInRegex": "error",
|
||||||
|
"noDebugger": "error",
|
||||||
|
"noDuplicateCase": "error",
|
||||||
|
"noDuplicateClassMembers": "error",
|
||||||
|
"noDuplicateObjectKeys": "error",
|
||||||
|
"noDuplicateParameters": "error",
|
||||||
|
"noEmptyBlockStatements": "error",
|
||||||
|
"noFallthroughSwitchClause": "error",
|
||||||
|
"noFunctionAssign": "error",
|
||||||
|
"noGlobalAssign": "error",
|
||||||
|
"noImportAssign": "error",
|
||||||
|
"noMisleadingCharacterClass": "error",
|
||||||
|
"noPrototypeBuiltins": "error",
|
||||||
|
"noRedeclare": "error",
|
||||||
|
"noShadowRestrictedNames": "error",
|
||||||
|
"noUnsafeNegation": "error",
|
||||||
|
"useGetterReturn": "error",
|
||||||
|
"useValidTypeof": "error"
|
||||||
|
},
|
||||||
|
"nursery": {
|
||||||
|
"noDuplicateJsonKeys": "error"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ignore": [
|
||||||
|
"**/npm node_modules",
|
||||||
|
"**/build",
|
||||||
|
"**/dist",
|
||||||
|
"**/src/i18n/locales"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"overrides": [
|
||||||
|
{
|
||||||
|
"ignore": [
|
||||||
|
"**/*.js"
|
||||||
|
],
|
||||||
|
"include": [
|
||||||
|
"**/*.ts",
|
||||||
|
"**/*.tsx"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"include": [
|
||||||
|
"**/*.js"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"include": [
|
||||||
|
"*.json"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"formatter": {
|
||||||
|
"enabled": true,
|
||||||
|
"indentStyle": "tab",
|
||||||
|
"indentWidth": 2,
|
||||||
|
"lineWidth": 90
|
||||||
|
},
|
||||||
|
"javascript": {
|
||||||
|
"formatter": {
|
||||||
|
"quoteStyle": "double",
|
||||||
|
"semicolons": "always",
|
||||||
|
"trailingCommas": "es5"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"json": {
|
||||||
|
"formatter": {
|
||||||
|
"trailingCommas": "none"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
129
commit-and-tag-version.mjs
Normal file
129
commit-and-tag-version.mjs
Normal file
|
|
@ -0,0 +1,129 @@
|
||||||
|
import { Command, Option } from "commander";
|
||||||
|
import commitAndTagVersion from "commit-and-tag-version";
|
||||||
|
import dedent from "dedent";
|
||||||
|
import pkg from "ansi-colors";
|
||||||
|
const { red, dim, gray, italic, bold, cyan, blue, green, underline, yellow, theme } = pkg;
|
||||||
|
|
||||||
|
const program = new Command();
|
||||||
|
|
||||||
|
theme({
|
||||||
|
danger: red,
|
||||||
|
dark: dim.gray,
|
||||||
|
disabled: gray,
|
||||||
|
em: italic,
|
||||||
|
heading: bold.underline,
|
||||||
|
info: cyan,
|
||||||
|
muted: dim,
|
||||||
|
primary: blue,
|
||||||
|
strong: bold,
|
||||||
|
success: green.bold,
|
||||||
|
warning: yellow.underline,
|
||||||
|
});
|
||||||
|
|
||||||
|
const info = (msg) => pkg.info(msg);
|
||||||
|
const heading = (msg) => pkg.heading(msg);
|
||||||
|
const em = (msg) => pkg.em(msg);
|
||||||
|
|
||||||
|
program
|
||||||
|
.description("Bump version and create a new tag")
|
||||||
|
.option("-b, --beta", "Pre-release version")
|
||||||
|
.option("--dry-run", "Dry run")
|
||||||
|
.addOption(
|
||||||
|
new Option("-r, --release-as <size>", "release type version").choices([
|
||||||
|
"major",
|
||||||
|
"minor",
|
||||||
|
"patch",
|
||||||
|
])
|
||||||
|
);
|
||||||
|
|
||||||
|
program.parse();
|
||||||
|
const opt = program.opts();
|
||||||
|
|
||||||
|
const betaMsg = opt.beta ? em("- Pre-release\n\t") : "";
|
||||||
|
const dryRunMsg = opt.dryRun ? em("- Dry run\n\t") : "";
|
||||||
|
const releaseAsMsg = opt.releaseAs ? em(`- Release as ${underline(opt.releaseAs)}`) : "";
|
||||||
|
|
||||||
|
const msg = dedent(`
|
||||||
|
${heading("Options :")}
|
||||||
|
${betaMsg}${dryRunMsg}${releaseAsMsg}
|
||||||
|
`);
|
||||||
|
|
||||||
|
console.log(msg);
|
||||||
|
console.log();
|
||||||
|
|
||||||
|
if (opt.beta) {
|
||||||
|
console.log(`${bold.green(">")} ${info(underline("Bumping beta version..."))}`);
|
||||||
|
console.log();
|
||||||
|
const bumpFiles = [
|
||||||
|
{
|
||||||
|
filename: "manifest-beta.json",
|
||||||
|
type: "json",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
filename: "package.json",
|
||||||
|
type: "json",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
filename: "package-lock.json",
|
||||||
|
type: "json",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
commitAndTagVersion({
|
||||||
|
infile: "CHANGELOG-beta.md",
|
||||||
|
bumpFiles,
|
||||||
|
prerelease: "",
|
||||||
|
dryRun: opt.dryRun,
|
||||||
|
tagPrefix: "",
|
||||||
|
scripts: {
|
||||||
|
postchangelog: "node hooks/_changelog.mjs -b",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
console.log("Done");
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.error(err);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
const versionBumped = opt.releaseAs
|
||||||
|
? info(`Release as ${underline(opt.releaseAs)}`)
|
||||||
|
: info("Release");
|
||||||
|
console.log(`${bold.green(">")} ${underline(versionBumped)}`);
|
||||||
|
console.log();
|
||||||
|
|
||||||
|
const bumpFiles = [
|
||||||
|
{
|
||||||
|
filename: "manifest-beta.json",
|
||||||
|
type: "json",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
filename: "package.json",
|
||||||
|
type: "json",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
filename: "package-lock.json",
|
||||||
|
type: "json",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
filename: "manifest.json",
|
||||||
|
type: "json",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
commitAndTagVersion({
|
||||||
|
infile: "CHANGELOG.md",
|
||||||
|
bumpFiles,
|
||||||
|
dryRun: opt.dryRun,
|
||||||
|
tagPrefix: "",
|
||||||
|
releaseAs: opt.releaseAs,
|
||||||
|
scripts: {
|
||||||
|
postchangelog: "node hooks/_changelog.mjs",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
console.log("Done");
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.error(err);
|
||||||
|
});
|
||||||
|
}
|
||||||
185
esbuild.config.mjs
Normal file
185
esbuild.config.mjs
Normal file
|
|
@ -0,0 +1,185 @@
|
||||||
|
import * as fs from "fs";
|
||||||
|
import * as path from "path";
|
||||||
|
import builtins from "builtin-modules";
|
||||||
|
import { Command } from "commander";
|
||||||
|
import dotenv from "dotenv";
|
||||||
|
import esbuild from "esbuild";
|
||||||
|
import manifest from "./manifest.json" with { type: "json" };
|
||||||
|
import packageJson from "./package.json" with { type: "json" };
|
||||||
|
|
||||||
|
const banner = `/*
|
||||||
|
THIS IS A GENERATED/BUNDLED FILE BY ESBUILD
|
||||||
|
if you want to view the source, please visit the github repository of this plugin: ${packageJson.repository}
|
||||||
|
*/
|
||||||
|
`;
|
||||||
|
|
||||||
|
function cleanOutDir(outdir) {
|
||||||
|
if (fs.existsSync(outdir)) {
|
||||||
|
fs.rm(outdir, { recursive: true });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef Options
|
||||||
|
* @prop {boolean|undefined} production
|
||||||
|
* @prop {string|boolean|undefined} vault
|
||||||
|
* @prop {string|undefined} outputDir
|
||||||
|
* @prop {boolean|undefined} beta
|
||||||
|
*/
|
||||||
|
|
||||||
|
dotenv.config({ path: [".env"] });
|
||||||
|
|
||||||
|
const program = new Command();
|
||||||
|
program
|
||||||
|
.option("-p, --production", "Production build")
|
||||||
|
.option("-v, --vault [vault]", "Use vault path")
|
||||||
|
.action((v) => {
|
||||||
|
if (!v) return false;
|
||||||
|
if (typeof v === "string") return path.resolve(v.replace(/\\/g, "/"));
|
||||||
|
return process.env.VAULT;
|
||||||
|
})
|
||||||
|
.option("-o, --output-dir <path>", "Output path")
|
||||||
|
.option("-b, --beta", "Pre-release version")
|
||||||
|
.parse();
|
||||||
|
program.parse();
|
||||||
|
|
||||||
|
/** OPTIONS */
|
||||||
|
/** @type {Options} */
|
||||||
|
const opt = program.opts();
|
||||||
|
/** @type {boolean} */
|
||||||
|
const prod = opt.production ?? false;
|
||||||
|
|
||||||
|
/** VARIABLES **/
|
||||||
|
const isStyled = fs.existsSync("src/styles.css");
|
||||||
|
const pluginID = manifest.id;
|
||||||
|
|
||||||
|
/** FOLDER PATHS **/
|
||||||
|
const folderPlugin = opt.vault
|
||||||
|
? path.join(opt.vault, ".obsidian", "plugins", pluginID)
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
if (folderPlugin && !fs.existsSync(folderPlugin)) {
|
||||||
|
fs.mkdirSync(folderPlugin, { recursive: true });
|
||||||
|
}
|
||||||
|
if (opt.beta && !fs.existsSync("manifest-beta.json")) {
|
||||||
|
fs.copyFileSync("manifest.json", "manifest-beta.json");
|
||||||
|
}
|
||||||
|
|
||||||
|
let outDir = "./";
|
||||||
|
if (opt.outputDir) {
|
||||||
|
outDir = opt.outputDir;
|
||||||
|
cleanOutDir(outDir);
|
||||||
|
} else if (opt.vault) {
|
||||||
|
outDir = folderPlugin;
|
||||||
|
if (!prod) fs.writeFileSync(path.join(folderPlugin, ".hotreload"), "");
|
||||||
|
} else if (prod) {
|
||||||
|
outDir = "./dist";
|
||||||
|
//clean dist if
|
||||||
|
cleanOutDir(outDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Move styles.css to output directory
|
||||||
|
*/
|
||||||
|
const moveStyles = {
|
||||||
|
name: "move-styles",
|
||||||
|
setup(build) {
|
||||||
|
build.onEnd(() => {
|
||||||
|
fs.copyFileSync("src/styles.css", "./styles.css");
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Export to vault if set in environment variable
|
||||||
|
*/
|
||||||
|
const exportToVaultFunc = {
|
||||||
|
name: "export-to-vault",
|
||||||
|
setup(build) {
|
||||||
|
build.onEnd(() => {
|
||||||
|
if (!folderPlugin)
|
||||||
|
throw new Error("VAULT environment variable not set, skipping export to vault");
|
||||||
|
|
||||||
|
fs.copyFileSync(`${outDir}/main.js`, path.join(folderPlugin, "main.js"));
|
||||||
|
if (fs.existsSync(`${outDir}/styles.css`))
|
||||||
|
fs.copyFileSync("./styles.css", path.join(folderPlugin, "styles.css"));
|
||||||
|
if (opt.beta)
|
||||||
|
fs.copyFileSync("manifest-beta.json", path.join(folderPlugin, "manifest.json"));
|
||||||
|
else fs.copyFileSync("./manifest.json", path.join(folderPlugin, "manifest.json"));
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Export to production folder
|
||||||
|
*/
|
||||||
|
const exportToDist = {
|
||||||
|
name: "export-to-dist",
|
||||||
|
setup(build) {
|
||||||
|
build.onEnd(() => {
|
||||||
|
if (opt.beta)
|
||||||
|
fs.copyFileSync("manifest-beta.json", path.join(outDir, "manifest.json"));
|
||||||
|
else fs.copyFileSync("manifest.json", path.join(outDir, "manifest.json"));
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ENTRIES *
|
||||||
|
*/
|
||||||
|
const entryPoints = ["src/main.ts"];
|
||||||
|
if (isStyled) entryPoints.push("src/styles.css");
|
||||||
|
|
||||||
|
/** PLUGINS **/
|
||||||
|
const plugins = [];
|
||||||
|
if (isStyled) plugins.push(moveStyles);
|
||||||
|
if (prod) plugins.push(exportToDist);
|
||||||
|
if (prod && opt.vault) plugins.push(exportToVaultFunc);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BUILD
|
||||||
|
*/
|
||||||
|
const context = await esbuild.context({
|
||||||
|
banner: {
|
||||||
|
js: banner,
|
||||||
|
},
|
||||||
|
entryPoints,
|
||||||
|
bundle: true,
|
||||||
|
external: [
|
||||||
|
"obsidian",
|
||||||
|
"electron",
|
||||||
|
"@codemirror/autocomplete",
|
||||||
|
"@codemirror/collab",
|
||||||
|
"@codemirror/commands",
|
||||||
|
"@codemirror/language",
|
||||||
|
"@codemirror/lint",
|
||||||
|
"@codemirror/search",
|
||||||
|
"@codemirror/state",
|
||||||
|
"@codemirror/view",
|
||||||
|
"@lezer/common",
|
||||||
|
"@lezer/highlight",
|
||||||
|
"@lezer/lr",
|
||||||
|
...builtins,
|
||||||
|
],
|
||||||
|
format: "cjs",
|
||||||
|
target: "esnext",
|
||||||
|
logLevel: "info",
|
||||||
|
sourcemap: prod ? false : "inline",
|
||||||
|
treeShaking: true,
|
||||||
|
minifySyntax: prod,
|
||||||
|
minifyWhitespace: prod,
|
||||||
|
outdir: outDir,
|
||||||
|
plugins,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (prod) {
|
||||||
|
console.log("🎉 Build for production");
|
||||||
|
console.log(`📤 Output directory: ${outDir}`);
|
||||||
|
await context.rebuild();
|
||||||
|
console.log("✅ Build successful");
|
||||||
|
process.exit(0);
|
||||||
|
} else {
|
||||||
|
console.log("🚀 Start development build");
|
||||||
|
console.log(`📤 Output directory: ${outDir}`);
|
||||||
|
await context.watch();
|
||||||
|
}
|
||||||
302
generate.mjs
Normal file
302
generate.mjs
Normal file
|
|
@ -0,0 +1,302 @@
|
||||||
|
import c from "ansi-colors";
|
||||||
|
import ejs from "ejs";
|
||||||
|
import fs from "node:fs";
|
||||||
|
import path from "node:path";
|
||||||
|
import prompts from "prompts";
|
||||||
|
import licenses from "spdx-license-list/full.js";
|
||||||
|
import { getLicense } from "license";
|
||||||
|
import packageJson from "./package.json" assert { type: "json" };
|
||||||
|
const { dim, reset } = c;
|
||||||
|
import { execa } from "execa";
|
||||||
|
import gitUserName from "git-user-name";
|
||||||
|
c.theme({
|
||||||
|
danger: c.red,
|
||||||
|
dark: c.dim.gray,
|
||||||
|
disabled: c.gray,
|
||||||
|
em: c.italic,
|
||||||
|
heading: c.bold.underline,
|
||||||
|
info: c.cyan,
|
||||||
|
muted: c.dim,
|
||||||
|
primary: c.blue,
|
||||||
|
strong: c.bold,
|
||||||
|
success: c.green.bold,
|
||||||
|
underline: c.underline,
|
||||||
|
warning: c.yellow.underline,
|
||||||
|
});
|
||||||
|
|
||||||
|
const capitalize = (s) => {
|
||||||
|
if (typeof s !== "string") return "";
|
||||||
|
return s.charAt(0).toUpperCase() + s.slice(1);
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Render ejs file
|
||||||
|
* @param {fs.Dirent} file
|
||||||
|
*/
|
||||||
|
function ejsRender(file, data) {
|
||||||
|
const pathFiles = path.join(file.path, file.name);
|
||||||
|
const template = fs.readFileSync(pathFiles, { encoding: "utf-8" });
|
||||||
|
const processedTemplate = ejs.render(template, { data });
|
||||||
|
fs.writeFileSync(pathFiles, processedTemplate, { encoding: "utf-8" });
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateManifest(data, answer) {
|
||||||
|
const manifest = fs.readFileSync("./manifest.json", { encoding: "utf-8" });
|
||||||
|
const processedManifest = ejs.render(manifest, { data });
|
||||||
|
fs.writeFileSync("manifest.json", processedManifest, { encoding: "utf-8" });
|
||||||
|
const license = getLicense(answer.license, {
|
||||||
|
author: data.author.name,
|
||||||
|
year: new Date().getFullYear(),
|
||||||
|
});
|
||||||
|
fs.writeFileSync("LICENSE", license, { encoding: "utf-8" });
|
||||||
|
fs.writeFileSync("manifest-beta.json", processedManifest, {
|
||||||
|
encoding: "utf-8",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Get package manager
|
||||||
|
* @returns {"pnpm" | "yarn" | "npm" | "bun" | undefined}
|
||||||
|
*/
|
||||||
|
function getPackageManager() {
|
||||||
|
if (fs.existsSync("yarn.lock")) return "yarn";
|
||||||
|
if (fs.existsSync("pnpm-lock.yaml")) return "pnpm";
|
||||||
|
if (fs.existsSync("package-lock.json")) return "npm";
|
||||||
|
if (fs.existsSync("bun.lockb")) return "bun";
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
function processReadme(data) {
|
||||||
|
const readme = fs.readFileSync("./README.md", { encoding: "utf-8" });
|
||||||
|
const processedReadme = ejs.render(readme, { data });
|
||||||
|
fs.writeFileSync(
|
||||||
|
"README.md",
|
||||||
|
processedReadme.replace(
|
||||||
|
"{{TEMPLATE_PLACEHOLDER LOCALE}}",
|
||||||
|
"<% tp.obsidian.moment.locale() %>"
|
||||||
|
),
|
||||||
|
{ encoding: "utf-8" }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function processCi(data) {
|
||||||
|
const ci = fs.readFileSync("./.github/workflows/ci.yaml", {
|
||||||
|
encoding: "utf-8",
|
||||||
|
});
|
||||||
|
const processedCi = ejs.render(ci, { data });
|
||||||
|
fs.writeFileSync(".github/workflows/ci.yaml", processedCi, {
|
||||||
|
encoding: "utf-8",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function processBugReport(data) {
|
||||||
|
const path = fs.readFileSync("./.github/ISSUE_TEMPLATE/bug.yml", {
|
||||||
|
encoding: "utf-8",
|
||||||
|
});
|
||||||
|
const processedCi = ejs.render(path, { data });
|
||||||
|
fs.writeFileSync("./.github/ISSUE_TEMPLATE/bug.yml", processedCi, {
|
||||||
|
encoding: "utf-8",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function updatePackageJson(data, answer) {
|
||||||
|
packageJson.author = data.author.name;
|
||||||
|
packageJson.name = data.id;
|
||||||
|
packageJson.license = answer.license;
|
||||||
|
packageJson.description = data.description;
|
||||||
|
delete packageJson.scripts.generate;
|
||||||
|
delete packageJson.devDependencies["@types/ejs"];
|
||||||
|
delete packageJson.dependencies.ejs;
|
||||||
|
delete packageJson.dependencies.prompts;
|
||||||
|
delete packageJson.dependencies["spdx-license-list"];
|
||||||
|
delete packageJson.dependencies.execa;
|
||||||
|
delete packageJson.dependencies.license;
|
||||||
|
delete packageJson.dependencies["git-user-name"];
|
||||||
|
fs.writeFileSync("package.json", JSON.stringify(packageJson, null, 2), {
|
||||||
|
encoding: "utf-8",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Install dep based on package manager detected (using lockfile)
|
||||||
|
* @param {"pnpm" | "npm" | "yarn" | "bun" | undefined} packageManager
|
||||||
|
*/
|
||||||
|
async function updateDep(packageManager) {
|
||||||
|
switch (packageManager) {
|
||||||
|
case "yarn":
|
||||||
|
console.log(c.info("Detected yarn, running yarn install"));
|
||||||
|
//replace pnpm with yarn in package.json scripts
|
||||||
|
fs.writeFileSync(
|
||||||
|
"package.json",
|
||||||
|
fs.readFileSync("package.json", "utf-8").replace("pnpm", "yarn"),
|
||||||
|
"utf-8"
|
||||||
|
);
|
||||||
|
await execa("yarn", ["install"]);
|
||||||
|
break;
|
||||||
|
case "npm":
|
||||||
|
console.log(c.info("Detected npm, running npm install"));
|
||||||
|
fs.writeFileSync(
|
||||||
|
"package.json",
|
||||||
|
fs.readFileSync("package.json", "utf-8").replace("pnpm", "npm"),
|
||||||
|
"utf-8"
|
||||||
|
);
|
||||||
|
await execa("npm", ["install"]);
|
||||||
|
break;
|
||||||
|
case "pnpm":
|
||||||
|
console.log(c.info("Detected pnpm, running pnpm install"));
|
||||||
|
await execa("pnpm", ["install"]);
|
||||||
|
break;
|
||||||
|
case "bun":
|
||||||
|
console.log(c.info("Detected bun, running bun install"));
|
||||||
|
await execa("bun", ["install"]);
|
||||||
|
fs.writeFileSync(
|
||||||
|
"package.json",
|
||||||
|
fs.readFileSync("package.json", "utf-8").replace("pnpm", "bun"),
|
||||||
|
"utf-8"
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Error("No package manager detected, please run yarn/npm/pnpm install");
|
||||||
|
}
|
||||||
|
console.log(c.success("✅ Installed dependencies"));
|
||||||
|
}
|
||||||
|
|
||||||
|
const defaultPluginID = process
|
||||||
|
.cwd()
|
||||||
|
.split(path.sep)
|
||||||
|
.pop()
|
||||||
|
.toLowerCase()
|
||||||
|
.replaceAll(" ", "-")
|
||||||
|
.replace(/-?obsidian-?/, "");
|
||||||
|
|
||||||
|
const answer = await prompts(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
type: () => "text",
|
||||||
|
name: "id",
|
||||||
|
message: `Enter the plugin ID ${reset("(lowercase, no spaces)")}`,
|
||||||
|
initial: defaultPluginID,
|
||||||
|
format: (value) => value.toLowerCase().replaceAll(" ", "-").toLowerCase(),
|
||||||
|
validate: (value) => (value.length > 0 ? true : "Please enter a valid plugin ID"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "text",
|
||||||
|
name: "name",
|
||||||
|
message: "Enter the plugin name",
|
||||||
|
initial: (prev) =>
|
||||||
|
prev
|
||||||
|
.replace("obsidian-plugin", "")
|
||||||
|
.split("-")
|
||||||
|
.filter((word) => word.length > 0)
|
||||||
|
.map((word) => capitalize(word))
|
||||||
|
.join(" "),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "text",
|
||||||
|
name: "description",
|
||||||
|
message: "Enter the plugin description",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "text",
|
||||||
|
name: "author",
|
||||||
|
message: "Enter the author name",
|
||||||
|
initial: gitUserName(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "text",
|
||||||
|
name: "authorUrl",
|
||||||
|
message: "Enter the author URL",
|
||||||
|
initial: (prev) => `https//github.com/${prev}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "confirm",
|
||||||
|
name: "desktopOnly",
|
||||||
|
message: "Is this plugin desktop-only?",
|
||||||
|
initial: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "text",
|
||||||
|
name: "fundingUrl",
|
||||||
|
message: "Enter the funding URL",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "autocomplete",
|
||||||
|
name: "license",
|
||||||
|
message: `Choose a license ${reset(dim("(type to filter, ↑ or ↓ to navigate)"))}`,
|
||||||
|
initial: "MIT",
|
||||||
|
choices: Object.entries(licenses).map(([id, license]) => {
|
||||||
|
return {
|
||||||
|
value: id,
|
||||||
|
title: license.name,
|
||||||
|
description: (license.osiApproved && "OSI Approved") || "",
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
{
|
||||||
|
onCancel: () => {
|
||||||
|
console.log(c.warning("❌ Generation cancelled"));
|
||||||
|
process.exit(0);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
/**
|
||||||
|
* Readd recursive sync
|
||||||
|
* @param {string} dir
|
||||||
|
* @returns {fs.Dirent[]}
|
||||||
|
*/
|
||||||
|
function readdirRecursiveSync(dir) {
|
||||||
|
const results = [];
|
||||||
|
|
||||||
|
function readDirRecursive(currentPath) {
|
||||||
|
const entries = fs.readdirSync(currentPath, { withFileTypes: true });
|
||||||
|
|
||||||
|
for (const entry of entries) {
|
||||||
|
const fullPath = path.join(currentPath, entry.name);
|
||||||
|
if (entry.isDirectory()) {
|
||||||
|
readDirRecursive(fullPath);
|
||||||
|
} else {
|
||||||
|
results.push(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
readDirRecursive(dir);
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
const templateFiles = readdirRecursiveSync("./src");
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
name: answer.name || "Sample Plugin",
|
||||||
|
id: answer.id || "sample-plugin",
|
||||||
|
description: answer.description || "This is a sample plugin",
|
||||||
|
interfaceName: answer.name.replaceAll(" ", "") || "SamplePlugin",
|
||||||
|
author: {
|
||||||
|
url: answer.authorUrl || "",
|
||||||
|
name: answer.author || "Sample Author",
|
||||||
|
},
|
||||||
|
isDesktopOnly: !!answer.desktopOnly || false,
|
||||||
|
packageManager: getPackageManager(),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (answer.fundingUrl) {
|
||||||
|
data.fundingUrl = answer.fundingUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const file of templateFiles) {
|
||||||
|
ejsRender(file, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateManifest(data, answer);
|
||||||
|
processReadme(data);
|
||||||
|
processCi(data);
|
||||||
|
processBugReport(data);
|
||||||
|
console.log(c.success("✅ Generated ") + c.info("all files"));
|
||||||
|
|
||||||
|
//update package.json
|
||||||
|
updatePackageJson(data, answer);
|
||||||
|
//create hotreload file
|
||||||
|
fs.writeFileSync(".hotreload", "", { encoding: "utf-8" });
|
||||||
|
|
||||||
|
//detect if yarn or npm or pnpm
|
||||||
|
await updateDep(data.packageManager);
|
||||||
|
|
||||||
|
//delete this files
|
||||||
|
fs.unlinkSync("generate.mjs");
|
||||||
30
hooks/_changelog.mjs
Normal file
30
hooks/_changelog.mjs
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
import { readFileSync, writeFile } from "fs";
|
||||||
|
|
||||||
|
import { Command } from "commander";
|
||||||
|
const program = new Command();
|
||||||
|
|
||||||
|
program.option("-b, --beta", "Pre-release version");
|
||||||
|
|
||||||
|
program.parse();
|
||||||
|
const opt = program.opts();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove text from the file
|
||||||
|
* @param {string} path
|
||||||
|
*/
|
||||||
|
function removeText(path) {
|
||||||
|
const toRemove = [
|
||||||
|
"# Changelog",
|
||||||
|
"All notable changes to this project will be documented in this file. See [commit-and-tag-version](https://github.com/absolute-version/commit-and-tag-version) for commit guidelines.",
|
||||||
|
];
|
||||||
|
let changelog = readFileSync(path, "utf8");
|
||||||
|
for (const remove of toRemove) changelog = changelog.replace(remove, "").trim();
|
||||||
|
changelog = changelog.replaceAll(/[\n\r]{3,}/gm, "\n\n").trim();
|
||||||
|
changelog = changelog.replaceAll(/## (.*)[\n\r]{2}### /gm, "## $1\n### ").trim();
|
||||||
|
writeFile(path, changelog.trim(), "utf8", (err) => {
|
||||||
|
if (err) return console.error(err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!opt.beta) removeText("CHANGELOG.md");
|
||||||
|
else removeText("CHANGELOG-beta.md");
|
||||||
14
manifest.json
Normal file
14
manifest.json
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
{
|
||||||
|
"id": "<%= data.id %>",
|
||||||
|
"name": "<%= data.name %>",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"minAppVersion": "1.5.12",
|
||||||
|
"description": "<%= data.description %>",
|
||||||
|
"author": "<%= data.author.name %>",
|
||||||
|
"authorUrl": "<%= data.author.url %>",
|
||||||
|
<%_ if (data.fundingURL) { _%>
|
||||||
|
"fundingUrl": "<%= data.fundingURL %>",
|
||||||
|
<%_
|
||||||
|
} _%>
|
||||||
|
"isDesktopOnly": <%= data.isDesktopOnly %>
|
||||||
|
}
|
||||||
54
package.json
Normal file
54
package.json
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
{
|
||||||
|
"name": "sample-plugin",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "main.js",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"prebuild": "tsc --noEmit --skipLibCheck",
|
||||||
|
"build": "node esbuild.config.mjs --production",
|
||||||
|
"dev:prod": "node esbuild.config.mjs --vault",
|
||||||
|
"dev": "node esbuild.config.mjs",
|
||||||
|
"export": "node esbuild.config.mjs --production --vault",
|
||||||
|
"bump": "dotenv -- node commit-and-tag-version.mjs",
|
||||||
|
"postbump": "dotenv -- if-env SKIP_POST_BUMP=true && echo skip bump || git push --follow-tags origin master",
|
||||||
|
"predeploy": "pnpm run bump",
|
||||||
|
"deploy": "pnpm run export",
|
||||||
|
"lint": "pnpm biome format --write src/"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^22.2.0"
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "",
|
||||||
|
"license": "MIT",
|
||||||
|
"devDependencies": {
|
||||||
|
"@biomejs/biome": "1.8.1",
|
||||||
|
"@types/node": "^16.11.6",
|
||||||
|
"builtin-modules": "4.0.0",
|
||||||
|
"i18next": "^23.16.4",
|
||||||
|
"esbuild": "0.21.5",
|
||||||
|
"obsidian": "latest",
|
||||||
|
"tslib": "2.6.3",
|
||||||
|
"typescript": "latest"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@delucis/if-env": "^1.1.2",
|
||||||
|
"ansi-colors": "^4.1.3",
|
||||||
|
"commander": "^12.1.0",
|
||||||
|
"commit-and-tag-version": "^12.4.1",
|
||||||
|
"dedent": "^1.5.3",
|
||||||
|
"dotenv": "^16.4.5",
|
||||||
|
"dotenv-cli": "^7.4.2",
|
||||||
|
"ejs": "^3.1.10",
|
||||||
|
"execa": "^9.5.2",
|
||||||
|
"git-user-name": "^2.0.0",
|
||||||
|
"license": "^1.0.3",
|
||||||
|
"prompts": "^2.4.2",
|
||||||
|
"spdx-license-list": "^6.9.0"
|
||||||
|
},
|
||||||
|
"trustedDependencies": [
|
||||||
|
"@biomejs/biome",
|
||||||
|
"esbuild"
|
||||||
|
]
|
||||||
|
}
|
||||||
8
src/i18n/i18next.d.ts
vendored
Normal file
8
src/i18n/i18next.d.ts
vendored
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
import type { resources } from "../i18n";
|
||||||
|
|
||||||
|
declare module "i18next" {
|
||||||
|
interface CustomTypeOptions {
|
||||||
|
readonly resources: (typeof resources)["en"];
|
||||||
|
readonly returnNull: false;
|
||||||
|
}
|
||||||
|
}
|
||||||
12
src/i18n/index.ts
Normal file
12
src/i18n/index.ts
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
import { moment } from "obsidian";
|
||||||
|
|
||||||
|
import en from "./locales/en.json";
|
||||||
|
//import fr from "./locales/fr.json";
|
||||||
|
|
||||||
|
|
||||||
|
export const resources = {
|
||||||
|
//fr: {translation: fr},
|
||||||
|
en: {translation: en}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const translationLanguage = Object.keys(resources).find(i => i.toLocaleLowerCase() == moment.locale()) ? moment.locale() : "en";
|
||||||
0
src/i18n/locales/en.json
Normal file
0
src/i18n/locales/en.json
Normal file
9
src/interfaces.ts
Normal file
9
src/interfaces.ts
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
|
||||||
|
|
||||||
|
export interface <%= data.interfaceName %>Settings {
|
||||||
|
mySetting: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const DEFAULT_SETTINGS: <%= data.interfaceName %>Settings = {
|
||||||
|
mySetting: "default"
|
||||||
|
};
|
||||||
98
src/main.ts
Normal file
98
src/main.ts
Normal file
|
|
@ -0,0 +1,98 @@
|
||||||
|
import { type Editor, MarkdownView, Notice, Plugin, Modal } from "obsidian";
|
||||||
|
import { resources, translationLanguage } from "./i18n";
|
||||||
|
import i18next from "i18next";
|
||||||
|
|
||||||
|
import { <%= data.interfaceName %>SettingTab } from "./settings";
|
||||||
|
import { <%= data.interfaceName%>Modal } from "./modals";
|
||||||
|
import { <%= data.interfaceName%>Settings, DEFAULT_SETTINGS } from "./interfaces";
|
||||||
|
|
||||||
|
export default class <%= data.interfaceName %> extends Plugin {
|
||||||
|
settings!: <%= data.interfaceName %>Settings;
|
||||||
|
|
||||||
|
async onload() {
|
||||||
|
console.log(`[${this.manifest.name}] Loaded`)
|
||||||
|
await this.loadSettings();
|
||||||
|
//load i18next
|
||||||
|
await i18next.init({
|
||||||
|
lng: translationLanguage,
|
||||||
|
fallbackLng: "en",
|
||||||
|
resources,
|
||||||
|
returnNull: false,
|
||||||
|
returnEmptyString: false,
|
||||||
|
});
|
||||||
|
// This creates an icon in the left ribbon.
|
||||||
|
const ribbonIconEl = this.addRibbonIcon("dice", "Sample Plugin", (_evt: MouseEvent) => {
|
||||||
|
// Called when the user clicks the icon.
|
||||||
|
new Notice("This is a notice!");
|
||||||
|
});
|
||||||
|
// Perform additional things with the ribbon
|
||||||
|
ribbonIconEl.addClass("my-plugin-ribbon-class");
|
||||||
|
|
||||||
|
// This adds a status bar item to the bottom of the app. Does not work on mobile apps.
|
||||||
|
const statusBarItemEl = this.addStatusBarItem();
|
||||||
|
statusBarItemEl.setText("Status Bar Text");
|
||||||
|
|
||||||
|
// This adds a simple command that can be triggered anywhere
|
||||||
|
this.addCommand({
|
||||||
|
id: "open-sample-modal-simple",
|
||||||
|
name: "Open sample modal (simple)",
|
||||||
|
callback: () => {
|
||||||
|
new <%= data.interfaceName%>Modal(this.app).open();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// This adds an editor command that can perform some operation on the current editor instance
|
||||||
|
this.addCommand({
|
||||||
|
id: "sample-editor-command",
|
||||||
|
name: "Sample editor command",
|
||||||
|
editorCallback: (editor: Editor, _view: MarkdownView|MarkdownFileInfo) => {
|
||||||
|
console.log(editor.getSelection());
|
||||||
|
editor.replaceSelection("Sample Editor Command");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// This adds a complex command that can check whether the current state of the app allows execution of the command
|
||||||
|
this.addCommand({
|
||||||
|
id: "open-sample-modal-complex",
|
||||||
|
name: "Open sample modal (complex)",
|
||||||
|
checkCallback: (checking: boolean) => {
|
||||||
|
// Conditions to check
|
||||||
|
const markdownView = this.app.workspace.getActiveViewOfType(MarkdownView);
|
||||||
|
if (markdownView) {
|
||||||
|
// If checking is true, we're simply "checking" if the command can be run.
|
||||||
|
// If checking is false, then we want to actually perform the operation.
|
||||||
|
if (!checking) {
|
||||||
|
new <%= DataTransferItem={}.name%>Modal(this.app).open();
|
||||||
|
}
|
||||||
|
|
||||||
|
// This command will only show up in Command Palette when the check function returns true
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// This adds a settings tab so the user can configure various aspects of the plugin
|
||||||
|
this.addSettingTab(new <%= data.interfaceName %>SettingTab(this.app, this));
|
||||||
|
|
||||||
|
// If the plugin hooks up any global DOM events (on parts of the app that doesn't belong to this plugin)
|
||||||
|
// Using this function will automatically remove the event listener when this plugin is disabled.
|
||||||
|
this.registerDomEvent(document, "click", (evt: MouseEvent) => {
|
||||||
|
console.log("click", evt);
|
||||||
|
});
|
||||||
|
|
||||||
|
// When registering intervals, this function will automatically clear the interval when the plugin is disabled.
|
||||||
|
this.registerInterval(window.setInterval(() => console.log("setInterval"), 5 * 60 * 1000));
|
||||||
|
}
|
||||||
|
|
||||||
|
onunload() {
|
||||||
|
console.log(`[${this.manifest.name}] Unloaded`);
|
||||||
|
}
|
||||||
|
|
||||||
|
async loadSettings() {
|
||||||
|
this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());
|
||||||
|
}
|
||||||
|
|
||||||
|
async saveSettings() {
|
||||||
|
await this.saveData(this.settings);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
17
src/modals.ts
Normal file
17
src/modals.ts
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
import { type App, Modal } from "obsidian";
|
||||||
|
|
||||||
|
export class <%= data.interfaceName%>Modal extends Modal {
|
||||||
|
constructor(app: App) {
|
||||||
|
super(app);
|
||||||
|
}
|
||||||
|
|
||||||
|
onOpen() {
|
||||||
|
const {contentEl} = this;
|
||||||
|
contentEl.setText("Woah!");
|
||||||
|
}
|
||||||
|
|
||||||
|
onClose() {
|
||||||
|
const {contentEl} = this;
|
||||||
|
contentEl.empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
28
src/settings.ts
Normal file
28
src/settings.ts
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
import { type App, PluginSettingTab, Setting } from "obsidian";
|
||||||
|
import <%= data.interfaceName %> from "./main";
|
||||||
|
|
||||||
|
export class <%= data.interfaceName %>SettingTab extends PluginSettingTab {
|
||||||
|
plugin: <%= data.interfaceName %>;
|
||||||
|
|
||||||
|
constructor(app: App, plugin: <%= data.interfaceName %>) {
|
||||||
|
super(app, plugin);
|
||||||
|
this.plugin = plugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
display(): void {
|
||||||
|
const {containerEl} = this;
|
||||||
|
|
||||||
|
containerEl.empty();
|
||||||
|
|
||||||
|
new Setting(containerEl)
|
||||||
|
.setName("Setting #1")
|
||||||
|
.setDesc("It's a secret")
|
||||||
|
.addText(text => text
|
||||||
|
.setPlaceholder("Enter your secret")
|
||||||
|
.setValue(this.plugin.settings.mySetting)
|
||||||
|
.onChange(async (value) => {
|
||||||
|
this.plugin.settings.mySetting = value;
|
||||||
|
await this.plugin.saveSettings();
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
8
src/styles.css
Normal file
8
src/styles.css
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
/*
|
||||||
|
|
||||||
|
This CSS file will be included with your plugin, and
|
||||||
|
available in the app when your plugin is enabled.
|
||||||
|
|
||||||
|
If your plugin does not need CSS, delete this file.
|
||||||
|
|
||||||
|
*/
|
||||||
33
tsconfig.json
Normal file
33
tsconfig.json
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"noEmit": true,
|
||||||
|
"baseUrl": ".",
|
||||||
|
"inlineSourceMap": true,
|
||||||
|
"inlineSources": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
|
"strict": true,
|
||||||
|
"module": "ESNext",
|
||||||
|
"target": "ESNext",
|
||||||
|
"allowJs": true,
|
||||||
|
"noImplicitAny": true,
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"importHelpers": true,
|
||||||
|
"isolatedModules": true,
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"strictNullChecks": true,
|
||||||
|
"lib": [
|
||||||
|
"DOM",
|
||||||
|
"ES5",
|
||||||
|
"ES6",
|
||||||
|
"ES7",
|
||||||
|
"ES2015",
|
||||||
|
"ES2021",
|
||||||
|
"ES2022",
|
||||||
|
"DOM.Iterable"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"**/*.ts"
|
||||||
|
]
|
||||||
|
}
|
||||||
14
version-bump.mjs
Normal file
14
version-bump.mjs
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
import { readFileSync, writeFileSync } from "fs";
|
||||||
|
|
||||||
|
const targetVersion = process.env.npm_package_version;
|
||||||
|
|
||||||
|
// read minAppVersion from manifest.json and bump version to target version
|
||||||
|
let manifest = JSON.parse(readFileSync("manifest.json", "utf8"));
|
||||||
|
const { minAppVersion } = manifest;
|
||||||
|
manifest.version = targetVersion;
|
||||||
|
writeFileSync("manifest.json", JSON.stringify(manifest, null, "\t"));
|
||||||
|
|
||||||
|
// update versions.json with target version and minAppVersion from manifest.json
|
||||||
|
let versions = JSON.parse(readFileSync("versions.json", "utf8"));
|
||||||
|
versions[targetVersion] = minAppVersion;
|
||||||
|
writeFileSync("versions.json", JSON.stringify(versions, null, "\t"));
|
||||||
3
versions.json
Normal file
3
versions.json
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"1.0.0": "0.15.0"
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue