@astrojs/ts-plugin 0.2.1 → 0.3.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.
@@ -1,38 +1,36 @@
1
1
  import type ts from 'typescript/lib/tsserverlibrary';
2
- import { Logger } from '../logger.js';
3
2
  import { AstroSnapshotManager } from '../astro-snapshots.js';
4
- import { isNotNullOrUndefined, isAstroFilePath } from '../utils.js';
3
+ import { Logger } from '../logger.js';
4
+ import { isAstroFilePath, isNotNullOrUndefined } from '../utils.js';
5
5
 
6
6
  export function decorateGetImplementation(
7
- ls: ts.LanguageService,
8
- snapshotManager: AstroSnapshotManager,
9
- logger: Logger
7
+ ls: ts.LanguageService,
8
+ snapshotManager: AstroSnapshotManager,
9
+ logger: Logger
10
10
  ): void {
11
- const getImplementationAtPosition = ls.getImplementationAtPosition;
12
- ls.getImplementationAtPosition = (fileName, position) => {
13
- const implementation = getImplementationAtPosition(fileName, position);
14
- return implementation
15
- ?.map((impl) => {
16
- if (!isAstroFilePath(impl.fileName)) {
17
- return impl;
18
- }
11
+ const getImplementationAtPosition = ls.getImplementationAtPosition;
12
+ ls.getImplementationAtPosition = (fileName, position) => {
13
+ const implementation = getImplementationAtPosition(fileName, position);
14
+ return implementation
15
+ ?.map((impl) => {
16
+ if (!isAstroFilePath(impl.fileName)) {
17
+ return impl;
18
+ }
19
19
 
20
- const textSpan = snapshotManager
21
- .get(impl.fileName)
22
- ?.getOriginalTextSpan(impl.textSpan);
23
- if (!textSpan) {
24
- return undefined;
25
- }
20
+ const textSpan = snapshotManager.get(impl.fileName)?.getOriginalTextSpan(impl.textSpan);
21
+ if (!textSpan) {
22
+ return undefined;
23
+ }
26
24
 
27
- return {
28
- ...impl,
29
- textSpan,
30
- // Spare the work for now
31
- contextSpan: undefined,
32
- originalTextSpan: undefined,
33
- originalContextSpan: undefined
34
- };
35
- })
36
- .filter(isNotNullOrUndefined);
37
- };
38
- }
25
+ return {
26
+ ...impl,
27
+ textSpan,
28
+ // Spare the work for now
29
+ contextSpan: undefined,
30
+ originalTextSpan: undefined,
31
+ originalContextSpan: undefined,
32
+ };
33
+ })
34
+ .filter(isNotNullOrUndefined);
35
+ };
36
+ }
@@ -1,6 +1,6 @@
1
1
  import type ts from 'typescript/lib/tsserverlibrary';
2
- import { Logger } from '../logger';
3
2
  import { AstroSnapshotManager } from '../astro-snapshots.js';
3
+ import { Logger } from '../logger';
4
4
  import { isAstroFilePath } from '../utils.js';
5
5
  import { decorateCompletions } from './completions.js';
6
6
  import { decorateGetDefinition } from './definition.js';
@@ -10,34 +10,34 @@ import { decorateGetImplementation } from './implementation.js';
10
10
  import { decorateRename } from './rename.js';
11
11
 
12
12
  export function decorateLanguageService(
13
- ls: ts.LanguageService,
14
- snapshotManager: AstroSnapshotManager,
15
- logger: Logger
13
+ ls: ts.LanguageService,
14
+ snapshotManager: AstroSnapshotManager,
15
+ logger: Logger
16
16
  ): ts.LanguageService {
17
- patchLineColumnOffset(ls, snapshotManager);
18
- decorateRename(ls, snapshotManager, logger);
19
- decorateDiagnostics(ls, logger);
20
- decorateFindReferences(ls, snapshotManager, logger);
21
- decorateCompletions(ls, logger);
22
- decorateGetDefinition(ls, snapshotManager, logger);
23
- decorateGetImplementation(ls, snapshotManager, logger);
24
- return ls;
17
+ patchLineColumnOffset(ls, snapshotManager);
18
+ decorateRename(ls, snapshotManager, logger);
19
+ decorateDiagnostics(ls, logger);
20
+ decorateFindReferences(ls, snapshotManager, logger);
21
+ decorateCompletions(ls, logger);
22
+ decorateGetDefinition(ls, snapshotManager, logger);
23
+ decorateGetImplementation(ls, snapshotManager, logger);
24
+ return ls;
25
25
  }
