This commit is contained in:
vrabe 2025-05-15 02:41:42 +08:00
parent e52a51c6f8
commit 02d7f54fba
No known key found for this signature in database
GPG key ID: 6A5083B90DD60877
15 changed files with 551 additions and 0 deletions

9
.editorconfig Normal file
View file

@ -0,0 +1,9 @@
root = true
[*]
end_of_line = lf
indent_style = space
indent_size = 2
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

24
.gitignore vendored Normal file
View file

@ -0,0 +1,24 @@
# 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
# Exclude sourcemaps
*.map
# obsidian
data.json
# Exclude macOS Finder (System Explorer) View States
.DS_Store
src/cjk-characters.js

1
.npmrc Normal file
View file

@ -0,0 +1 @@
tag-version-prefix=""

26
.prettierignore Normal file
View 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
# Exclude sourcemaps
*.map
# obsidian
data.json
# Exclude macOS Finder (System Explorer) View States
.DS_Store
pnpm-lock.yaml
src/cjk-characters.js

8
.prettierrc.js Normal file
View file

@ -0,0 +1,8 @@
export default {
printWidth: 100,
semi: true,
singleQuote: false,
jsxSingleQuote: false,
trailingComma: "es5",
tabWidth: 2,
};

33
esbuild.config.js Normal file
View file

