@itcode-dev/ts-plugin-fix-import-suggestion 1.0.0 → 1.0.1

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/CHANGELOG.md ADDED
@@ -0,0 +1,18 @@
1
+ # Changelog
2
+
3
+ ## [1.0.1]
4
+
5
+ ### Changed
6
+
7
+ - Switched the build tool from `tsc` to `tsup` (esbuild-based). Output is now a single bundled, minified `dist/index.js` instead of separate compiled files.
8
+ - Added a dedicated `typecheck` script (`tsc --noEmit`), since `tsup`/esbuild doesn't type-check on its own. `build` now only bundles.
9
+ - Narrowed `tsconfig.json`'s `include` to `src/**/*.ts` so root-level config files (e.g. `tsup.config.ts`) aren't pulled into the type-checked program.
10
+
11
+ ### Notes
12
+
13
+ - No runtime behavior change: completions, Quick Fix, and "Add all missing imports" were re-verified against a real TypeScript `Program` after this change, with identical results to before.
14
+ - The published `main`/`types` entry points are unchanged.
15
+
16
+ ## [1.0.0]
17
+
18
+ - Initial public release.
package/dist/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
- import type * as ts from 'typescript';
2
- import type { server } from 'typescript';
1
+ import ts, { server } from 'typescript';
2
+
3
3
  declare function init({ typescript }: {
4
4
  typescript: typeof ts;
5
5
  }): Partial<server.PluginModule>;