26
26
 
27
27
  function patchLineColumnOffset(ls: ts.LanguageService, snapshotManager: AstroSnapshotManager) {
28
- if (!ls.toLineColumnOffset) {
29
- return;
30
- }
28
+ if (!ls.toLineColumnOffset) {
29
+ return;
30
+ }
31
31
 
32
- // We need to patch this because (according to source, only) getDefinition uses this
33
- const toLineColumnOffset = ls.toLineColumnOffset;
34
- ls.toLineColumnOffset = (fileName, position) => {
35
- if (isAstroFilePath(fileName)) {
36
- const snapshot = snapshotManager.get(fileName);
37
- if (snapshot) {
38
- return snapshot.positionAt(position);
39
- }
40
- }
41
- return toLineColumnOffset(fileName, position);
42
- };
43
- }
32
+ // We need to patch this because (according to source, only) getDefinition uses this
33
+ const toLineColumnOffset = ls.toLineColumnOffset;
34
+ ls.toLineColumnOffset = (fileName, position) => {
35
+ if (isAstroFilePath(fileName)) {
36
+ const snapshot = snapshotManager.get(fileName);
37
+ if (snapshot) {
38
+ return snapshot.positionAt(position);
39
+ }
40
+ }
41
+ return toLineColumnOffset(fileName, position);
42
+ };
43
+ }
@@ -1,52 +1,42 @@
1
1
  import type ts from 'typescript/lib/tsserverlibrary';
2
- import { Logger } from '../logger.js';
3
2
  import { AstroSnapshotManager } from '../astro-snapshots.js';
4
- import { isNotNullOrUndefined, isAstroFilePath } from '../utils.js';
3
+ import { Logger } from '../logger.js';
4
+ import { isAstroFilePath, isNotNullOrUndefined } from '../utils.js';
5
5
 
6
- export function decorateRename(
7
- ls: ts.LanguageService,
8
- snapshotManager: AstroSnapshotManager,
9
- logger: Logger
10
- ): void {
11
- const findRenameLocations = ls.findRenameLocations;
12
- ls.findRenameLocations = (
13
- fileName,
14
- position,
15
- findInStrings,
16
- findInComments,
17
- providePrefixAndSuffixTextForRename
18
- ) => {
19
- const renameLocations = findRenameLocations(
20
- fileName,
21
- position,
22
- findInStrings,
23
- findInComments,
24
- providePrefixAndSuffixTextForRename
25
- );
26
- return renameLocations
27
- ?.map((renameLocation) => {
28
- const snapshot = snapshotManager.get(renameLocation.fileName);
29
- if (!isAstroFilePath(renameLocation.fileName) || !snapshot) {
30
- return renameLocation;
31
- }
6
+ export function decorateRename(ls: ts.LanguageService, snapshotManager: AstroSnapshotManager, logger: Logger): void {
7
+ const findRenameLocations = ls.findRenameLocations;
8
+ ls.findRenameLocations = (fileName, position, findInStrings, findInComments, providePrefixAndSuffixTextForRename) => {
9
+ const renameLocations = findRenameLocations(
10
+ fileName,
11
+ position,
12
+ findInStrings,
13
+ findInComments,
14
+ providePrefixAndSuffixTextForRename
15
+ );
16
+ return renameLocations
17
+ ?.map((renameLocation) => {
18
+ const snapshot = snapshotManager.get(renameLocation.fileName);
19
+ if (!isAstroFilePath(renameLocation.fileName) || !snapshot) {
20
+ return renameLocation;
21
+ }
32
22
 
33
- // TODO more needed to filter invalid locations, see RenameProvider
34
- const textSpan = snapshot.getOriginalTextSpan(renameLocation.textSpan);
35
- if (!textSpan) {
36
- return null;
37
- }
23
+ // TODO more needed to filter invalid locations, see RenameProvider
24
+ const textSpan = snapshot.getOriginalTextSpan(renameLocation.textSpan);
25
+ if (!textSpan) {
26
+ return null;
27
+ }
38
28
 
39
- const converted = {
40
- ...renameLocation,
41
- textSpan
42
- };
43
- if (converted.contextSpan) {
44
- // Not important, spare the work
45
- converted.contextSpan = undefined;
46
- }
47
- logger.debug('Converted rename location ', converted);
48
- return converted;
49
- })
50
- .filter(isNotNullOrUndefined);
51
- };
52
- }
29
+ const converted = {
30
+ ...renameLocation,
31
+ textSpan,
32
+ };
33
+ if (converted.contextSpan) {
34
+ // Not important, spare the work
35
+ converted.contextSpan = undefined;
36
+ }
37
+ logger.debug('Converted rename location ', converted);
38
+ return converted;
39
+ })
40
+ .filter(isNotNullOrUndefined);
41
+ };
42
+ }
package/src/logger.ts CHANGED
@@ -1,41 +1,37 @@
1
1
  import type ts from 'typescript/lib/tsserverlibrary';
