@astrojs/ts-plugin 0.2.1 → 0.4.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.
Files changed (54) hide show
  1. package/.turbo/turbo-build.log +5 -2
  2. package/CHANGELOG.md +16 -0
  3. package/LICENSE +36 -0
  4. package/README.md +1 -1
  5. package/dist/astro-snapshots.js +48 -47
  6. package/dist/astro-sys.js +22 -35
  7. package/dist/astro2tsx.js +17 -41
  8. package/dist/index.js +38 -39
  9. package/dist/language-service/completions.js +42 -42
  10. package/dist/language-service/definition.js +22 -40
  11. package/dist/language-service/diagnostics.js +15 -18
  12. package/dist/language-service/file-references.js +52 -0
  13. package/dist/language-service/find-references.js +20 -38
  14. package/dist/language-service/implementation.js +18 -37
  15. package/dist/language-service/index.js +26 -42
  16. package/dist/language-service/line-column-offset.js +44 -0
  17. package/dist/language-service/rename.js +24 -37
  18. package/dist/logger.js +18 -5
  19. package/dist/module-loader.js +28 -22
  20. package/dist/project-astro-files.js +125 -0
  21. package/dist/utils.js +34 -19
  22. package/dist/workers/TSXService.js +39 -0
  23. package/dist/workers/TSXWorker.js +9 -0
  24. package/package.json +36 -27
  25. package/src/astro-snapshots.ts +270 -291
  26. package/src/astro-sys.ts +22 -22
  27. package/src/astro2tsx.ts +5 -50
  28. package/src/index.ts +49 -60
  29. package/src/language-service/completions.ts +56 -64
  30. package/src/language-service/definition.ts +35 -42
  31. package/src/language-service/diagnostics.ts +32 -33
  32. package/src/language-service/file-references.ts +31 -0
  33. package/src/language-service/find-references.ts +67 -76
  34. package/src/language-service/implementation.ts +27 -34
  35. package/src/language-service/index.ts +17 -32
  36. package/src/language-service/line-column-offset.ts +21 -0
  37. package/src/language-service/rename.ts +38 -48
  38. package/src/logger.ts +32 -36
  39. package/src/module-loader.ts +124 -124
  40. package/src/project-astro-files.ts +130 -0
  41. package/src/utils.ts +54 -45
  42. package/src/workers/TSXService.ts +11 -0
  43. package/src/workers/TSXWorker.ts +8 -0
  44. package/test/fixtures/MyAstroComponent.astro +5 -0
  45. package/test/fixtures/script.ts +9 -0
  46. package/test/fixtures/tsconfig.json +3 -0
  47. package/test/runTest.js +41 -0
  48. package/test/suite/extension.test.js +68 -0
  49. package/test/suite/index.js +38 -0
  50. package/test/tsconfig.json +14 -0
  51. package/test/utils.js +65 -0
  52. package/tsconfig.json +2 -1
  53. package/dist/source-mapper.js +0 -114
  54. package/src/source-mapper.ts +0 -123
@@ -1,47 +1,47 @@
1
1
  import type ts from 'typescript/lib/tsserverlibrary';
2
- import { Logger } from './logger.js';
3
- import { AstroSnapshotManager } from './astro-snapshots.js';
2
+ import type { AstroSnapshotManager } from './astro-snapshots.js';
4
3
  import { createAstroSys } from './astro-sys.js';
4
+ import type { 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>();
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
- }
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
- }
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
- }
41
-
42
- private getKey(moduleName: string, containingFile: string) {
43
- return containingFile + ':::' + ensureRealAstroFilePath(moduleName);
44
- }
11
+ private cache = new Map<string, ts.ResolvedModule>();
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
+ }
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
+ }
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
+ }
41
+
42
+ private getKey(moduleName: string, containingFile: string) {
43
+ return containingFile + ':::' + ensureRealAstroFilePath(moduleName);
44
+ }
45
45
  }
46
46
 
