-
-
Notifications
You must be signed in to change notification settings - Fork 13
Expand file tree
/
Copy pathindex.cts
More file actions
126 lines (117 loc) · 5.61 KB
/
index.cts
File metadata and controls
126 lines (117 loc) · 5.61 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
import type { CMKConfig } from '@css-modules-kit/core';
import { createMatchesPattern, createResolver, readConfigFile } from '@css-modules-kit/core';
import { TsConfigFileNotFoundError } from '@css-modules-kit/core';
import type { Language } from '@volar/language-core';
import { createLanguageServicePlugin } from '@volar/typescript/lib/quickstart/createLanguageServicePlugin.js';
import type ts from 'typescript';
import { createCSSLanguagePlugin } from './language-plugin.js';
import { proxyLanguageService } from './language-service/proxy.js';
import { createDocumentLinkHandler } from './protocol-handler/documentLink.js';
import { createGetEditsForFileRenameHandler } from './protocol-handler/getEditsForFileRename.js';
import { createRenameHandler } from './protocol-handler/rename.js';
import { createRenameInfoHandler } from './protocol-handler/renameInfo.js';
import { CustomSourceMap } from './source-map.js';
const projectToLanguage = new WeakMap<ts.server.Project, Language<string>>();
const plugin = createLanguageServicePlugin((ts, info) => {
if (info.project.projectKind !== ts.server.ProjectKind.Configured) {
info.project.projectService.logger.info(`[@css-modules-kit/ts-plugin] info: Project is not configured`);
return { languagePlugins: [] };
}
let config: CMKConfig;
try {
config = readConfigFile(info.project.getProjectName());
// TODO: Report diagnostics
info.project.projectService.logger.info(
`[@css-modules-kit/ts-plugin] info: Config file is found '${config.configFileName}'`,
);
} catch (error) {
// If the config file is not found, disable the plugin.
if (error instanceof TsConfigFileNotFoundError) {
return { languagePlugins: [] };
} else {
let msg = `[@css-modules-kit/ts-plugin] error: Fail to read config file`;
if (error instanceof Error) {
msg += `\n: ${error.message}`;
msg += `\n${error.stack}`;
}
info.project.projectService.logger.info(msg);
return { languagePlugins: [] };
}
}
if (!config.enabled) {
return { languagePlugins: [] };
}
// tsserver should report a "Cannot find module" error for import statements in CSS Modules that
// do not exist. However, if `dtsOutDir` is included in `rootDirs` and old .d.ts files remain
// in `dtsOutDir`, the error will not be reported. Therefore, remove `dtsOutDir` from `rootDirs`.
const getCompilationSettings = info.languageServiceHost.getCompilationSettings.bind(info.languageServiceHost);
info.languageServiceHost.getCompilationSettings = () => {
const settings = getCompilationSettings();
return new Proxy(settings, {
get(target, prop, receiver) {
if (prop === 'rootDirs' && target.rootDirs) {
return target.rootDirs.filter((dir) => dir !== config.dtsOutDir);
}
return Reflect.get(target, prop, receiver);
},
});
};
const moduleResolutionCache = info.languageServiceHost.getModuleResolutionCache?.();
const resolver = createResolver(config.compilerOptions, moduleResolutionCache);
const matchesPattern = createMatchesPattern(config);
return {
languagePlugins: [createCSSLanguagePlugin(matchesPattern, config)],
setup: (language) => {
language.mapperFactory = (mappings) => new CustomSourceMap(mappings);
projectToLanguage.set(info.project, language);
info.languageService = proxyLanguageService(
language,
info.languageService,
info.project,
resolver,
matchesPattern,
config,
);
if (info.session) {
// Register protocol handlers for "Request Forwarding to tsserver".
// See https://github.com/mizdra/css-modules-kit/pull/207 for more details.
// `info.session.addProtocolHandler` cannot register multiple handlers with the same command name.
// Attempting to do so will result in an error.
//
// By the way, tsserver creates one ConfiguredProject for each tsconfig.json file. Then, tsserver
// initializes each plugin for each ConfiguredProject. This means that if there are multiple
// tsconfig.json files, the handler will be registered multiple times.
//
// Therefore, we will do the following:
// - Implement the handler to handle files from different projects
// - Skip registration if the handler is already registered
try {
info.session.addProtocolHandler('_css-modules-kit:rename', createRenameHandler(info.project.projectService));
info.session.addProtocolHandler(
'_css-modules-kit:renameInfo',
createRenameInfoHandler(info.project.projectService),
);
info.session.addProtocolHandler(
'_css-modules-kit:getEditsForFileRename',
createGetEditsForFileRenameHandler(info.project.projectService),
);
info.session.addProtocolHandler(
'_css-modules-kit:documentLink',
createDocumentLinkHandler(info.project.projectService, projectToLanguage, resolver),
);
} catch {
info.project.projectService.logger.info(
`[@css-modules-kit/ts-plugin] Skipping protocol handler registration because the handlers are already registered.`,
);
}
} else {
// When a plugin is used via tsserver from the editor, the session is always available.
// However, when a plugin is used via the TypeScript Compiler API, the session may not be available.
info.project.projectService.logger.info(
'[@css-modules-kit/ts-plugin] info: Skipping protocol handler registration because session is not available.',
);
}
},
};
});
export = plugin;