2
2
 
3
3
  export class Logger {
4
- constructor(
5
- private tsLogService: ts.server.Logger,
6
- suppressNonAstroLogs = false,
7
- private logDebug = false
8
- ) {
9
- if (suppressNonAstroLogs) {
10
- const log = this.tsLogService.info.bind(this.tsLogService);
11
- this.tsLogService.info = (s: string) => {
12
- if (s.startsWith('-Astro Plugin-')) {
13
- log(s);
14
- }
15
- };
16
- }
17
- }
4
+ constructor(private tsLogService: ts.server.Logger, suppressNonAstroLogs = false, private logDebug = false) {
5
+ if (suppressNonAstroLogs) {
6
+ const log = this.tsLogService.info.bind(this.tsLogService);
7
+ this.tsLogService.info = (s: string) => {
8
+ if (s.startsWith('-Astro Plugin-')) {
9
+ log(s);
10
+ }
11
+ };
12
+ }
13
+ }
18
14
 
19
- log(...args: any[]) {
20
- const str = args
21
- .map((arg) => {
22
- if (typeof arg === 'object') {
23
- try {
24
- return JSON.stringify(arg);
25
- } catch (e) {
26
- return '[object that cannot by stringified]';
27
- }
28
- }
29
- return arg;
30
- })
31
- .join(' ');
32
- this.tsLogService.info('-Astro Plugin- ' + str);
33
- }
15
+ log(...args: any[]) {
16
+ const str = args
17
+ .map((arg) => {
18
+ if (typeof arg === 'object') {
19
+ try {
20
+ return JSON.stringify(arg);
21
+ } catch (e) {
22
+ return '[object that cannot by stringified]';
23
+ }
24
+ }
25
+ return arg;
26
+ })
27
+ .join(' ');
28
+ this.tsLogService.info('-Astro Plugin- ' + str);
29
+ }
34
30
 
35
- debug(...args: any[]) {
36
- if (!this.logDebug) {
37
- return;
38
- }
39
- this.log(...args);
40
- }
41
- }
31
+ debug(...args: any[]) {
32
+ if (!this.logDebug) {
33
+ return;
34
+ }
35
+ this.log(...args);
36
+ }
37
+ }
@@ -1,47 +1,47 @@
1
1
  import type ts from 'typescript/lib/tsserverlibrary';
2
- import { Logger } from './logger.js';
3
2
  import { AstroSnapshotManager } from './astro-snapshots.js';
4
3
  import { createAstroSys } from './astro-sys.js';
4
+ import { Logger } from './logger.js';
5
5
  import { ensureRealAstroFilePath, isVirtualAstroFilePath } from './utils.js';
6
6
 
7
7
  /**
8
8
  * Caches resolved modules.
9
9
  */
