11import { EOL } from "os" ;
22import * as path from "path" ;
33import * as helpers from "../common/helpers" ;
4- import { TrackActionNames } from "../constants" ;
4+ import { TrackActionNames , NODE_MODULES_FOLDER_NAME , TNS_CORE_MODULES_NAME } from "../constants" ;
55import { doctor , constants } from "nativescript-doctor" ;
66
7- class DoctorService implements IDoctorService {
7+ export class DoctorService implements IDoctorService {
88 private static DarwinSetupScriptLocation = path . join ( __dirname , ".." , ".." , "setup" , "mac-startup-shell-script.sh" ) ;
99 private static WindowsSetupScriptExecutable = "powershell.exe" ;
1010 private static WindowsSetupScriptArguments = [ "start-process" , "-FilePath" , "PowerShell.exe" , "-NoNewWindow" , "-Wait" , "-ArgumentList" , '"-NoProfile -ExecutionPolicy Bypass -Command iex ((new-object net.webclient).DownloadString(\'https://www.nativescript.org/setup/win\'))"' ] ;
@@ -14,10 +14,12 @@ class DoctorService implements IDoctorService {
1414 private $logger : ILogger ,
1515 private $childProcess : IChildProcess ,
1616 private $injector : IInjector ,
17+ private $projectDataService : IProjectDataService ,
18+ private $fs : IFileSystem ,
1719 private $terminalSpinnerService : ITerminalSpinnerService ,
1820 private $versionsService : IVersionsService ) { }
1921
20- public async printWarnings ( configOptions ?: { trackResult : boolean , projectDir ?: string , runtimeVersion ?: string , options ?: IOptions } ) : Promise < void > {
22+ public async printWarnings ( configOptions ?: { trackResult : boolean , projectDir ?: string , runtimeVersion ?: string , options ?: IOptions } ) : Promise < void > {
2123 const infos = await this . $terminalSpinnerService . execute < NativeScriptDoctor . IInfo [ ] > ( {
2224 text : `Getting environment information ${ EOL } `
2325 } , ( ) => doctor . getInfos ( { projectDir : configOptions && configOptions . projectDir , androidRuntimeVersion : configOptions && configOptions . runtimeVersion } ) ) ;
@@ -48,6 +50,8 @@ class DoctorService implements IDoctorService {
4850 this . $logger . error ( "Cannot get the latest versions information from npm. Please try again later." ) ;
4951 }
5052
53+ this . checkForDeprecatedShortImportsInAppDir ( configOptions . projectDir ) ;
54+
5155 await this . $injector . resolve < IPlatformEnvironmentRequirements > ( "platformEnvironmentRequirements" ) . checkEnvironmentRequirements ( {
5256 platform : null ,
5357 projectDir : configOptions && configOptions . projectDir ,
@@ -113,6 +117,59 @@ class DoctorService implements IDoctorService {
113117 return ! hasWarnings ;
114118 }
115119
120+ public checkForDeprecatedShortImportsInAppDir ( projectDir : string ) : void {
121+ if ( projectDir ) {
122+ try {
123+ const files = this . $projectDataService . getAppExecutableFiles ( projectDir ) ;
124+ const shortImports = this . getDeprecatedShortImportsInFiles ( files , projectDir ) ;
125+ if ( shortImports . length ) {
126+ this . $logger . printMarkdown ( "Detected short imports in your application. Please note that `short imports are deprecated` since NativeScript 5.2.0. More information can be found in this blogpost https://www.nativescript.org/blog/say-goodbye-to-short-imports-in-nativescript" ) ;
127+ shortImports . forEach ( shortImport => {
128+ this . $logger . printMarkdown ( `In file \`${ shortImport . file } \` line \`${ shortImport . line } \` is short import. Add \`tns-core-modules/\` in front of the required/imported module.` ) ;
129+ } ) ;
130+ }
131+ } catch ( err ) {
132+ this . $logger . trace ( `Unable to validate if project has short imports. Error is` , err ) ;
133+ }
134+ }
135+ }
136+
137+ protected getDeprecatedShortImportsInFiles ( files : string [ ] , projectDir : string ) : { file : string , line : string } [ ] {
138+ const shortImportRegExps = this . getShortImportRegExps ( projectDir ) ;
139+ const shortImports : { file : string , line : string } [ ] = [ ] ;
140+
141+ for ( const file of files ) {
142+ const fileContent = this . $fs . readText ( file ) ;
143+ const strippedComments = helpers . stripComments ( fileContent ) ;
144+ const linesWithRequireStatements = strippedComments
145+ . split ( / \r ? \n / )
146+ . filter ( line => / \b t n s - c o r e - m o d u l e s \b / . exec ( line ) === null && ( / \b i m p o r t \b / . exec ( line ) || / \b r e q u i r e \b / . exec ( line ) ) ) ;
147+
148+ for ( const line of linesWithRequireStatements ) {
149+ for ( const regExp of shortImportRegExps ) {
150+ const matches = line . match ( regExp ) ;
151+
152+ if ( matches && matches . length ) {
153+ shortImports . push ( { file, line } ) ;
154+ break ;
155+ }
156+ }
157+ }
158+ }
159+
160+ return shortImports ;
161+ }
162+
163+ private getShortImportRegExps ( projectDir : string ) : RegExp [ ] {
164+ const pathToTnsCoreModules = path . join ( projectDir , NODE_MODULES_FOLDER_NAME , TNS_CORE_MODULES_NAME ) ;
165+ const contents = this . $fs . readDirectory ( pathToTnsCoreModules )
166+ . filter ( entry => this . $fs . getFsStats ( path . join ( pathToTnsCoreModules , entry ) ) . isDirectory ( ) ) ;
167+
168+ const regExps = contents . map ( c => new RegExp ( `[\"\']${ c } [\"\'/]` , "g" ) ) ;
169+
170+ return regExps ;
171+ }
172+
116173 private async runSetupScriptCore ( executablePath : string , setupScriptArgs : string [ ] ) : Promise < ISpawnResult > {
117174 return this . $childProcess . spawnFromEvent ( executablePath , setupScriptArgs , "close" , { stdio : "inherit" } ) ;
118175 }
0 commit comments