6
- export = init;
6
+
7
+ export { init as default };
package/dist/index.js CHANGED
@@ -1,149 +1 @@
1
- "use strict";
2
- const extension_js_1 = require("./extension.js");
3
- const IMPORT_FIX_ID = 'fixMissingImport';
4
- const IMPORT_FIX_NAME = 'import';
5
- function patchMissingImportChanges(changes, typescript, info) {
6
- const program = info.languageService.getProgram();
7
- if (!program) {
8
- return [];
9
- }
10
- const compilerOptions = program.getCompilerOptions();
11
- const moduleResolutionHost = info.languageServiceHost;
12
- const fixes = [];
13
- for (const change of changes) {
14
- for (const textChange of change.textChanges) {
15
- textChange.newText = textChange.newText.replace(/\bfrom\s+(['"])([^'"]+)\1/gu, (whole, quote, specifier) => {
16
- const resolved = typescript.resolveModuleName(specifier, change.fileName, compilerOptions, moduleResolutionHost);
17
- const fixed = (0, extension_js_1.fixExtension)(specifier, resolved.resolvedModule?.resolvedFileName);
18
- if (fixed === specifier) {
19
- return whole;
20
- }
21
- fixes.push({ fixed, specifier });
22
- return `from ${quote}${fixed}${quote}`;
23
- });
24
- }
25
- }
26
- return fixes;
27
- }
28
- function init({ typescript }) {
29
- return {
30
- create(info) {
31
- const config = info.config;
32
- const isDebug = config.debug === true;
33
- const isOverwrite = config.overwrite === true;
34
- const log = (message) => {
35
- if (isDebug) {
36
- info.project.projectService.logger.info(`[ts-plugin-fix-import-extension] ${message}`);
37
- }
38
- };
39
- log(`create() called (overwrite: ${isOverwrite})`);
40
- const getCompletionsAtPosition = (fileName, position, options, formattingSettings) => {
41
- const result = info.languageService.getCompletionsAtPosition(fileName, position, options, formattingSettings);
42
- if (!result) {
43
- return result;
44
- }
45
- if (isOverwrite) {
46
- let fixedCount = 0;
47
- for (const entry of result.entries) {
48
- if (!(entry.source && entry.data?.fileName)) {
49
- continue;
50
- }
51
- const fixed = (0, extension_js_1.fixExtension)(entry.source, entry.data.fileName);
52
- if (fixed === entry.source) {
53
- continue;
54
- }
55
- entry.source = fixed;
56
- entry.sourceDisplay = [{ kind: 'text', text: fixed }];
57
- fixedCount++;
58
- }
59
- log(`getCompletionsAtPosition: ${result.entries.length} entries, ${fixedCount} overwritten`);
60
- return result;
61
- }
62
- const addedEntries = [];
63
- for (const entry of result.entries) {
64
- if (!(entry.source && entry.data?.fileName)) {
65
- continue;
66
- }
67
- const fixed = (0, extension_js_1.fixExtension)(entry.source, entry.data.fileName);
68
- if (fixed === entry.source) {
69
- continue;
70
- }
71
- addedEntries.push({
72
- ...entry,
73
- source: fixed,
74
- sourceDisplay: [{ kind: 'text', text: fixed }]
75
- });
76
- }
77
- result.entries.push(...addedEntries);
78
- log(`getCompletionsAtPosition: ${result.entries.length} entries, ${addedEntries.length} variants added`);
79
- return result;
80
- };
81
- const getCompletionEntryDetails = (fileName, position, entryName, formatOptions, source, preferences, data) => {
82
- const result = info.languageService.getCompletionEntryDetails(fileName, position, entryName, formatOptions, source, preferences, data);
83
- if (!result?.codeActions) {
84
- return result;
85
- }
86
- const realExt = (0, extension_js_1.getExtension)(data?.fileName);
87
- const pickedAddedEntry = realExt && source?.endsWith(realExt);
88
- const fakeSpecifier = data?.moduleSpecifier;
89
- const fixedSpecifier = pickedAddedEntry && fakeSpecifier ? (0, extension_js_1.fixExtension)(fakeSpecifier, data.fileName) : undefined;
90
- let patchedCount = 0;
91
- if (fixedSpecifier && fakeSpecifier && fixedSpecifier !== fakeSpecifier) {
92
- for (const codeAction of result.codeActions) {
93
- for (const change of codeAction.changes) {
94
- for (const textChange of change.textChanges) {
95
- if (textChange.newText.includes(fakeSpecifier)) {
96
- textChange.newText = textChange.newText.split(fakeSpecifier).join(fixedSpecifier);
97
- patchedCount++;
98
- }
99
- }
100
- }
101
- }
102
- }
103
- log(`getCompletionEntryDetails: ${patchedCount} textChanges patched`);
104
- return result;
105
- };
106
- const getCodeFixesAtPosition = (fileName, start, end, errorCodes, formatOptions, preferences) => {
107
- const result = info.languageService.getCodeFixesAtPosition(fileName, start, end, errorCodes, formatOptions, preferences);
108
- let patchedCount = 0;
109
- for (const action of result) {
110
- if (action.fixId !== IMPORT_FIX_ID && action.fixName !== IMPORT_FIX_NAME) {
111
- continue;
112
- }
113
- const fixes = patchMissingImportChanges(action.changes, typescript, info);
114
- for (const { fixed, specifier } of fixes) {
115
- action.description = action.description.split(specifier).join(fixed);
116
- }
117
- patchedCount += fixes.length;
118
- }
119
- log(`getCodeFixesAtPosition: ${result.length} actions, ${patchedCount} specifiers patched`);
120
- return result;
121
- };
122
- const getCombinedCodeFix = (scope, fixId, formatOptions, preferences) => {
123
- const result = info.languageService.getCombinedCodeFix(scope, fixId, formatOptions, preferences);
124
- if (fixId !== IMPORT_FIX_ID) {
125
- return result;
126
- }
127
- const patchedCount = patchMissingImportChanges(result.changes, typescript, info).length;
128
- log(`getCombinedCodeFix: ${patchedCount} specifiers patched`);
129
- return result;
130
- };
131
- const overrides = {
132
- getCodeFixesAtPosition,
133
- getCombinedCodeFix,
134
- getCompletionEntryDetails,
135
- getCompletionsAtPosition
136
- };
137
- return new Proxy(info.languageService, {
138
- get(target, prop, receiver) {
139
- if (prop in overrides) {
140
- return overrides[prop];
141
- }
142
- const value = Reflect.get(target, prop, receiver);
143
- return typeof value === 'function' ? value.bind(target) : value;
144
- }
145
- });
146
- }
147
- };
148
- }
149
- module.exports = init;
1
+ "use strict";function y(o){if(o!==void 0){if(o.endsWith(".tsx"))return".tsx";if(o.endsWith(".ts"))return".ts";if(o.endsWith(".jsx"))return".jsx";if(o.endsWith(".js"))return".js"}}function m(o,r){let l=y(o),p=y(r);return l&&p?`${o.slice(0,-l.length)}${p}`:o}var w="fixMissingImport",D="import";function T(o,r,l){let p=l.languageService.getProgram();if(!p)return[];let h=p.getCompilerOptions(),f=l.languageServiceHost,S=[];for(let P of o)for(let E of P.textChanges)E.newText=E.newText.replace(/\bfrom\s+(['"])([^'"]+)\1/gu,(A,x,i)=>{let s=r.resolveModuleName(i,P.fileName,h,f),c=m(i,s.resolvedModule?.resolvedFileName);return c===i?A:(S.push({fixed:c,specifier:i}),`from ${x}${c}${x}`)});return S}function L({typescript:o}){return{create(r){let l=r.config,p=l.debug===!0,h=l.overwrite===!0,f=i=>{p&&r.project.projectService.logger.info(`[ts-plugin-fix-import-extension] ${i}`)};f(`create() called (overwrite: ${h})`);let x={getCodeFixesAtPosition:(i,s,c,u,t,a)=>{let n=r.languageService.getCodeFixesAtPosition(i,s,c,u,t,a),e=0;for(let g of n){if(g.fixId!==w&&g.fixName!==D)continue;let v=T(g.changes,o,r);for(let{fixed:d,specifier:C}of v)g.description=g.description.split(C).join(d);e+=v.length}return f(`getCodeFixesAtPosition: ${n.length} actions, ${e} specifiers patched`),n},getCombinedCodeFix:(i,s,c,u)=>{let t=r.languageService.getCombinedCodeFix(i,s,c,u);if(s!==w)return t;let a=T(t.changes,o,r).length;return f(`getCombinedCodeFix: ${a} specifiers patched`),t},getCompletionEntryDetails:(i,s,c,u,t,a,n)=>{let e=r.languageService.getCompletionEntryDetails(i,s,c,u,t,a,n);if(!e?.codeActions)return e;let g=y(n?.fileName),v=g&&t?.endsWith(g),d=n?.moduleSpecifier,C=v&&d?m(d,n.fileName):void 0,$=0;if(C&&d&&C!==d)for(let b of e.codeActions)for(let j of b.changes)for(let F of j.textChanges)F.newText.includes(d)&&(F.newText=F.newText.split(d).join(C),$++);return f(`getCompletionEntryDetails: ${$} textChanges patched`),e},getCompletionsAtPosition:(i,s,c,u)=>{let t=r.languageService.getCompletionsAtPosition(i,s,c,u);if(!t)return t;if(h){let n=0;for(let e of t.entries){if(!(e.source&&e.data?.fileName))continue;let g=m(e.source,e.data.fileName);g!==e.source&&(e.source=g,e.sourceDisplay=[{kind:"text",text:g}],n++)}return f(`getCompletionsAtPosition: ${t.entries.length} entries, ${n} overwritten`),t}let a=[];for(let n of t.entries){if(!(n.source&&n.data?.fileName))continue;let e=m(n.source,n.data.fileName);e!==n.source&&a.push({...n,source:e,sourceDisplay:[{kind:"text",text:e}]})}return t.entries.push(...a),f(`getCompletionsAtPosition: ${t.entries.length} entries, ${a.length} variants added`),t}};return new Proxy(r.languageService,{get(i,s,c){if(s in x)return x[s];let u=Reflect.get(i,s,c);return typeof u=="function"?u.bind(i):u}})}}}module.exports=L;
package/package.json CHANGED
@@ -4,6 +4,7 @@
4
4
  "devDependencies": {
5
5
  "@biomejs/biome": "^2.4.16",
6
6
  "@itcode-dev/biome-config": "^1.0.1",
7
+ "tsup": "^8.5.1",
7
8
  "typescript": "^6.0.3"
8
9
  },
9
10
  "devEngines": {
@@ -30,8 +31,9 @@
30
31
  "name": "@itcode-dev/ts-plugin-fix-import-suggestion",
31
32
  "type": "commonjs",
32
33
  "types": "dist/index.d.ts",
33
- "version": "1.0.0",
34
+ "version": "1.0.1",
34
35
  "scripts": {
35
- "build": "tsc"
36
+ "build": "tsup",
37
+ "typecheck": "tsc --noEmit"
36
38
  }
37
39
  }
@@ -1,3 +0,0 @@
1
- export type Extension = '.tsx' | '.ts' | '.jsx' | '.js';
2
- export declare function getExtension(fileName?: string): Extension | undefined;
3
- export declare function fixExtension(specifier: string, fileName?: string): string;
package/dist/extension.js DELETED
@@ -1,29 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getExtension = getExtension;
4
- exports.fixExtension = fixExtension;
5
- function getExtension(fileName) {
6
- if (fileName === undefined) {
7
- return;
8
- }
9
- if (fileName.endsWith('.tsx')) {
10
- return '.tsx';
11
- }
12
- if (fileName.endsWith('.ts')) {
13
- return '.ts';
14
- }
15
- if (fileName.endsWith('.jsx')) {
16
- return '.jsx';
17
- }
18
- if (fileName.endsWith('.js')) {
19
- return '.js';
20
- }
21
- }
22
- function fixExtension(specifier, fileName) {
23
- const displayExt = getExtension(specifier);
24
- const fileExt = getExtension(fileName);
25
- if (!(displayExt && fileExt)) {
26
- return specifier;
27
- }
28
- return `${specifier.slice(0, -displayExt.length)}${fileExt}`;
29
- }