47
47
  /**
@@ -54,92 +54,92 @@ 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);
66
-
67
- lsHost.resolveModuleNames = resolveModuleNames;
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
- };
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));
96
-
97
- return resolved.map((moduleName, idx) => {
98
- const fileName = moduleNames[idx];
99
- if (moduleName || !ensureRealAstroFilePath(fileName).endsWith('.astro')) {
100
- return moduleName;
101
- }
102
-
103
- const cachedModule = moduleCache.get(fileName, containingFile);
104
- if (cachedModule) {
105
- return cachedModule;
106
- }
107
-
108
- const resolvedModule = resolveModuleName(fileName, containingFile, compilerOptions);
109
- moduleCache.set(fileName, containingFile, resolvedModule);
110
- return resolvedModule;
111
- });
112
- }
113
-
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
- }
131
-
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
- }
138
-
139
- const resolvedAstroModule: ts.ResolvedModuleFull = {
140
- extension: snapshot.isTsFile ? typescript.Extension.Tsx : typescript.Extension.Jsx,
141
- resolvedFileName
142
- };
143
- return resolvedAstroModule;
144
- }
145
- }
63
+ const astroSys = createAstroSys(logger);
64
+ const moduleCache = new ModuleResolutionCache();
65
+ const origResolveModuleNames = lsHost.resolveModuleNames?.bind(lsHost);
66
+
67
+ lsHost.resolveModuleNames = resolveModuleNames;
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
+ };
75
+
76
+ // Patch readDirectory so we get completions for .astro files
77
+ const origReadDirectory = project.readDirectory.bind(project);
78
+ project.readDirectory = (path, extensions, exclude, include, depth) => {
79
+ const extensionsWithAstro = (extensions ?? []).concat('.astro', '.md', '.mdx');
80
+ return origReadDirectory(path, extensionsWithAstro, exclude, include, depth);
81
+ };
82
+
83
+ function resolveModuleNames(
84
+ moduleNames: string[],
85
+ containingFile: string,
86
+ reusedNames: string[] | undefined,
87
+ redirectedReference: ts.ResolvedProjectReference | undefined,
88
+ compilerOptions: ts.CompilerOptions
89
+ ): Array<ts.ResolvedModule | undefined> {
90
+ // logger.log('Resolving modules names for ' + containingFile);
91
+
92
+ // Try resolving all module names with the original method first.
93
+ // The ones that are undefined will be re-checked if they are a
94
+ // astro file and if so, are resolved, too. This way we can defer
95
+ // all module resolving logic except for astro files to TypeScript.
96
+ const resolved =
97
+ origResolveModuleNames?.(moduleNames, containingFile, reusedNames, redirectedReference, compilerOptions) ||
98
+ Array.from<undefined>(Array(moduleNames.length));
99
+
100
+ return resolved.map((moduleName, idx) => {
101
+ const fileName = moduleNames[idx];
102
+ if (moduleName || !ensureRealAstroFilePath(fileName).endsWith('.astro')) {
103
+ return moduleName;
104
+ }
105
+
106
+ const cachedModule = moduleCache.get(fileName, containingFile);
107
+ if (cachedModule) {
108
+ return cachedModule;
109
+ }
110
+
111
+ const resolvedModule = resolveModuleName(fileName, containingFile, compilerOptions);
112
+ moduleCache.set(fileName, containingFile, resolvedModule);
113
+ return resolvedModule;
114
+ });
115
+ }
116
+
117
+ function resolveModuleName(
118
+ name: string,
119
+ containingFile: string,
120
+ compilerOptions: ts.CompilerOptions
121
+ ): ts.ResolvedModule | undefined {
122
+ const astroResolvedModule = typescript.resolveModuleName(
123
+ name,
124
+ containingFile,
125
+ compilerOptions,
126
+ astroSys
127
+ ).resolvedModule;
128
+ if (!astroResolvedModule || !isVirtualAstroFilePath(astroResolvedModule.resolvedFileName)) {
129
+ return astroResolvedModule;
130
+ }
131
+
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
+ }
138
+
139
+ const resolvedAstroModule: ts.ResolvedModuleFull = {
140
+ extension: typescript.Extension.Tsx,
141
+ resolvedFileName,
142
+ };
143
+ return resolvedAstroModule;
144
+ }
145
+ }
@@ -0,0 +1,130 @@
1
+ import type ts from 'typescript/lib/tsserverlibrary';
2
+ import type { AstroSnapshotManager } from './astro-snapshots';
3
+ import { getConfigPathForProject, isAstroFilePath, readProjectAstroFilesFromFs } from './utils';
4
+
5
+ export class ProjectAstroFilesManager {
6
+ private files = new Set<string>();
7
+ private directoryWatchers = new Set<ts.FileWatcher>();
8
+
9
+ private static instances = new Map<string, ProjectAstroFilesManager>();
10
+
11
+ static getInstance(projectName: string) {
12
+ return this.instances.get(projectName);
13
+ }
14
+
15
+ constructor(
16
+ private readonly typescript: typeof ts,
17
+ private readonly project: ts.server.Project,
18
+ private readonly serverHost: ts.server.ServerHost,
19
+ private readonly snapshotManager: AstroSnapshotManager,
20
+ private parsedCommandLine: ts.ParsedCommandLine
21
+ ) {
22
+ this.setupWatchers();
23
+ this.updateProjectAstroFiles();
24
+
25
+ ProjectAstroFilesManager.instances.set(project.getProjectName(), this);
26
+ }
27
+
28
+ updateProjectConfig(serviceHost: ts.LanguageServiceHost) {
29
+ const parsedCommandLine = serviceHost.getParsedCommandLine?.(getConfigPathForProject(this.project));
30
+
31
+ if (!parsedCommandLine) {
32
+ return;
33
+ }
34
+
35
+ this.disposeWatchersAndFiles();
36
+ this.parsedCommandLine = parsedCommandLine;
37
+ this.setupWatchers();
38
+ this.updateProjectAstroFiles();
39
+ }
40
+
41
+ getFiles() {
42
+ return Array.from(this.files);
43
+ }
44
+
45
+ /**
46
+ * Create directory watcher for include and exclude
47
+ * The watcher in tsserver doesn't support astro file
48
+ * It won't add new created astro file to root
49
+ */
50
+ private setupWatchers() {
51
+ for (const directory in this.parsedCommandLine.wildcardDirectories) {
52
+ if (!Object.prototype.hasOwnProperty.call(this.parsedCommandLine.wildcardDirectories, directory)) {
53
+ continue;
54
+ }
55
+
56
+ const watchDirectoryFlags = this.parsedCommandLine.wildcardDirectories[directory];
57
+ const watcher = this.serverHost.watchDirectory(
58
+ directory,
59
+ this.watcherCallback.bind(this),
60
+ watchDirectoryFlags === this.typescript.WatchDirectoryFlags.Recursive,
61
+ this.parsedCommandLine.watchOptions
62
+ );
63
+
64
+ this.directoryWatchers.add(watcher);
65
+ }
66
+ }
67
+
68
+ private watcherCallback(fileName: string) {
69
+ if (!isAstroFilePath(fileName)) {
70
+ return;
71
+ }
72
+
73
+ // We can't just add the file to the project directly, because
74
+ // - the casing of fileName is different
75
+ // - we don't know whether the file was added or deleted
76
+ this.updateProjectAstroFiles();
77
+ }
78
+
79
+ private updateProjectAstroFiles() {
80
+ const fileNamesAfter = readProjectAstroFilesFromFs(this.typescript, this.project, this.parsedCommandLine);
81
+ const removedFiles = new Set(...this.files);
82
+ const newFiles = fileNamesAfter.filter((fileName) => {
83
+ const has = this.files.has(fileName);
84
+ if (has) {
85
+ removedFiles.delete(fileName);
86
+ }
87
+ return !has;
88
+ });
89
+
90
+ for (const newFile of newFiles) {
91
+ this.addFileToProject(newFile);
92
+ this.files.add(newFile);
93
+ }
94
+ for (const removedFile of removedFiles) {
95
+ this.removeFileFromProject(removedFile, false);
96
+ this.files.delete(removedFile);
97
+ }
98
+ }
99
+
100
+ private addFileToProject(newFile: string) {
101
+ this.snapshotManager.create(newFile);
102
+ const snapshot = this.project.projectService.getScriptInfo(newFile);
103
+
104
+ if (snapshot) {
105
+ this.project.addRoot(snapshot);
106
+ }
107
+ }
108
+
109
+ private removeFileFromProject(file: string, exists = true) {
110
+ const info = this.project.getScriptInfo(file);
111
+
112
+ if (info) {
113
+ this.project.removeFile(info, exists, true);
114
+ }
115
+ }
116
+
117
+ private disposeWatchersAndFiles() {
118
+ this.directoryWatchers.forEach((watcher) => watcher.close());
119
+ this.directoryWatchers.clear();
120
+
121
+ this.files.forEach((file) => this.removeFileFromProject(file));
122
+ this.files.clear();
123
+ }
124
+
125
+ dispose() {
126
+ this.disposeWatchersAndFiles();
127
+
128
+ ProjectAstroFilesManager.instances.delete(this.project.getProjectName());
129
+ }
130
+ }
package/src/utils.ts CHANGED
@@ -1,66 +1,75 @@
1
1
  export function isAstroFilePath(filePath: string) {
2
- return filePath.endsWith('.astro');
2
+ return filePath.endsWith('.astro');
3
3
  }