10
10
  class ModuleResolutionCache {
11
- private cache = new Map<string, ts.ResolvedModule>();
11
+ private cache = new Map<string, ts.ResolvedModule>();
12
12
 
13
- /**
14
- * Tries to get a cached module.
15
- */
16
- get(moduleName: string, containingFile: string): ts.ResolvedModule | undefined {
17
- return this.cache.get(this.getKey(moduleName, containingFile));
18
- }
13
+ /**
14
+ * Tries to get a cached module.
15
+ */
16
+ get(moduleName: string, containingFile: string): ts.ResolvedModule | undefined {
17
+ return this.cache.get(this.getKey(moduleName, containingFile));
18
+ }
19
19
 
20
- /**
21
- * Caches resolved module, if it is not undefined.
22
- */
23
- set(moduleName: string, containingFile: string, resolvedModule: ts.ResolvedModule | undefined) {
24
- if (!resolvedModule) {
25
- return;
26
- }
27
- this.cache.set(this.getKey(moduleName, containingFile), resolvedModule);
28
- }
20
+ /**
21
+ * Caches resolved module, if it is not undefined.
22
+ */
23
+ set(moduleName: string, containingFile: string, resolvedModule: ts.ResolvedModule | undefined) {
24
+ if (!resolvedModule) {
25
+ return;
26
+ }
27
+ this.cache.set(this.getKey(moduleName, containingFile), resolvedModule);
28
+ }
29
29
 
30
- /**
31
- * Deletes module from cache. Call this if a file was deleted.
32
- * @param resolvedModuleName full path of the module
33
- */
34
- delete(resolvedModuleName: string): void {
35
- this.cache.forEach((val, key) => {
36
- if (val.resolvedFileName === resolvedModuleName) {
37
- this.cache.delete(key);
38
- }
39
- });
40
- }
30
+ /**
31
+ * Deletes module from cache. Call this if a file was deleted.
32
+ * @param resolvedModuleName full path of the module
33
+ */
34
+ delete(resolvedModuleName: string): void {
35
+ this.cache.forEach((val, key) => {
36
+ if (val.resolvedFileName === resolvedModuleName) {
37
+ this.cache.delete(key);
38
+ }
39
+ });
40
+ }
41
41
 
42
- private getKey(moduleName: string, containingFile: string) {
43
- return containingFile + ':::' + ensureRealAstroFilePath(moduleName);
44
- }
42
+ private getKey(moduleName: string, containingFile: string) {
43
+ return containingFile + ':::' + ensureRealAstroFilePath(moduleName);
44
+ }
45
45
  }
46
46
 
47
47
  /**
@@ -54,92 +54,84 @@ class ModuleResolutionCache {
54
54
  * In order to fix this, we need to wrap typescript's module resolution and reroute all `.astro.ts` file lookups to .astro.
55
55
  */
