ts-abbr-skill 1.0.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/README.md ADDED
@@ -0,0 +1,102 @@
1
+ # ts-abbr-skill
2
+
3
+ <p align="center">
4
+ <img src="assets/logo.png" alt="ts-abbr-skill" width="480">
5
+ </p>
6
+
7
+ <p align="center">
8
+ <a href="README.zh-CN.md">đŸ‡¨đŸ‡ŗ įŽ€äŊ“中文</a> |
9
+ <a href="README.md">đŸ‡ē🇸 English</a>
10
+ </p>
11
+
12
+ <p align="center">
13
+ <a href="https://github.com/aShu-guo/ts-abbreviation-skill/releases"><img src="https://img.shields.io/github/v/release/aShu-guo/ts-abbreviation-skill?style=for-the-badge&color=blue" alt="GitHub Release"></a>
14
+ <a href="https://www.npmjs.com/package/ts-abbr-skill"><img src="https://img.shields.io/npm/v/ts-abbr-skill?style=for-the-badge&logo=npm&color=red" alt="npm version"></a>
15
+ <a href="https://github.com/aShu-guo/ts-abbreviation-skill/blob/main/LICENSE"><img src="https://img.shields.io/github/license/aShu-guo/ts-abbreviation-skill?style=for-the-badge&color=green" alt="License"></a>
16
+ </p>
17
+
18
+ <p align="center">
19
+ <a href="https://www.npmjs.com/package/ts-abbr-skill"><img src="https://img.shields.io/npm/dm/ts-abbr-skill?style=flat-square&label=downloads" alt="npm downloads"></a>
20
+ <a href="https://github.com/aShu-guo/ts-abbreviation-skill/stargazers"><img src="https://img.shields.io/github/stars/aShu-guo/ts-abbreviation-skill?style=flat-square&logo=github" alt="GitHub stars"></a>
21
+ </p>
22
+
23
+ A Claude Code skill that makes generated/refactored TypeScript naming follow a shared abbreviation dictionary (`business` → `biz`, `context` → `ctx`, `configuration` → `cfg`, ...) instead of verbose full words.
24
+
25
+ ## Install
26
+
27
+ ```bash
28
+ npx ts-abbr-skill
29
+ ```
30
+
31
+ You'll be asked where to install:
32
+
33
+ - **Project** — `./.claude/skills/ts-abbr-skill/` (recommended for team-shared conventions, commit this to your repo)
34
+ - **Global** — `~/.claude/skills/ts-abbr-skill/` (applies to all your projects)
35
+
36
+ Both can be selected at once. Re-running the installer is safe: your customized `config/default.config.json` and `dictionary/default.json` are never overwritten.
37
+
38
+ ## What it does
39
+
40
+ - **When generating new code**: Claude checks the abbreviation dictionary before naming local variables/parameters and uses the abbreviated form when a match exists.
41
+ - **When refactoring existing code**: batch renames go through an AST-aware rename script (`ts-morph`-based), never plain-text find/replace, so cross-file references stay correct. A `tsc --noEmit` check is required afterward before the rename is considered done.
42
+
43
+ See [`skill/SKILL.md`](skill/SKILL.md) for the full rules Claude follows.
44
+
45
+ ## Built-in Dictionary (excerpt)
46
+
47
+ | Full word | Abbreviation |
48
+ |-----------|--------------|
49
+ | business | biz |
50
+ | context | ctx |
51
+ | configuration / config | cfg |
52
+ | parameter / parameters | param / params |
53
+ | response | res |
54
+ | request | req |
55
+ | temporary | tmp |
56
+ | reference | ref |
57
+ | element | el |
58
+ | repository | repo |
59
+ | service | svc |
60
+ | database | db |
61
+ | application | app |
62
+ | ... | ... |
63
+
64
+ Full dictionary: [`skill/dictionary/default.json`](skill/dictionary/default.json)
65
+
66
+ ## Customize
67
+
68
+ **Scope** — edit `<install target>/config/default.config.json`:
69
+
70
+ ```json
71
+ { "scope": ["variable", "parameter"], "exported": false }
72
+ ```
73
+
74
+ `scope` accepts `variable`, `parameter`, `localFunction`, `class`. `exported` controls whether public/exported symbols are eligible (default `false`).
75
+
76
+ **Project-specific additions** — add `.claude/ts-abbr.local.json` at your repo root; entries are merged on top of the default dictionary:
77
+
78
+ ```json
79
+ {
80
+ "warehouse": "wh",
81
+ "department": "dept"
82
+ }
83
+ ```
84
+
85
+ ## Development
86
+
87
+ ```bash
88
+ npm install
89
+ npm run build # bundles src/cli.ts -> dist/cli.js
90
+ node dist/cli.js # try the installer locally
91
+ ```
92
+
93
+ For iterating on skill content, use a symlink instead of rebuilding:
94
+
95
+ ```bash
96
+ ln -sfn /path/to/ts-abbreviation-skill/skill \
97
+ your-test-project/.claude/skills/ts-abbr-skill
98
+ ```
99
+
100
+ ## License
101
+
102
+ MIT
@@ -0,0 +1,102 @@
1
+ # ts-abbr-skill
2
+
3
+ <p align="center">
4
+ <img src="assets/logo.png" alt="ts-abbr-skill" width="480">
5
+ </p>
6
+
7
+ <p align="center">
8
+ <a href="README.zh-CN.md">đŸ‡¨đŸ‡ŗ įŽ€äŊ“中文</a> |
9
+ <a href="README.md">đŸ‡ē🇸 English</a>
10
+ </p>
11
+
12
+ <p align="center">
13
+ <a href="https://github.com/aShu-guo/ts-abbreviation-skill/releases"><img src="https://img.shields.io/github/v/release/aShu-guo/ts-abbreviation-skill?style=for-the-badge&color=blue" alt="GitHub Release"></a>
14
+ <a href="https://www.npmjs.com/package/ts-abbr-skill"><img src="https://img.shields.io/npm/v/ts-abbr-skill?style=for-the-badge&logo=npm&color=red" alt="npm version"></a>
15
+ <a href="https://github.com/aShu-guo/ts-abbreviation-skill/blob/main/LICENSE"><img src="https://img.shields.io/github/license/aShu-guo/ts-abbreviation-skill?style=for-the-badge&color=green" alt="License"></a>
16
+ </p>
17
+
18
+ <p align="center">
19
+ <a href="https://www.npmjs.com/package/ts-abbr-skill"><img src="https://img.shields.io/npm/dm/ts-abbr-skill?style=flat-square&label=downloads" alt="npm downloads"></a>
20
+ <a href="https://github.com/aShu-guo/ts-abbreviation-skill/stargazers"><img src="https://img.shields.io/github/stars/aShu-guo/ts-abbreviation-skill?style=flat-square&logo=github" alt="GitHub stars"></a>
21
+ </p>
22
+
23
+ 一ä¸Ē Claude Code SkillīŧŒčŽŠį”Ÿæˆ/é‡æž„įš„ TypeScript äģŖį å‘Ŋ名éĩåžĒįģŸä¸€įš„įŧŠå†™č¯å…¸īŧˆ`business` → `biz`、`context` → `ctx`、`configuration` → `cfg` į­‰īŧ‰īŧŒč€Œä¸æ˜¯å†—é•ŋįš„å…¨į§°ã€‚
24
+
25
+ ## åŽ‰čŖ…
26
+
27
+ ```bash
28
+ npx ts-abbr-skill
29
+ ```
30
+
31
+ åŽ‰čŖ…æ—ļäŧšč¯ĸé—ŽčŖ…åˆ°å“Ē里īŧš
32
+
33
+ - **éĄšį›Žįē§** — `./.claude/skills/ts-abbr-skill/`īŧˆæŽ¨čå›ĸé˜Ÿå…ąäēĢīŧŒæäē¤åˆ°äģ“åē“īŧ‰
34
+ - **å…¨åą€** — `~/.claude/skills/ts-abbr-skill/`īŧˆé€‚ᔍäēŽäŊ æ‰€æœ‰įš„éĄšį›Žīŧ‰
35
+
36
+ 两ä¸Ēé€‰éĄšå¯äģĨ同æ—ļ勞选。重复čŋčĄŒåŽ‰čŖ…å™¨æ˜¯åŽ‰å…¨įš„īŧšį›Žæ ‡čˇ¯åž„ä¸‹åˇ˛å­˜åœ¨įš„ `config/default.config.json` 和 `dictionary/default.json` 不äŧščĸĢčĻ†į›–ã€‚
37
+
38
+ ## 效果
39
+
40
+ - **į”Ÿæˆæ–°äģŖį æ—ļ**īŧšClaude 在å‘Ŋååą€éƒ¨å˜é‡/参数䚋前æŸĨįŧŠå†™č¯å…¸īŧŒæœ‰åŒšé…åˆ™äŊŋᔍįŧŠå†™åŊĸåŧã€‚
41
+ - **é‡æž„åˇ˛æœ‰äģŖį æ—ļ**īŧšæ‰šé‡æ”šååŧēåˆļčĩ°åŸēäēŽ AST įš„é‡å‘Ŋåč„šæœŦīŧˆ`ts-morph`īŧ‰īŧŒä¸å…čޏį睿–‡æœŦæ›ŋæĸīŧŒéŋå…č¯¯æ”šå­—įŦĻ䏞字éĸé‡å’Œčˇ¨äŊœį”¨åŸŸåŒåå˜é‡ã€‚攚名后åŋ…éĄģ跑 `tsc --noEmit` æ ĄénjīŧŒä¸é€ščŋ‡ä¸įŽ—åŽŒæˆã€‚
42
+
43
+ åŽŒæ•´č§„åˆ™č§ [`skill/SKILL.md`](skill/SKILL.md)。
44
+
45
+ ## 内įŊŽč¯å…¸æ‘˜åŊ•
46
+
47
+ | 免᧰ | įŧŠå†™ |
48
+ |------|------|
49
+ | business | biz |
50
+ | context | ctx |
51
+ | configuration / config | cfg |
52
+ | parameter / parameters | param / params |
53
+ | response | res |
54
+ | request | req |
55
+ | temporary | tmp |
56
+ | reference | ref |
57
+ | element | el |
58
+ | repository | repo |
59
+ | service | svc |
60
+ | database | db |
61
+ | application | app |
62
+ | ... | ... |
63
+
64
+ åŽŒæ•´č¯å…¸č§ [`skill/dictionary/default.json`](skill/dictionary/default.json)。
65
+
66
+ ## č‡Ē厚䚉
67
+
68
+ **č°ƒæ•´į”Ÿæ•ˆčŒƒå›´** — äŋŽæ”šåŽ‰čŖ…į›ŽåŊ•é‡Œįš„ `config/default.config.json`īŧš
69
+
70
+ ```json
71
+ { "scope": ["variable", "parameter"], "exported": false }
72
+ ```
73
+
74
+ `scope` 可选å€ŧīŧš`variable`、`parameter`、`localFunction`、`class`。`exported` 控åˆļ是åĻ寚å¯ŧå‡ē/å…Ŧå…ąįŦĻåˇį”Ÿæ•ˆīŧˆéģ˜čޤ `false`īŧ‰ã€‚
75
+
76
+ **æˇģåŠ éĄšį›Žä¸“åąžįŧŠå†™** — 在äģ“å瓿 šį›ŽåŊ•攞 `.claude/ts-abbr.local.json`īŧŒč¯æĄäŧšåˆåšļčφᛖéģ˜čŽ¤č¯å…¸īŧš
77
+
78
+ ```json
79
+ {
80
+ "warehouse": "wh",
81
+ "department": "dept"
82
+ }
83
+ ```
84
+
85
+ ## æœŦ地åŧ€å‘
86
+
87
+ ```bash
88
+ npm install
89
+ npm run build # 构åģē src/cli.ts -> dist/cli.js
90
+ node dist/cli.js # æœŦ地æĩ‹č¯•åމ誅噍
91
+ ```
92
+
93
+ čŋ­äģŖč°ƒč¯• Skill 内厚æ—ļīŧŒį”¨ symlink äģŖæ›ŋ每æŦĄé‡æ–°æž„åģēīŧš
94
+
95
+ ```bash
96
+ ln -sfn /path/to/ts-abbreviation-skill/skill \
97
+ your-test-project/.claude/skills/ts-abbr-skill
98
+ ```
99
+
100
+ ## License
101
+
102
+ MIT
package/dist/cli.js ADDED
@@ -0,0 +1,80 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/cli.ts
4
+ import prompts from "prompts";
5
+
6
+ // src/install.ts
7
+ import fs from "fs";
8
+ import os from "os";
9
+ import path from "path";
10
+ import { fileURLToPath } from "url";
11
+ var __dirname = path.dirname(fileURLToPath(import.meta.url));
12
+ var SKILL_NAME = "ts-abbreviation-skill";
13
+ var PROTECTED_RELATIVE_PATHS = ["config/default.config.json", "dictionary/default.json"];
14
+ function getSkillSourceDir() {
15
+ return path.join(__dirname, "..", "skill");
16
+ }
17
+ function getTargetDir(scope, cwd) {
18
+ const base = scope === "project" ? path.join(cwd, ".claude", "skills") : path.join(os.homedir(), ".claude", "skills");
19
+ return path.join(base, SKILL_NAME);
20
+ }
21
+ function copyRecursive(srcDir, destDir, protectedRelPaths, relPrefix = "") {
22
+ const skipped = [];
23
+ fs.mkdirSync(destDir, { recursive: true });
24
+ for (const entry of fs.readdirSync(srcDir, { withFileTypes: true })) {
25
+ const srcPath = path.join(srcDir, entry.name);
26
+ const destPath = path.join(destDir, entry.name);
27
+ const relPath = relPrefix ? `${relPrefix}/${entry.name}` : entry.name;
28
+ if (entry.isDirectory()) {
29
+ skipped.push(...copyRecursive(srcPath, destPath, protectedRelPaths, relPath));
30
+ continue;
31
+ }
32
+ if (protectedRelPaths.has(relPath) && fs.existsSync(destPath)) {
33
+ skipped.push(relPath);
34
+ continue;
35
+ }
36
+ fs.copyFileSync(srcPath, destPath);
37
+ }
38
+ return skipped;
39
+ }
40
+ function installSkill(scope, cwd = process.cwd()) {
41
+ const srcDir = getSkillSourceDir();
42
+ const targetDir = getTargetDir(scope, cwd);
43
+ const skippedExisting = copyRecursive(srcDir, targetDir, new Set(PROTECTED_RELATIVE_PATHS));
44
+ return { targetDir, skippedExisting };
45
+ }
46
+
47
+ // src/cli.ts
48
+ async function main() {
49
+ console.log("ts-abbreviation-skill installer\n");
50
+ const { scopes } = await prompts({
51
+ type: "multiselect",
52
+ name: "scopes",
53
+ message: "Where should this skill be installed?",
54
+ choices: [
55
+ { title: "This project (./.claude/skills/)", value: "project", selected: true },
56
+ { title: "Global (~/.claude/skills/)", value: "global" }
57
+ ],
58
+ min: 1
59
+ });
60
+ if (!scopes || scopes.length === 0) {
61
+ console.log("No install scope selected, aborting.");
62
+ process.exit(1);
63
+ }
64
+ for (const scope of scopes) {
65
+ const { targetDir, skippedExisting } = installSkill(scope);
66
+ console.log(`
67
+ \u2714 Installed to ${targetDir}`);
68
+ if (skippedExisting.length > 0) {
69
+ console.log(` Kept existing customizations (not overwritten): ${skippedExisting.join(", ")}`);
70
+ }
71
+ }
72
+ console.log("\nNext steps:");
73
+ console.log(" - Restart/reopen Claude Code so it picks up the new skill.");
74
+ console.log(" - Customize scope/exported in <target>/config/default.config.json if needed.");
75
+ console.log(" - Add project-specific abbreviations via .claude/ts-abbreviation.local.json in your repo.");
76
+ }
77
+ main().catch((err) => {
78
+ console.error(err);
79
+ process.exit(1);
80
+ });
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "ts-abbr-skill",
3
+ "version": "1.0.0",
4
+ "description": "Claude Code skill that applies a configurable abbreviation dictionary (business→biz, context→ctx, ...) to TypeScript variable/parameter naming.",
5
+ "type": "module",
6
+ "bin": {
7
+ "ts-abbr-skill": "dist/cli.js"
8
+ },
9
+ "files": [
10
+ "dist",
11
+ "skill"
12
+ ],
13
+ "scripts": {
14
+ "build": "tsup",
15
+ "dev": "tsup --watch"
16
+ },
17
+ "keywords": [
18
+ "claude-code",
19
+ "skill",
20
+ "typescript",
21
+ "naming",
22
+ "abbreviation"
23
+ ],
24
+ "license": "MIT",
25
+ "dependencies": {
26
+ "prompts": "^2.4.2"
27
+ },
28
+ "devDependencies": {
29
+ "@types/node": "^20.14.0",
30
+ "@types/prompts": "^2.4.9",
31
+ "ts-morph": "^23.0.0",
32
+ "tsup": "^8.2.4",
33
+ "typescript": "^5.5.4"
34
+ },
35
+ "engines": {
36
+ "node": ">=18"
37
+ }
38
+ }
package/skill/SKILL.md ADDED
@@ -0,0 +1,63 @@
1
+ ---
2
+ name: ts-abbreviation-skill
3
+ description: Use when writing or refactoring TypeScript variable, parameter, function, or class names — applies a configurable abbreviation dictionary (business→biz, context→ctx, configuration→cfg, etc.) so generated and refactored code matches the team's naming conventions.
4
+ ---
5
+
6
+ # TS Abbreviation Skill
7
+
8
+ ## Overview
9
+
10
+ Generated TypeScript code tends to use full, verbose English words for local names (`business`, `context`, `configuration`). This skill applies a shared abbreviation dictionary so naming stays short and consistent, in both newly generated code and refactors of existing code.
11
+
12
+ ## Config and Dictionary Lookup Order
13
+
14
+ Before naming anything, resolve config and dictionary by merging, most specific first:
15
+
16
+ 1. Project override: `.claude/ts-abbreviation.local.json` in the current repo root (if present) — entries here are merged on top of the default dictionary/config, not a full replacement.
17
+ 2. Default config/dictionary shipped with this skill: `config/default.config.json`, `dictionary/default.json`.
18
+
19
+ Default config (`config/default.config.json`):
20
+ ```json
21
+ {
22
+ "scope": ["variable", "parameter"],
23
+ "exported": false
24
+ }
25
+ ```
26
+
27
+ - `scope`: which kinds of identifiers this applies to. Possible values: `variable`, `parameter`, `localFunction`, `class`. Only apply abbreviations to kinds listed here.
28
+ - `exported`: whether exported/public symbols (exported consts, public class members, public function names) are in scope. Default `false` — never abbreviate a symbol that's part of a public API unless the project config explicitly sets `exported: true`.
29
+
30
+ If the project has no `.claude/ts-abbreviation.local.json`, use the defaults as-is.
31
+
32
+ ## Mode 1: Generating New Code
33
+
34
+ When about to name a new local variable, parameter, (optionally) local function, or class — per the resolved `scope` — look it up in the merged dictionary. If a whole-word match exists (case-sensitively adapting to camelCase/PascalCase as needed), use the abbreviation instead of the full word. Compound identifiers should abbreviate the matched segment only, keeping the rest of the identifier as-is (e.g. `businessContext` → `bizCtx`, `userConfiguration` → `userCfg`).
35
+
36
+ Do not abbreviate:
37
+ - Symbols outside the configured `scope`
38
+ - Exported/public symbols unless `exported: true` is configured
39
+ - Identifiers where abbreviating would collide with an existing name in the same scope
40
+
41
+ **This is a two-pass task, not a one-pass one.** First draft the code naturally. Then, before finishing, do a second pass: enumerate *every* declared identifier in what you just wrote — every parameter, and every local variable (`const`/`let` inside the function body), regardless of whether that word appeared in the user's request — and check each one against the dictionary independently. It's easy to abbreviate the parameters (because they're named right there in the request) and forget local variables the code introduces on its own (intermediate results, loop variables, destructured values). Both are in the default `scope` and both need the same check.
42
+
43
+ For example, in a function that takes `configuration` and an `identifier` and returns a `message`, the parameters *and* any local variable holding an intermediate value (e.g. a fetched record, a formatted string) all need the same dictionary lookup — not just the ones named in the prompt. Type/class names and exported symbol names are the only things that stay full by default (see `scope`/`exported` above).
44
+
45
+ ## Mode 2: Refactoring Existing Code (batch rename)
46
+
47
+ Renaming an existing identifier across a codebase is only safe if every reference updates together. **Never use plain-text `grep`/`sed`/find-and-replace to rename identifiers** — it will corrupt string literals, comments, unrelated identically-named locals in other scopes, and any partial-word matches.
48
+
49
+ Instead:
50
+
51
+ 1. Identify the exact declaration site (file, line, column) of the symbol to rename.
52
+ 2. Use `scripts/rename-with-ts-morph.ts` to perform an AST-aware rename — it resolves the symbol via the TypeScript compiler API and updates every reference consistently.
53
+ ```bash
54
+ npx tsx scripts/rename-with-ts-morph.ts --file src/foo.ts --line 12 --col 7 --newName bizCtx
55
+ ```
56
+ (Requires `ts-morph` as a dependency in the target project — install with `npm i -D ts-morph` if not already present.)
57
+ 3. After renaming, run `tsc --noEmit` in the target project and confirm it exits with no errors before considering the rename complete. Do not report a rename as done without this check passing — if it fails, fix the fallout (e.g. missed re-export) before finishing.
58
+
59
+ ## Common Mistakes
60
+
61
+ - Abbreviating an exported API name because it "looked local" — check `scope`/`exported` config first.
62
+ - Using sed/grep-based renames for "just one variable" — even single renames can hit false positives (e.g. a `context` string literal or an unrelated `context` param in another function).
63
+ - Skipping the `tsc --noEmit` check after a rename because "it looked like a simple change."
@@ -0,0 +1,4 @@
1
+ {
2
+ "scope": ["variable", "parameter"],
3
+ "exported": false
4
+ }
@@ -0,0 +1,21 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "title": "ts-abbreviation-skill config",
4
+ "type": "object",
5
+ "additionalProperties": false,
6
+ "properties": {
7
+ "scope": {
8
+ "type": "array",
9
+ "description": "Identifier kinds this skill is allowed to abbreviate.",
10
+ "items": {
11
+ "type": "string",
12
+ "enum": ["variable", "parameter", "localFunction", "class"]
13
+ },
14
+ "minItems": 1
15
+ },
16
+ "exported": {
17
+ "type": "boolean",
18
+ "description": "Whether exported/public symbols may be abbreviated. Defaults to false."
19
+ }
20
+ }
21
+ }
@@ -0,0 +1,100 @@
1
+ {
2
+ "business": "biz",
3
+ "context": "ctx",
4
+ "configuration": "cfg",
5
+ "config": "cfg",
6
+ "parameter": "param",
7
+ "parameters": "params",
8
+ "argument": "arg",
9
+ "arguments": "args",
10
+ "temporary": "tmp",
11
+ "reference": "ref",
12
+ "references": "refs",
13
+ "element": "el",
14
+ "elements": "els",
15
+ "index": "idx",
16
+ "indexes": "idxs",
17
+ "indices": "idxs",
18
+ "value": "val",
19
+ "values": "vals",
20
+ "message": "msg",
21
+ "messages": "msgs",
22
+ "response": "res",
23
+ "request": "req",
24
+ "callback": "cb",
25
+ "attribute": "attr",
26
+ "attributes": "attrs",
27
+ "property": "prop",
28
+ "properties": "props",
29
+ "environment": "env",
30
+ "directory": "dir",
31
+ "directories": "dirs",
32
+ "document": "doc",
33
+ "documents": "docs",
34
+ "component": "comp",
35
+ "utility": "util",
36
+ "utilities": "utils",
37
+ "controller": "ctrl",
38
+ "repository": "repo",
39
+ "database": "db",
40
+ "identifier": "id",
41
+ "identifiers": "ids",
42
+ "number": "num",
43
+ "numbers": "nums",
44
+ "string": "str",
45
+ "strings": "strs",
46
+ "object": "obj",
47
+ "objects": "objs",
48
+ "array": "arr",
49
+ "arrays": "arrs",
50
+ "boolean": "bool",
51
+ "booleans": "bools",
52
+ "function": "fn",
53
+ "functions": "fns",
54
+ "variable": "var",
55
+ "variables": "vars",
56
+ "current": "cur",
57
+ "previous": "prev",
58
+ "initialize": "init",
59
+ "initialization": "init",
60
+ "authentication": "auth",
61
+ "authorization": "authz",
62
+ "administrator": "admin",
63
+ "application": "app",
64
+ "package": "pkg",
65
+ "source": "src",
66
+ "destination": "dest",
67
+ "description": "desc",
68
+ "information": "info",
69
+ "language": "lang",
70
+ "library": "lib",
71
+ "libraries": "libs",
72
+ "specification": "spec",
73
+ "specifications": "specs",
74
+ "structure": "struct",
75
+ "synchronize": "sync",
76
+ "synchronization": "sync",
77
+ "transaction": "txn",
78
+ "transactions": "txns",
79
+ "coordinate": "coord",
80
+ "coordinates": "coords",
81
+ "column": "col",
82
+ "columns": "cols",
83
+ "position": "pos",
84
+ "dimension": "dim",
85
+ "dimensions": "dims",
86
+ "maximum": "max",
87
+ "minimum": "min",
88
+ "average": "avg",
89
+ "total": "sum",
90
+ "increment": "inc",
91
+ "decrement": "dec",
92
+ "expression": "expr",
93
+ "statement": "stmt",
94
+ "declaration": "decl",
95
+ "definition": "def",
96
+ "implementation": "impl",
97
+ "instance": "inst",
98
+ "namespace": "ns",
99
+ "seconds": "secs"
100
+ }
@@ -0,0 +1,74 @@
1
+ import path from 'node:path'
2
+ import { Project, SyntaxKind } from 'ts-morph'
3
+
4
+ interface RenameArgs {
5
+ file: string
6
+ line: number
7
+ col: number
8
+ newName: string
9
+ tsconfig?: string
10
+ }
11
+
12
+ function parseArgs(): RenameArgs {
13
+ const argv = process.argv.slice(2)
14
+ const raw: Record<string, string> = {}
15
+
16
+ for (let i = 0; i < argv.length; i++) {
17
+ const arg = argv[i]
18
+ if (arg.startsWith('--')) {
19
+ raw[arg.slice(2)] = argv[i + 1]
20
+ i++
21
+ }
22
+ }
23
+
24
+ const { file, line, col, newName, tsconfig } = raw
25
+ if (!file || !line || !col || !newName) {
26
+ console.error(
27
+ 'Usage: rename-with-ts-morph --file <path> --line <n> --col <n> --newName <name> [--tsconfig <path>]',
28
+ )
29
+ process.exit(1)
30
+ }
31
+
32
+ return {
33
+ file,
34
+ line: Number(line),
35
+ col: Number(col),
36
+ newName,
37
+ tsconfig,
38
+ }
39
+ }
40
+
41
+ function main() {
42
+ const { file, line, col, newName, tsconfig } = parseArgs()
43
+
44
+ const project = new Project({
45
+ tsConfigFilePath: path.resolve(tsconfig ?? 'tsconfig.json'),
46
+ })
47
+
48
+ const filePath = path.resolve(file)
49
+ const sourceFile = project.getSourceFileOrThrow(filePath)
50
+
51
+ const pos = sourceFile.compilerNode.getPositionOfLineAndCharacter(line - 1, col - 1)
52
+ const node = sourceFile.getDescendantAtPos(pos)
53
+ if (!node) {
54
+ console.error(`No node found at ${file}:${line}:${col}`)
55
+ process.exit(1)
56
+ }
57
+
58
+ const identifierNode =
59
+ node.getKind() === SyntaxKind.Identifier ? node : node.getFirstAncestorByKind(SyntaxKind.Identifier)
60
+ if (!identifierNode) {
61
+ console.error(`No identifier found at ${file}:${line}:${col}`)
62
+ process.exit(1)
63
+ }
64
+
65
+ const identifier = identifierNode.asKindOrThrow(SyntaxKind.Identifier)
66
+ const oldName = identifier.getText()
67
+ identifier.rename(newName)
68
+ project.saveSync()
69
+
70
+ console.log(`Renamed "${oldName}" -> "${newName}" at ${file}:${line}:${col} (all references updated).`)
71
+ console.log('Next: run `tsc --noEmit` to confirm the rename did not break anything.')
72
+ }
73
+
74
+ main()