11import type { LanguagePlugin , VirtualCode } from '@volar/language-core'
2+ import type { TypeScriptServiceScript } from '@volar/typescript'
23import type * as ets from 'ohos-typescript'
34import type * as ts from 'typescript'
45import type { URI } from 'vscode-uri'
@@ -7,10 +8,6 @@ import { $$thisFixerPlugin } from './$$this-fixer-plugin'
78import { ESObjectPlugin } from './es-object-plugin'
89import { createEmptyVirtualCode , createVirtualCode , ETSVirtualCode } from './ets-code'
910
10- function isEts ( tsOrEts : typeof ets | typeof ts ) : tsOrEts is typeof ets {
11- return 'ETS' in tsOrEts . ScriptKind && tsOrEts . ScriptKind . ETS === 8
12- }
13-
1411export interface ETSLanguagePluginOptions {
1512 /**
1613 * Paths excluded from virtual code. It is very useful when you want to disable files in the `openharmony` & `hms` sdk.
@@ -39,97 +36,132 @@ export function ETSLanguagePlugin(tsOrEts: typeof ts, options?: ETSLanguagePlugi
3936export function ETSLanguagePlugin ( tsOrEts : typeof ets , options ?: ETSLanguagePluginOptions ) : LanguagePlugin < URI | string >
4037export function ETSLanguagePlugin ( tsOrEts : typeof ets | typeof ts , { excludePaths = [ ] , tsdk = '' } : ETSLanguagePluginOptions = { } ) : LanguagePlugin < URI | string > {
4138 const isETSServerMode = isEts ( tsOrEts )
42- const isTSPluginMode = ! isETSServerMode
4339
44- // full feature virtual code
45- const getFullVirtualCode = ( snapshot : ts . IScriptSnapshot , languageId : string ) : VirtualCode => (
46- createVirtualCode ( snapshot , languageId , {
47- completion : true ,
48- format : true ,
49- navigation : true ,
50- semantic : true ,
51- structure : true ,
52- verification : true ,
53- } )
54- )
40+ function getLanguageId ( uri : URI | string ) : string | undefined {
41+ const filePath = typeof uri === 'string' ? uri : uri . fsPath
42+ if ( filePath . endsWith ( '.ets' ) ) return 'ets'
43+ if ( filePath . endsWith ( '.ts' ) ) return 'typescript'
44+ if ( filePath . endsWith ( '.json' ) || filePath . endsWith ( '.json5' ) || filePath . endsWith ( '.jsonc' ) || filePath . endsWith ( '.tsbuildinfo' ) ) return 'json'
45+ return undefined
46+ }
47+
48+ function getScriptKindByFilePath ( filePath : string , defaultExtension : string = '.ets' ) : [ ets . ScriptKind , string ] {
49+ if ( ! filePath ) return [ 7 satisfies typeof ets . ScriptKind . Deferred , defaultExtension ]
50+ if ( filePath . endsWith ( '.d.ts' ) ) return [ 3 satisfies typeof ets . ScriptKind . TS , '.d.ts' ]
51+ if ( filePath . endsWith ( '.d.ets' ) ) return [ 8 satisfies typeof ets . ScriptKind . ETS , '.d.ets' ]
52+ if ( filePath . endsWith ( '.d.cts' ) ) return [ 3 satisfies typeof ets . ScriptKind . TS , '.d.cts' ]
53+ if ( filePath . endsWith ( '.d.mts' ) ) return [ 3 satisfies typeof ets . ScriptKind . TS , '.d.mts' ]
5554
56- // disabled virtual code, but still keep the full content
57- const getDisabledVirtualCode = ( snapshot : ts . IScriptSnapshot , languageId : string ) : VirtualCode => (
58- createVirtualCode ( snapshot , languageId , {
59- completion : false ,
60- format : false ,
61- navigation : false ,
62- semantic : false ,
63- structure : false ,
64- verification : false ,
65- } )
66- )
55+ const extension = path . extname ( filePath )
56+ switch ( extension ) {
57+ case '.ts' :
58+ case '.cts' :
59+ case '.mts' :
60+ return [ 3 satisfies typeof ets . ScriptKind . TS , extension ]
61+ case '.ets' :
62+ return [ 8 satisfies typeof ets . ScriptKind . ETS , extension ]
63+ default :
64+ return [ 7 satisfies typeof ets . ScriptKind . Deferred , extension ]
65+ }
66+ }
6767
68- // disabled virtual code, and remove the full content to empty string
69- const getFullDisabledVirtualCode = ( snapshot : ts . IScriptSnapshot , languageId : string ) : VirtualCode => (
70- createEmptyVirtualCode ( snapshot , languageId , {
71- completion : false ,
72- format : false ,
73- navigation : false ,
74- semantic : false ,
75- structure : false ,
76- verification : false ,
77- } )
78- )
68+ if ( isETSServerMode ) {
69+ return {
70+ getLanguageId,
71+ createVirtualCode ( uri , languageId , snapshot ) {
72+ const filePath = path . resolve ( typeof uri === 'string' ? uri : uri . fsPath )
73+ if ( languageId === 'ets' ) {
74+ return new ETSVirtualCode (
75+ filePath ,
76+ tsOrEts . createSourceFile ( filePath , snapshot . getText ( 0 , snapshot . getLength ( ) ) , 99 as any ) as unknown as ts . SourceFile ,
77+ 'typescript' ,
78+ [ $$thisFixerPlugin ( ) , ESObjectPlugin ( ) ] as any ,
79+ )
80+ }
81+ // json5、json files, directly using full feature virtual code
82+ if ( filePath . endsWith ( '.json' ) || filePath . endsWith ( '.json5' ) || filePath . endsWith ( '.jsonc' ) || languageId === 'json' || languageId === 'jsonc' ) return getFullVirtualCode ( snapshot , languageId )
83+ // tsdk files we must disable the full feature virtual code but still keep the full content
84+ if ( filePath . startsWith ( tsdk ) ) return getDisabledVirtualCode ( snapshot , languageId )
85+ } ,
86+ typescript : {
87+ extraFileExtensions : [
88+ // eslint-disable-next-line ts/ban-ts-comment
89+ // @ts -expect-error
90+ { extension : 'ets' , isMixedContent : false , scriptKind : 8 satisfies ets . ScriptKind . ETS } ,
91+ // eslint-disable-next-line ts/ban-ts-comment
92+ // @ts -expect-error
93+ { extension : 'd.ets' , isMixedContent : false , scriptKind : 8 satisfies ets . ScriptKind . ETS } ,
94+ ] ,
95+ resolveHiddenExtensions : true ,
96+ getServiceScript ( root : VirtualCode & { filePath : string } ) {
97+ const [ scriptKind , extension ] = getScriptKindByFilePath ( root . filePath )
98+ return {
99+ code : root ,
100+ extension,
101+ scriptKind,
102+ } as unknown as TypeScriptServiceScript
103+ } ,
104+ } ,
105+ }
106+ }
79107
80108 return {
81- getLanguageId ( uri ) {
82- const filePath = typeof uri === 'string' ? uri : uri . fsPath
83- if ( filePath . endsWith ( '.ets' ) ) return 'ets'
84- if ( filePath . endsWith ( '.ts' ) ) return 'typescript'
85- if ( filePath . endsWith ( '.json' ) || filePath . endsWith ( '.json5' ) || filePath . endsWith ( '.jsonc' ) ) return 'json'
86- return undefined
87- } ,
109+ getLanguageId,
88110 createVirtualCode ( uri , languageId , snapshot ) {
89111 const filePath = path . resolve ( typeof uri === 'string' ? uri : uri . fsPath )
90112 const isInExcludePath = excludePaths . some ( excludePath => filePath . startsWith ( excludePath ) )
91- const isInTsdkPath = filePath . startsWith ( tsdk )
92- const isDTS = filePath . endsWith ( '.d.ts' )
93- const isDETS = filePath . endsWith ( '.d.ets' )
94-
95- // json5、json files, directly using full feature virtual code
96- if ( filePath . endsWith ( '.json' ) || filePath . endsWith ( '.json5' ) || filePath . endsWith ( '.jsonc' ) || languageId === 'json' || languageId === 'jsonc' ) return getFullVirtualCode ( snapshot , languageId )
97-
98- // ets files, using ts-macro to generate the virtual code
99- if ( languageId === 'ets' ) {
100- return new ETSVirtualCode (
101- filePath ,
102- tsOrEts . createSourceFile ( filePath , snapshot . getText ( 0 , snapshot . getLength ( ) ) , 99 as any ) as ts . SourceFile ,
103- 'typescript' ,
104- [ $$thisFixerPlugin ( ) , ESObjectPlugin ( ) ] as any ,
105- )
106- }
107- // ETS Server mode
108- if ( isETSServerMode && ! ( isDTS || isDETS ) && ! isInExcludePath ) return getDisabledVirtualCode ( snapshot , languageId )
109- // TS Plugin mode
110- if ( isTSPluginMode && ( isDTS || isDETS ) && isInExcludePath ) {
111- return getFullDisabledVirtualCode ( snapshot , languageId )
112- }
113- // Proxy ts internal lib files, such as `lib.d.ts`, `lib.es2020.d.ts`, etc.
114- if ( isETSServerMode && ( isDTS || isDETS ) && isInTsdkPath ) return getDisabledVirtualCode ( snapshot , languageId )
113+ if ( ( filePath . endsWith ( '.d.ts' ) || filePath . endsWith ( '.d.ets' ) ) && isInExcludePath ) return getFullDisabledVirtualCode ( snapshot , languageId , { filePath } )
115114 } ,
116115 typescript : {
117- // eslint-disable-next-line ts/ban-ts-comment
118- // @ts -expect-error
119- extraFileExtensions : isETSServerMode
120- ? [
121- { extension : 'ets' , isMixedContent : false , scriptKind : 8 satisfies ets . ScriptKind . ETS } ,
122- { extension : 'd.ets' , isMixedContent : false , scriptKind : 8 satisfies ets . ScriptKind . ETS } ,
123- ]
124- : [ ] ,
125- resolveHiddenExtensions : true ,
126- getServiceScript ( root ) {
116+ extraFileExtensions : [ ] ,
117+ getServiceScript ( root : VirtualCode & { filePath : string } ) {
118+ const [ scriptKind , extension ] = getScriptKindByFilePath ( root . filePath , '.ts' )
127119 return {
128120 code : root ,
129- extension : '.ets' ,
130- scriptKind : 3 satisfies typeof ets . ScriptKind . TS ,
121+ extension,
122+ scriptKind : scriptKind as ts . ScriptKind ,
131123 }
132124 } ,
133125 } ,
134126 }
135127}
128+
129+ function isEts ( tsOrEts : typeof ets | typeof ts ) : tsOrEts is typeof ets {
130+ return 'ETS' in tsOrEts . ScriptKind && tsOrEts . ScriptKind . ETS === 8
131+ }
132+
133+ // full feature virtual code
134+ function getFullVirtualCode ( snapshot : ts . IScriptSnapshot , languageId : string ) : VirtualCode {
135+ return createVirtualCode ( snapshot , languageId , {
136+ completion : true ,
137+ format : true ,
138+ navigation : true ,
139+ semantic : true ,
140+ structure : true ,
141+ verification : true ,
142+ } )
143+ }
144+
145+ // disabled virtual code, but still keep the full content
146+ function getDisabledVirtualCode ( snapshot : ts . IScriptSnapshot , languageId : string ) : VirtualCode {
147+ return createVirtualCode ( snapshot , languageId , {
148+ completion : false ,
149+ format : false ,
150+ navigation : false ,
151+ semantic : false ,
152+ structure : false ,
153+ verification : false ,
154+ } )
155+ }
156+
157+ // disabled virtual code, and remove the full content to empty string
158+ function getFullDisabledVirtualCode < T extends Record < string , any > > ( snapshot : ts . IScriptSnapshot , languageId : string , options ?: T ) : VirtualCode & T {
159+ return createEmptyVirtualCode ( snapshot , languageId , {
160+ completion : false ,
161+ format : false ,
162+ navigation : false ,
163+ semantic : false ,
164+ structure : false ,
165+ verification : false ,
166+ } , options )
167+ }
0 commit comments