@ -0,0 +1,33 @@
import esbuild from "esbuild";
import process from "process";
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
*/
`;
const prod = process.argv[2] === "production";
const context = await esbuild.context({
banner: {
js: banner,
},
entryPoints: ["src/index.js"],
bundle: true,
external: ["obsidian"],
format: "cjs",
target: "es2018",
logLevel: "info",
sourcemap: prod ? false : "inline",
treeShaking: true,
outfile: "main.js",
minify: prod,
});
if (prod) {
await context.rebuild();
process.exit(0);
} else {
await context.watch();
}

10
jsconfig.json Normal file
View file

@ -0,0 +1,10 @@
{
"compilerOptions": {
"baseUrl": ".",
"module": "ESNext",
"target": "ES6",
"moduleResolution": "node",
"lib": ["DOM", "ES5", "ES6", "ES7"]
},
"include": ["**/*"]
}

10
manifest.json Normal file
View file

@ -0,0 +1,10 @@
{
"id": "cjk-count",
"name": "CJK Count",
"version": "1.0.0",
"minAppVersion": "1.8.10",
"description": "A word count plugin that only counts Chinese, Japanese and Korean (CJK) characters.",
"author": "vrabe",
"authorUrl": "https://vrabe.tw",
"isDesktopOnly": true
}

23
package.json Normal file
View file

@ -0,0 +1,23 @@
{
"name": "obsidian-cjk-count",
"version": "1.0.0",
"description": "A word count Obsidian plugin that only counts Chinese, Japanese and Korean (CJK) characters.",
"main": "main.js",
"type": "module",
"scripts": {
"dev": "node esbuild.config.js",
"build": "node esbuild.config.js production",
"version": "node version-bump.js && git add manifest.json versions.json",
"generate": "node src/scripts/generate-cjk-characters.js",
"format": "prettier -w --cache ."
},
"keywords": [],
"author": "",
"license": "MIT",
"devDependencies": {
"cjk-regex": "^3.3.0",
"esbuild": "0.17.3",
"obsidian": "^1.8.7",
"prettier": "^3.5.3"
}
}

352
pnpm-lock.yaml Normal file
View file

@ -0,0 +1,352 @@
lockfileVersion: '9.0'
settings:
autoInstallPeers: true
excludeLinksFromLockfile: false
importers:
.:
devDependencies:
cjk-regex:
specifier: ^3.3.0
version: 3.3.0
esbuild:
specifier: 0.17.3
version: 0.17.3
obsidian:
specifier: ^1.8.7
version: 1.8.7(@codemirror/state@6.5.2)(@codemirror/view@6.36.7)
prettier:
specifier: ^3.5.3
version: 3.5.3
packages:
'@codemirror/state@6.5.2':
resolution: {integrity: sha512-FVqsPqtPWKVVL3dPSxy8wEF/ymIEuVzF1PK3VbUgrxXpJUSHQWWZz4JMToquRxnkw+36LTamCZG2iua2Ptq0fA==}
'@codemirror/view@6.36.7':
resolution: {integrity: sha512-kCWGW/chWGPgZqfZ36Um9Iz0X2IVpmCjg1P/qY6B6a2ecXtWRRAigmpJ6YgUQ5lTWXMyyVdfmpzhLZmsZQMbtg==}
'@esbuild/android-arm64@0.17.3':
resolution: {integrity: sha512-XvJsYo3dO3Pi4kpalkyMvfQsjxPWHYjoX4MDiB/FUM4YMfWcXa5l4VCwFWVYI1+92yxqjuqrhNg0CZg3gSouyQ==}
engines: {node: '>=12'}
cpu: [arm64]
os: [android]
'@esbuild/android-arm@0.17.3':
resolution: {integrity: sha512-1Mlz934GvbgdDmt26rTLmf03cAgLg5HyOgJN+ZGCeP3Q9ynYTNMn2/LQxIl7Uy+o4K6Rfi2OuLsr12JQQR8gNg==}
engines: {node: '>=12'}
cpu: [arm]
os: [android]
'@esbuild/android-x64@0.17.3':
resolution: {integrity: sha512-nuV2CmLS07Gqh5/GrZLuqkU9Bm6H6vcCspM+zjp9TdQlxJtIe+qqEXQChmfc7nWdyr/yz3h45Utk1tUn8Cz5+A==}
engines: {node: '>=12'}
cpu: [x64]
os: [android]
'@esbuild/darwin-arm64@0.17.3':
resolution: {integrity: sha512-01Hxaaat6m0Xp9AXGM8mjFtqqwDjzlMP0eQq9zll9U85ttVALGCGDuEvra5Feu/NbP5AEP1MaopPwzsTcUq1cw==}
engines: {node: '>=12'}
cpu: [arm64]
os: [darwin]
'@esbuild/darwin-x64@0.17.3':
resolution: {integrity: sha512-Eo2gq0Q/er2muf8Z83X21UFoB7EU6/m3GNKvrhACJkjVThd0uA+8RfKpfNhuMCl1bKRfBzKOk6xaYKQZ4lZqvA==}
engines: {node: '>=12'}
cpu: [x64]
os: [darwin]
'@esbuild/freebsd-arm64@0.17.3':
resolution: {integrity: sha512-CN62ESxaquP61n1ZjQP/jZte8CE09M6kNn3baos2SeUfdVBkWN5n6vGp2iKyb/bm/x4JQzEvJgRHLGd5F5b81w==}
engines: {node: '>=12'}
cpu: [arm64]
os: [freebsd]
'@esbuild/freebsd-x64@0.17.3':
resolution: {integrity: sha512-feq+K8TxIznZE+zhdVurF3WNJ/Sa35dQNYbaqM/wsCbWdzXr5lyq+AaTUSER2cUR+SXPnd/EY75EPRjf4s1SLg==}
engines: {node: '>=12'}
cpu: [x64]
os: [freebsd]
'@esbuild/linux-arm64@0.17.3':
resolution: {integrity: sha512-JHeZXD4auLYBnrKn6JYJ0o5nWJI9PhChA/Nt0G4MvLaMrvXuWnY93R3a7PiXeJQphpL1nYsaMcoV2QtuvRnF/g==}
engines: {node: '>=12'}
cpu: [arm64]
os: [linux]
'@esbuild/linux-arm@0.17.3':
resolution: {integrity: sha512-CLP3EgyNuPcg2cshbwkqYy5bbAgK+VhyfMU7oIYyn+x4Y67xb5C5ylxsNUjRmr8BX+MW3YhVNm6Lq6FKtRTWHQ==}
engines: {node: '>=12'}
cpu: [arm]
os: [linux]
'@esbuild/linux-ia32@0.17.3':
resolution: {integrity: sha512-FyXlD2ZjZqTFh0sOQxFDiWG1uQUEOLbEh9gKN/7pFxck5Vw0qjWSDqbn6C10GAa1rXJpwsntHcmLqydY9ST9ZA==}
engines: {node: '>=12'}
cpu: [ia32]
os: [linux]
'@esbuild/linux-loong64@0.17.3':
resolution: {integrity: sha512-OrDGMvDBI2g7s04J8dh8/I7eSO+/E7nMDT2Z5IruBfUO/RiigF1OF6xoH33Dn4W/OwAWSUf1s2nXamb28ZklTA==}
engines: {node: '>=12'}
cpu: [loong64]
os: [linux]
'@esbuild/linux-mips64el@0.17.3':
resolution: {integrity: sha512-DcnUpXnVCJvmv0TzuLwKBC2nsQHle8EIiAJiJ+PipEVC16wHXaPEKP0EqN8WnBe0TPvMITOUlP2aiL5YMld+CQ==}
engines: {node: '>=12'}
cpu: [mips64el]
os: [linux]
'@esbuild/linux-ppc64@0.17.3':
resolution: {integrity: sha512-BDYf/l1WVhWE+FHAW3FzZPtVlk9QsrwsxGzABmN4g8bTjmhazsId3h127pliDRRu5674k1Y2RWejbpN46N9ZhQ==}
engines: {node: '>=12'}
cpu: [ppc64]
os: [linux]
'@esbuild/linux-riscv64@0.17.3':
resolution: {integrity: sha512-WViAxWYMRIi+prTJTyV1wnqd2mS2cPqJlN85oscVhXdb/ZTFJdrpaqm/uDsZPGKHtbg5TuRX/ymKdOSk41YZow==}
engines: {node: '>=12'}
cpu: [riscv64]
os: [linux]
'@esbuild/linux-s390x@0.17.3':
resolution: {integrity: sha512-Iw8lkNHUC4oGP1O/KhumcVy77u2s6+KUjieUqzEU3XuWJqZ+AY7uVMrrCbAiwWTkpQHkr00BuXH5RpC6Sb/7Ug==}
engines: {node: '>=12'}
cpu: [s390x]
os: [linux]
'@esbuild/linux-x64@0.17.3':
resolution: {integrity: sha512-0AGkWQMzeoeAtXQRNB3s4J1/T2XbigM2/Mn2yU1tQSmQRmHIZdkGbVq2A3aDdNslPyhb9/lH0S5GMTZ4xsjBqg==}
engines: {node: '>=12'}
cpu: [x64]
os: [linux]
'@esbuild/netbsd-x64@0.17.3':
resolution: {integrity: sha512-4+rR/WHOxIVh53UIQIICryjdoKdHsFZFD4zLSonJ9RRw7bhKzVyXbnRPsWSfwybYqw9sB7ots/SYyufL1mBpEg==}
engines: {node: '>=12'}
cpu: [x64]
os: [netbsd]
'@esbuild/openbsd-x64@0.17.3':
resolution: {integrity: sha512-cVpWnkx9IYg99EjGxa5Gc0XmqumtAwK3aoz7O4Dii2vko+qXbkHoujWA68cqXjhh6TsLaQelfDO4MVnyr+ODeA==}
engines: {node: '>=12'}
cpu: [x64]
os: [openbsd]
'@esbuild/sunos-x64@0.17.3':
resolution: {integrity: sha512-RxmhKLbTCDAY2xOfrww6ieIZkZF+KBqG7S2Ako2SljKXRFi+0863PspK74QQ7JpmWwncChY25JTJSbVBYGQk2Q==}
engines: {node: '>=12'}
cpu: [x64]
os: [sunos]
'@esbuild/win32-arm64@0.17.3':
resolution: {integrity: sha512-0r36VeEJ4efwmofxVJRXDjVRP2jTmv877zc+i+Pc7MNsIr38NfsjkQj23AfF7l0WbB+RQ7VUb+LDiqC/KY/M/A==}
engines: {node: '>=12'}
cpu: [arm64]
os: [win32]
'@esbuild/win32-ia32@0.17.3':
resolution: {integrity: sha512-wgO6rc7uGStH22nur4aLFcq7Wh86bE9cOFmfTr/yxN3BXvDEdCSXyKkO+U5JIt53eTOgC47v9k/C1bITWL/Teg==}
engines: {node: '>=12'}
cpu: [ia32]
os: [win32]
'@esbuild/win32-x64@0.17.3':
resolution: {integrity: sha512-FdVl64OIuiKjgXBjwZaJLKp0eaEckifbhn10dXWhysMJkWblg3OEEGKSIyhiD5RSgAya8WzP3DNkngtIg3Nt7g==}
engines: {node: '>=12'}
cpu: [x64]
os: [win32]
'@marijn/find-cluster-break@1.0.2':
resolution: {integrity: sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g==}
'@types/codemirror@5.60.8':
resolution: {integrity: sha512-VjFgDF/eB+Aklcy15TtOTLQeMjTo07k7KAjql8OK5Dirr7a6sJY4T1uVBDuTVG9VEmn1uUsohOpYnVfgC6/jyw==}
'@types/estree@1.0.7':
resolution: {integrity: sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==}
'@types/tern@0.23.9':
resolution: {integrity: sha512-ypzHFE/wBzh+BlH6rrBgS5I/Z7RD21pGhZ2rltb/+ZrVM1awdZwjx7hE5XfuYgHWk9uvV5HLZN3SloevCAp3Bw==}
cjk-regex@3.3.0:
resolution: {integrity: sha512-o9QeA4DIiljRGO3mXzkQXBttzE6XRGZG99V9F8uqrdqKo5RHTFe8w+pk1aOMB/wxQ7qQ8J7WoTagabTabPgl8A==}
engines: {node: '>=16'}
esbuild@0.17.3:
resolution: {integrity: sha512-9n3AsBRe6sIyOc6kmoXg2ypCLgf3eZSraWFRpnkto+svt8cZNuKTkb1bhQcitBcvIqjNiK7K0J3KPmwGSfkA8g==}
engines: {node: '>=12'}
hasBin: true
moment@2.29.4:
resolution: {integrity: sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==}
obsidian@1.8.7:
resolution: {integrity: sha512-h4bWwNFAGRXlMlMAzdEiIM2ppTGlrh7uGOJS6w4gClrsjc+ei/3YAtU2VdFUlCiPuTHpY4aBpFJJW75S1Tl/JA==}
peerDependencies:
'@codemirror/state': ^6.0.0
'@codemirror/view': ^6.0.0
prettier@3.5.3:
resolution: {integrity: sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==}
engines: {node: '>=14'}
hasBin: true
regexp-util@2.0.3:
resolution: {integrity: sha512-GP6h9OgJmhAZpb3dbNbXTfRWVnGcoMhWRZv/HxgM4/qCVqs1P9ukQdYxaUhjWBSAs9oJ/uPXUUvGT1VMe0Bs0Q==}
engines: {node: '>=16'}
style-mod@4.1.2:
resolution: {integrity: sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw==}
unicode-regex@4.1.2:
resolution: {integrity: sha512-30Y3tQ8OUxceQjsEJHzNh20lLYZX6ZwQyUOHBUdN1UPKQWH3AvH20aUADWa1gEz2lQPTSQ/l2ZqdM4FjFNMJsQ==}
engines: {node: '>=16'}
w3c-keyname@2.2.8:
resolution: {integrity: sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==}
snapshots:
'@codemirror/state@6.5.2':
dependencies:
'@marijn/find-cluster-break': 1.0.2
'@codemirror/view@6.36.7':
dependencies:
'@codemirror/state': 6.5.2
style-mod: 4.1.2
w3c-keyname: 2.2.8
'@esbuild/android-arm64@0.17.3':
optional: true
'@esbuild/android-arm@0.17.3':
optional: true
'@esbuild/android-x64@0.17.3':
optional: true
'@esbuild/darwin-arm64@0.17.3':
optional: true
'@esbuild/darwin-x64@0.17.3':
optional: true
'@esbuild/freebsd-arm64@0.17.3':
optional: true
'@esbuild/freebsd-x64@0.17.3':
optional: true
'@esbuild/linux-arm64@0.17.3':
optional: true
'@esbuild/linux-arm@0.17.3':
optional: true
'@esbuild/linux-ia32@0.17.3':
optional: true
'@esbuild/linux-loong64@0.17.3':
optional: true
'@esbuild/linux-mips64el@0.17.3':
optional: true
'@esbuild/linux-ppc64@0.17.3':
optional: true
'@esbuild/linux-riscv64@0.17.3':
optional: true
'@esbuild/linux-s390x@0.17.3':
optional: true
'@esbuild/linux-x64@0.17.3':
optional: true
'@esbuild/netbsd-x64@0.17.3':
optional: true
'@esbuild/openbsd-x64@0.17.3':
optional: true
'@esbuild/sunos-x64@0.17.3':
optional: true
'@esbuild/win32-arm64@0.17.3':
optional: true
'@esbuild/win32-ia32@0.17.3':
optional: true
'@esbuild/win32-x64@0.17.3':
optional: true
'@marijn/find-cluster-break@1.0.2': {}
'@types/codemirror@5.60.8':
dependencies:
'@types/tern': 0.23.9
'@types/estree@1.0.7': {}
'@types/tern@0.23.9':
dependencies:
'@types/estree': 1.0.7
cjk-regex@3.3.0:
dependencies:
regexp-util: 2.0.3
unicode-regex: 4.1.2
esbuild@0.17.3:
optionalDependencies:
'@esbuild/android-arm': 0.17.3
'@esbuild/android-arm64': 0.17.3
'@esbuild/android-x64': 0.17.3
'@esbuild/darwin-arm64': 0.17.3
'@esbuild/darwin-x64': 0.17.3
'@esbuild/freebsd-arm64': 0.17.3
'@esbuild/freebsd-x64': 0.17.3
'@esbuild/linux-arm': 0.17.3
'@esbuild/linux-arm64': 0.17.3
'@esbuild/linux-ia32': 0.17.3
'@esbuild/linux-loong64': 0.17.3
'@esbuild/linux-mips64el': 0.17.3
'@esbuild/linux-ppc64': 0.17.3
'@esbuild/linux-riscv64': 0.17.3
'@esbuild/linux-s390x': 0.17.3
'@esbuild/linux-x64': 0.17.3
'@esbuild/netbsd-x64': 0.17.3
'@esbuild/openbsd-x64': 0.17.3
'@esbuild/sunos-x64': 0.17.3
'@esbuild/win32-arm64': 0.17.3
'@esbuild/win32-ia32': 0.17.3
'@esbuild/win32-x64': 0.17.3
moment@2.29.4: {}
obsidian@1.8.7(@codemirror/state@6.5.2)(@codemirror/view@6.36.7):
dependencies:
'@codemirror/state': 6.5.2
'@codemirror/view': 6.36.7
'@types/codemirror': 5.60.8
moment: 2.29.4
prettier@3.5.3: {}
regexp-util@2.0.3: {}
style-mod@4.1.2: {}
unicode-regex@4.1.2:
dependencies:
regexp-util: 2.0.3
w3c-keyname@2.2.8: {}

2
pnpm-workspace.yaml Normal file
View file

@ -0,0 +1,2 @@
onlyBuiltDependencies:
- esbuild

32
src/index.js Normal file
View file

@ -0,0 +1,32 @@
import { MarkdownView, Plugin } from "obsidian";
import CJKCharacters from "./cjk-characters";
export default class CJKCountPlugin extends Plugin {
#statusBarItemEl;
async onload() {
this.#statusBarItemEl = this.addStatusBarItem();
this.#statusBarItemEl.setText("0 字");
this.registerEvent(
this.app.workspace.on("file-open", () => setTimeout(() => this.#updateCount(), 100))
);
this.registerEvent(this.app.workspace.on("editor-change", () => this.#updateCount()));
this.#updateCount();
}
#updateCount() {
const activeView = this.app.workspace.getActiveViewOfType(MarkdownView);
let characterCount = 0;
if (activeView) {
const content = activeView.editor.getValue();
const characters = content.match(new RegExp(CJKCharacters, "g"));
characterCount = characters ? characters.length : 0;
}
this.#statusBarItemEl.setText(`${characterCount}`);
}
}

View file

@ -0,0 +1,4 @@
import { writeFile } from "node:fs/promises";
import { letters as CJKCharacters } from "cjk-regex";
writeFile("src/cjk-characters.js", `export default "${CJKCharacters().toString()}";`);

14
version-bump.js Normal file
View 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
View file

@ -0,0 +1,3 @@
{
"1.0.0": "0.15.0"
}