4
4
 
5
5
  export function isVirtualAstroFilePath(filePath: string) {
6
- return filePath.endsWith('.astro.ts');
6
+ return filePath.endsWith('.astro.ts');
7
7
  }
8
8
 
9
9
  export function toRealAstroFilePath(filePath: string) {
10
- return filePath.slice(0, -'.ts'.length);
10
+ return filePath.slice(0, -'.ts'.length);
11
11
  }
12
12
 
13
13
  export function ensureRealAstroFilePath(filePath: string) {
14
- return isVirtualAstroFilePath(filePath) ? toRealAstroFilePath(filePath) : filePath;
14
+ return isVirtualAstroFilePath(filePath) ? toRealAstroFilePath(filePath) : filePath;
15
15
  }
16
16
 
17
17
  export function isNotNullOrUndefined<T>(val: T | undefined | null): val is T {
18
- return val !== undefined && val !== null;
18
+ return val !== undefined && val !== null;
19
19
  }
20
20
 
21
21
  /**
22
- * Checks if this a section that should be completely ignored
23
- * because it's purely generated.
24
- */
25
- export function isInGeneratedCode(text: string, start: number, end: number) {
26
- const lineStart = text.lastIndexOf('\n', start);
27
- const lineEnd = text.indexOf('\n', end);
28
- const lastStart = text.substring(lineStart, start).lastIndexOf('/*Ωignore_startΩ*/');
29
- const lastEnd = text.substring(lineStart, start).lastIndexOf('/*Ωignore_endΩ*/');
30
- return lastStart > lastEnd && text.substring(end, lineEnd).includes('/*Ωignore_endΩ*/');
22
+ * Replace all occurrences of a string within an object with another string,
23
+ */
24
+ export function replaceDeep<T extends Record<string, any>>(
25
+ obj: T,
26
+ searchStr: string | RegExp,
27
+ replacementStr: string
28
+ ): T {
29
+ return _replaceDeep(obj);
30
+
31
+ function _replaceDeep(_obj: any): any {
32
+ if (typeof _obj === 'string') {
33
+ return _obj.replace(searchStr, replacementStr);
34
+ }
35
+ if (Array.isArray(_obj)) {
36
+ return _obj.map((entry) => _replaceDeep(entry));
37
+ }
38
+ if (typeof _obj === 'object') {
39
+ return Object.keys(_obj).reduce((_o, key) => {
40
+ _o[key] = _replaceDeep(_obj[key]);
41
+ return _o;
42
+ }, {} as any);
43
+ }
44
+ return _obj;
45
+ }
31
46
  }
32
47
 
33
- /**
34
- * Checks that this isn't a text span that should be completely ignored
35
- * because it's purely generated.
36
- */
37
- export function isNoTextSpanInGeneratedCode(text: string, span: ts.TextSpan) {
38
- return !isInGeneratedCode(text, span.start, span.start + span.length);
48
+ export function getConfigPathForProject(project: ts.server.Project) {
49
+ return (
50
+ (project as ts.server.ConfiguredProject).canonicalConfigFilePath ??
51
+ (project.getCompilerOptions() as any).configFilePath
52
+ );
39
53
  }
40
54
 
41
- /**
42
- * Replace all occurrences of a string within an object with another string,
43
- */
44
- export function replaceDeep<T extends Record<string, any>>(
45
- obj: T,
46
- searchStr: string | RegExp,
47
- replacementStr: string
48
- ): T {
49
- return _replaceDeep(obj);
55
+ export function readProjectAstroFilesFromFs(
56
+ ts: typeof import('typescript/lib/tsserverlibrary'),
57
+ project: ts.server.Project,
58
+ parsedCommandLine: ts.ParsedCommandLine
59
+ ) {
60
+ const fileSpec: TsFilesSpec = parsedCommandLine.raw;
61
+ const { include, exclude } = fileSpec;
62
+
63
+ if (include?.length === 0) {
64
+ return [];
65
+ }
50
66
 
51
- function _replaceDeep(_obj: any): any {
52
- if (typeof _obj === 'string') {
53
- return _obj.replace(searchStr, replacementStr);
54
- }
55
- if (Array.isArray(_obj)) {
56
- return _obj.map((entry) => _replaceDeep(entry));
57
- }
58
- if (typeof _obj === 'object') {
59
- return Object.keys(_obj).reduce((_o, key) => {
60
- _o[key] = _replaceDeep(_obj[key]);
61
- return _o;
62
- }, {} as any);
63
- }
64
- return _obj;
65
- }
66
- }
67
+ return ts.sys
68
+ .readDirectory(project.getCurrentDirectory() || process.cwd(), ['.astro'], exclude, include)
69
+ .map(ts.server.toNormalizedPath);
70
+ }
71
+
72
+ export interface TsFilesSpec {
73
+ include?: readonly string[];
74
+ exclude?: readonly string[];
75
+ }
@@ -0,0 +1,11 @@
1
+ import type { TSXResult } from '@astrojs/compiler/shared/types';
2
+ import { createSyncFn } from 'synckit';
3
+
4
+ const convertToTSXSync = createSyncFn(require.resolve('./TSXWorker'));
5
+
6
+ /**
7
+ * Parse code by `@astrojs/compiler`
8
+ */
9
+ export function convertToTSX(source: string, options: { sourcefile: string }): TSXResult {
10
+ return convertToTSXSync(source, options);
11
+ }
@@ -0,0 +1,8 @@
1
+ import { runAsWorker } from 'synckit';
2
+
3
+ const dynamicImport = new Function('m', 'return import(m)');
4
+ runAsWorker(async (source: string, options: { sourcefile: string }) => {
5
+ const { convertToTSX } = await dynamicImport('@astrojs/compiler');
6
+ const result: any = convertToTSX(source, options);
7
+ return result;
8
+ });
@@ -0,0 +1,5 @@
1
+ ---
2
+ import { Hello, sayHello } from "./script"
3
+
4
+ class MyHello implements Hello {}
5
+ ---
@@ -0,0 +1,9 @@
1
+ export function sayHello() {
2
+ console.log("Hello")
3
+ }
4
+
5
+ MyAstroCompon
6
+
7
+ export class Hello {
8
+
9
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ // Purposely empty, this is done so TypeScript knows where the root of the project is and doesn't try to go too high into the monorepo
3
+ }
@@ -0,0 +1,41 @@
1
+ const path = require('path');
2
+ const { runTests } = require('@vscode/test-electron');
3
+ const { downloadDirToExecutablePath } = require('./utils');
4
+ const { existsSync, readdirSync } = require('fs');
5
+
6
+ async function main() {
7
+ try {
8
+ // The folder containing the Extension Manifest package.json
9
+ // Passed to `--extensionDevelopmentPath`
10
+ const extensionDevelopmentPath = path.resolve(__dirname, '../../vscode');
11
+
12
+ // The path to the extension test script
13
+ // Passed to --extensionTestsPath
14
+ const extensionTestsPath = path.resolve(__dirname, './suite/index.js');
15
+
16
+ // If there's already a downloaded version of VS Code, let's use it
17
+ const vscodeTestPath = path.resolve(__dirname, '../../vscode/.vscode-test');
18
+ let vsPath = undefined;
19
+ if (existsSync(vscodeTestPath)) {
20
+ const files = readdirSync(vscodeTestPath);
21
+ files.forEach((file) => {
22
+ if (file.startsWith('vscode-')) {
23
+ vsPath = downloadDirToExecutablePath(path.resolve(__dirname, '../../vscode/.vscode-test/', file));
24
+ return;
25
+ }
26
+ });
27
+ }
28
+
29
+ await runTests({
30
+ extensionDevelopmentPath,
31
+ extensionTestsPath,
32
+ vscodeExecutablePath: vsPath,
33
+ launchArgs: ['./fixtures/fixtures.code-workspace'],
34
+ });
35
+ } catch (err) {
36
+ console.error('Failed to run tests');
37
+ process.exit(1);
38
+ }
39
+ }
40
+
41
+ main();