56
56
  export function patchModuleLoader(
57
- logger: Logger,
58
- snapshotManager: AstroSnapshotManager,
59
- typescript: typeof ts,
60
- lsHost: ts.LanguageServiceHost,
61
- project: ts.server.Project
57
+ logger: Logger,
58
+ snapshotManager: AstroSnapshotManager,
59
+ typescript: typeof ts,
60
+ lsHost: ts.LanguageServiceHost,
61
+ project: ts.server.Project
62
62
  ): void {
63
- const astroSys = createAstroSys(logger);
64
- const moduleCache = new ModuleResolutionCache();
65
- const origResolveModuleNames = lsHost.resolveModuleNames?.bind(lsHost);
63
+ const astroSys = createAstroSys(logger);
64
+ const moduleCache = new ModuleResolutionCache();
65
+ const origResolveModuleNames = lsHost.resolveModuleNames?.bind(lsHost);
66
66
 
67
- lsHost.resolveModuleNames = resolveModuleNames;
67
+ lsHost.resolveModuleNames = resolveModuleNames;
68
68
 
69
- const origRemoveFile = project.removeFile.bind(project);
70
- project.removeFile = (info, fileExists, detachFromProject) => {
71
- logger.log('File is being removed. Delete from cache: ', info.fileName);
72
- moduleCache.delete(info.fileName);
73
- return origRemoveFile(info, fileExists, detachFromProject);
74
- };
69
+ const origRemoveFile = project.removeFile.bind(project);
70
+ project.removeFile = (info, fileExists, detachFromProject) => {
71
+ logger.log('File is being removed. Delete from cache: ', info.fileName);
72
+ moduleCache.delete(info.fileName);
73
+ return origRemoveFile(info, fileExists, detachFromProject);
74
+ };
75
75
 
76
- function resolveModuleNames(
77
- moduleNames: string[],
78
- containingFile: string,
79
- reusedNames: string[] | undefined,
80
- redirectedReference: ts.ResolvedProjectReference | undefined,
81
- compilerOptions: ts.CompilerOptions
82
- ): Array<ts.ResolvedModule | undefined> {
83
- logger.log('Resolving modules names for ' + containingFile);
84
- // Try resolving all module names with the original method first.
85
- // The ones that are undefined will be re-checked if they are a
86
- // astro file and if so, are resolved, too. This way we can defer
87
- // all module resolving logic except for astro files to TypeScript.
88
- const resolved =
89
- origResolveModuleNames?.(
90
- moduleNames,
91
- containingFile,
92
- reusedNames,
93
- redirectedReference,
94
- compilerOptions
95
- ) || Array.from<undefined>(Array(moduleNames.length));
76
+ function resolveModuleNames(
77
+ moduleNames: string[],
78
+ containingFile: string,
79
+ reusedNames: string[] | undefined,
80
+ redirectedReference: ts.ResolvedProjectReference | undefined,
81
+ compilerOptions: ts.CompilerOptions
82
+ ): Array<ts.ResolvedModule | undefined> {
83
+ logger.log('Resolving modules names for ' + containingFile);
84
+ // Try resolving all module names with the original method first.
85
+ // The ones that are undefined will be re-checked if they are a
86
+ // astro file and if so, are resolved, too. This way we can defer
87
+ // all module resolving logic except for astro files to TypeScript.
88
+ const resolved =
89
+ origResolveModuleNames?.(moduleNames, containingFile, reusedNames, redirectedReference, compilerOptions) ||
90
+ Array.from<undefined>(Array(moduleNames.length));
96
91
 
97
- return resolved.map((moduleName, idx) => {
98
- const fileName = moduleNames[idx];
99
- if (moduleName || !ensureRealAstroFilePath(fileName).endsWith('.astro')) {
100
- return moduleName;
101
- }
92
+ return resolved.map((moduleName, idx) => {
93
+ const fileName = moduleNames[idx];
94
+ if (moduleName || !ensureRealAstroFilePath(fileName).endsWith('.astro')) {
95
+ return moduleName;
96
+ }
102
97
 
103
- const cachedModule = moduleCache.get(fileName, containingFile);
104
- if (cachedModule) {
105
- return cachedModule;
106
- }
98
+ const cachedModule = moduleCache.get(fileName, containingFile);
99
+ if (cachedModule) {
100
+ return cachedModule;
101
+ }
107
102
 
108
- const resolvedModule = resolveModuleName(fileName, containingFile, compilerOptions);
109
- moduleCache.set(fileName, containingFile, resolvedModule);
110
- return resolvedModule;
111
- });
112
- }
103
+ const resolvedModule = resolveModuleName(fileName, containingFile, compilerOptions);
104
+ moduleCache.set(fileName, containingFile, resolvedModule);
105
+ return resolvedModule;
106
+ });
107
+ }
113
108
 
114
- function resolveModuleName(
115
- name: string,
116
- containingFile: string,
117
- compilerOptions: ts.CompilerOptions
118
- ): ts.ResolvedModule | undefined {
119
- const astroResolvedModule = typescript.resolveModuleName(
120
- name,
121
- containingFile,
122
- compilerOptions,
123
- astroSys
124
- ).resolvedModule;
125
- if (
126
- !astroResolvedModule ||
127
- !isVirtualAstroFilePath(astroResolvedModule.resolvedFileName)
128
- ) {
129
- return astroResolvedModule;
130
- }
109
+ function resolveModuleName(
110
+ name: string,
111
+ containingFile: string,
112
+ compilerOptions: ts.CompilerOptions
113
+ ): ts.ResolvedModule | undefined {
114
+ const astroResolvedModule = typescript.resolveModuleName(
115
+ name,
116
+ containingFile,
117
+ compilerOptions,
118
+ astroSys
119
+ ).resolvedModule;
120
+ if (!astroResolvedModule || !isVirtualAstroFilePath(astroResolvedModule.resolvedFileName)) {
121
+ return astroResolvedModule;
122
+ }
131
123
 
132
- const resolvedFileName = ensureRealAstroFilePath(astroResolvedModule.resolvedFileName);
133
- logger.log('Resolved', name, 'to astro file', resolvedFileName);
134
- const snapshot = snapshotManager.create(resolvedFileName);
135
- if (!snapshot) {
136
- return undefined;
137
- }
124
+ const resolvedFileName = ensureRealAstroFilePath(astroResolvedModule.resolvedFileName);
125
+ logger.log('Resolved', name, 'to astro file', resolvedFileName);
126
+ const snapshot = snapshotManager.create(resolvedFileName);
127
+ if (!snapshot) {
128
+ return undefined;
129
+ }
138
130
 
139
- const resolvedAstroModule: ts.ResolvedModuleFull = {
140
- extension: snapshot.isTsFile ? typescript.Extension.Tsx : typescript.Extension.Jsx,
141
- resolvedFileName
142
- };
143
- return resolvedAstroModule;
144
- }
145
- }
131
+ const resolvedAstroModule: ts.ResolvedModuleFull = {
132
+ extension: snapshot.isTsFile ? typescript.Extension.Tsx : typescript.Extension.Jsx,
133
+ resolvedFileName,
134
+ };
135
+ return resolvedAstroModule;
136
+ }
137
+ }