11/*
2- * Copyright (c) 2016-2025 Moddable Tech, Inc.
2+ * Copyright (c) 2016-2026 Moddable Tech, Inc.
33 *
44 * This file is part of the Moddable SDK Tools.
55 *
@@ -725,26 +725,52 @@ otadata, data, ota, , ${OTADATA_SIZE},`;
725725 options += " -d" ;
726726 if ( tool . nativeCode )
727727 options += " -c" ;
728+ const check = ( TSConfigFile . filter ( tool , [ { source} ] ) ) . length ;
729+ const typeCheck = tool . typeCheck && check ;
730+ const lintCheck = tool . lintCheck && check ;
728731
729732 if ( tool . platform == "zephyr" ) {
730733 source = source . replaceAll ( "#" , tool . escapedHash ) ;
731734 var output = "${MODULES_DIR}" + tool . slash + target . replaceAll ( "#" , tool . escapedHash ) ;
732735 var outputPath = output . slice ( 0 , output . lastIndexOf ( "/" ) ) ;
733736 this . line ( "add_custom_command(" ) ;
734737 this . line ( "\tOUTPUT " + output ) ;
738+ if ( lintCheck )
739+ this . line ( "\tCOMMAND eslint " + source + " --config ${MODDABLE}/eslint.config.mjs" ) ;
735740 this . line ( "\tCOMMAND xsc " + source + " " + options + " -e -o " + outputPath + " -r " + targetParts . name . replaceAll ( "#" , tool . escapedHash ) ) ;
736- this . line ( "\tDEPENDS " + source ) ;
741+ this . line ( "\tDEPENDS " + source + ( typeCheck ? " ${TYPECHECK_FILE}" : "" ) ) ;
742+ this . line ( "\tWORKING_DIRECTORY ${MODDABLE}" ) ;
737743 this . line ( "\tVERBATIM)" ) ;
738744 this . line ( "" ) ;
739745 }
740746 else {
741- this . line ( "$(MODULES_DIR)" , tool . slash , target . replaceAll ( "#" , tool . escapedHash ) , ": " , source . replaceAll ( "#" , tool . escapedHash ) ) ;
747+ this . line ( "$(MODULES_DIR)" , tool . slash , target . replaceAll ( "#" , tool . escapedHash ) , ": " , source . replaceAll ( "#" , tool . escapedHash ) , typeCheck ? " $(MODULES_DIR)" + tool . slash + ".typeCheck" : "" ) ;
748+ if ( lintCheck ) {
749+ this . echo ( tool , "eslint " , source . split ( tool . slash ) . at ( - 1 ) ) ;
750+ this . line ( "\tcd $(MODDABLE) && eslint " , source , " --config $(MODDABLE)/eslint.config.mjs" ) ;
751+ }
742752 this . echo ( tool , "xsc " , target ) ;
743753 this . line ( "\txsc " , source , options , " -e -o $(@D) -r " , targetParts . name . replaceAll ( "#" , "\\#" ) ) ;
744754 }
745755 }
746756 this . line ( "" ) ;
747757
758+ if ( tool . typeCheck ) {
759+ const sources = TSConfigFile . filter ( tool , tool . jsFiles ) ;
760+ if ( "zephyr" === tool . platform ) {
761+ this . line ( "set(JAVASCRIPT_SOURCE_FILES" ) ;
762+ sources . map ( file => file . source . replaceAll ( "#" , tool . escapedHash ) ) . forEach ( source => this . line ( "\t" , source ) ) ;
763+ this . line ( ")" ) ;
764+ }
765+ else {
766+ this . line ( "$(MODULES_DIR)" , tool . slash , ".typeCheck: " + sources . map ( item => item . source ) . join ( " " ) ) ;
767+ this . echo ( tool , "tsc " , "tsconfig-js.json" , " (typeCheck JavaScript)" ) ;
768+ this . line ( "\t" , tool . typescript . compiler , " -p $(MODULES_DIR)" , tool . slash , "tsconfig-js.json" ) ;
769+ this . line ( "\t" , "touch $(MODULES_DIR)" , tool . slash , ".typeCheck" ) ;
770+ this . line ( "" ) ;
771+ }
772+ }
773+
748774 if ( tool . tsFiles . length ) {
749775 let directories = tool . tsFiles . map ( item => tool . splitPath ( item . source ) . directory ) ;
750776 const length = directories . length ;
@@ -796,8 +822,11 @@ otadata, data, ota, , ${OTADATA_SIZE},`;
796822
797823 this . line ( "add_custom_command(" ) ;
798824 this . line ( "\tOUTPUT ${MODULES_DIR}" , temporary . slice ( 0 , - 3 ) , ".xsb" ) ;
825+ if ( tool . lintCheck )
826+ this . line ( "\tCOMMAND eslint " + source + " --config ${MODDABLE}/eslint.config.mjs" ) ;
799827 this . line ( "\tCOMMAND xsc ${MODULES_DIR}" , temporary , options , " -e -o ${MODULES_DIR} -r " , targetParts . name . replaceAll ( "#" , tool . escapedHash ) ) ;
800828 this . line ( "\tDEPENDS ${MODULES_DIR}" , temporary ) ;
829+ this . line ( "\tWORKING_DIRECTORY ${MODDABLE}" ) ;
801830 this . line ( "\tVERBATIM" ) ;
802831 this . line ( ")" ) ;
803832 this . line ( "" ) ;
@@ -810,6 +839,11 @@ otadata, data, ota, , ${OTADATA_SIZE},`;
810839 var targetParts = tool . splitPath ( target ) ;
811840 var temporary = source . slice ( common , - 3 ) + ".js"
812841 this . line ( "$(MODULES_DIR)" , tool . slash , target . replaceAll ( "#" , tool . escapedHash ) , ": $(MODULES_DIR)" , temporary . replaceAll ( "#" , tool . escapedHash ) ) ;
842+
843+ if ( tool . lintCheck ) {
844+ this . echo ( tool , "eslint " , source . split ( tool . slash ) . at ( - 1 ) ) ;
845+ this . line ( "\tcd $(MODDABLE) && eslint " , source , " --config $(MODDABLE)/eslint.config.mjs" ) ;
846+ }
813847 this . echo ( tool , "xsc " , target ) ;
814848 var options = "" ;
815849 if ( result . commonjs )
@@ -1637,11 +1671,8 @@ trace(`face: ${name}\n`);
16371671}
16381672
16391673export class TSConfigFile extends FILE {
1640- constructor ( path ) {
1641- super ( path ) ;
1642- }
1643- generate ( tool ) {
1644- let json = {
1674+ generate ( tool , typescript = true , javascript = false ) {
1675+ const json = {
16451676 ...tool . typescript . tsconfig ,
16461677 compilerOptions : {
16471678 baseUrl : "./" ,
@@ -1650,36 +1681,72 @@ export class TSConfigFile extends FILE {
16501681 outDir : tool . modulesPath ,
16511682 paths : {
16521683 } ,
1653- lib : [ "es2024" ] ,
1684+ lib : [ "es2024" , "esnext.iterator" ] ,
16541685 sourceMap : true ,
1655- target : "es2024" ,
1656- ...tool . typescript . tsconfig ?. compilerOptions
1686+ target : "es2024"
16571687 } ,
16581688 files : [
16591689 ]
16601690 }
1661- var paths = json . compilerOptions . paths ;
1662- for ( var result of tool . dtsFiles ) {
1663- var specifier = result . target ;
1691+ const paths = json . compilerOptions . paths ;
1692+ for ( let result of tool . dtsFiles ) {
1693+ let specifier = result . target ;
16641694 if ( tool . windows )
16651695 specifier = specifier . replaceAll ( "\\" , "/" ) ;
16661696 specifier = tool . unresolvePrefix ( specifier ) ;
16671697 paths [ specifier ] = [ result . source . slice ( 0 , - 5 ) ] ;
16681698 }
1669- for ( var result of tool . tsFiles ) {
1670- var specifier = result . target . slice ( 0 , - 4 ) ;
1671- if ( tool . windows )
1672- specifier = specifier . replaceAll ( "\\" , "/" ) ;
1673- specifier = tool . unresolvePrefix ( specifier ) ;
1674- paths [ specifier ] = [ result . source . slice ( 0 , - 3 ) ] ;
1675- json . files . push ( result . source ) ;
1699+ if ( typescript ) {
1700+ for ( let result of tool . tsFiles ) {
1701+ let specifier = result . target . slice ( 0 , - 4 ) ;
1702+ if ( tool . windows )
1703+ specifier = specifier . replaceAll ( "\\" , "/" ) ;
1704+ specifier = tool . unresolvePrefix ( specifier ) ;
1705+ paths [ specifier ] = [ result . source . slice ( 0 , - 3 ) ] ;
1706+ json . files . push ( result . source ) ;
1707+ }
1708+ }
1709+ if ( javascript ) {
1710+ const sources = TSConfigFile . filter ( tool , tool . jsFiles ) ;
1711+ for ( let result of sources ) {
1712+ let specifier = result . target . slice ( 0 , - 4 ) ;
1713+ if ( tool . windows )
1714+ specifier = specifier . replaceAll ( "\\" , "/" ) ;
1715+ specifier = tool . unresolvePrefix ( specifier ) ;
1716+ json . files . push ( result . source ) ;
1717+ }
1718+
1719+ json . compilerOptions = {
1720+ ...json . compilerOptions ,
1721+ allowJs : true ,
1722+ checkJs : true ,
1723+ noEmit : true ,
1724+ strict : true ,
1725+ noImplicitAny : false ,
1726+ strictNullChecks : false
1727+ }
16761728 }
16771729 if ( "zephyr" === tool . platform ) {
1678- paths [ "embedded:provider/builtin" ] = [ tool . tmpPath + tool . slash + "mc.devicetree.d.ts" ] ;
1730+ paths [ "embedded:provider/builtin" ] = [ tool . tmpPath + tool . slash + "mc.devicetree" ] ;
1731+ paths [ "mc/devicetree" ] = [ tool . tmpPath + tool . slash + "mc.devicetree.js" ] ;
1732+ }
1733+
1734+ if ( tool . typescript . tsconfig ?. compilerOptions ) {
1735+ json . compilerOptions = {
1736+ ...json . compilerOptions ,
1737+ ...tool . typescript . tsconfig . compilerOptions
1738+ }
16791739 }
1740+
16801741 this . write ( JSON . stringify ( json , null , "\t" ) ) ;
16811742 this . close ( ) ;
16821743 }
1744+ static filter ( tool , sources ) {
1745+ const MODDABLE = tool . environment . MODDABLE ;
1746+ const modules = MODDABLE + tool . slash + "modules" + tool . slash ;
1747+ const build = MODDABLE + tool . slash + "build" + tool . slash ;
1748+ return sources . filter ( item => ! item . source . startsWith ( modules ) && ! item . source . startsWith ( build ) ) ;
1749+ }
16831750}
16841751
16851752export class PrerequisiteFile {
@@ -2314,6 +2381,12 @@ export class Tool extends TOOL {
23142381 this . xsbugLaunch = "log" ;
23152382 this . reportWarning ( null , 0 , "-l deprecated. use -dl instead." ) ;
23162383 break ;
2384+ case "-tc" :
2385+ this . typeCheck = true ;
2386+ break ;
2387+ case "-lc" :
2388+ this . lintCheck = true ;
2389+ break ;
23172390 default :
23182391 name = argv [ argi ] ;
23192392 let split = name . split ( "=" ) ;
0 commit comments