2024-09-11 02:37:36 +00:00
"use strict" ;
/ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Copyright ( c ) Microsoft Corporation . All rights reserved .
* Licensed under the MIT License . See License . txt in the project root for license information .
* -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- * /
2025-03-01 02:01:53 +00:00
var _ _importDefault = ( this && this . _ _importDefault ) || function ( mod ) {
return ( mod && mod . _ _esModule ) ? mod : { "default" : mod } ;
} ;
2024-09-11 02:37:36 +00:00
Object . defineProperty ( exports , "__esModule" , { value : true } ) ;
2025-03-01 02:01:53 +00:00
const typescript _1 = _ _importDefault ( require ( "typescript" ) ) ;
2024-09-11 02:37:36 +00:00
const fs _1 = require ( "fs" ) ;
const path _1 = require ( "path" ) ;
const minimatch _1 = require ( "minimatch" ) ;
//
// #############################################################################################
//
// A custom typescript checker for the specific task of detecting the use of certain types in a
// layer that does not allow such use. For example:
// - using DOM globals in common/node/electron-main layer (e.g. HTMLElement)
// - using node.js globals in common/browser layer (e.g. process)
//
// Make changes to below RULES to lift certain files from these checks only if absolutely needed
//
// #############################################################################################
//
// Types we assume are present in all implementations of JS VMs (node.js, browsers)
// Feel free to add more core types as you see needed if present in node.js and browsers
const CORE _TYPES = [
'setTimeout' ,
'clearTimeout' ,
'setInterval' ,
'clearInterval' ,
'console' ,
'Console' ,
'Error' ,
'ErrorConstructor' ,
'String' ,
'TextDecoder' ,
'TextEncoder' ,
'self' ,
'queueMicrotask' ,
'Array' ,
'Uint8Array' ,
'Uint16Array' ,
'Uint32Array' ,
'Int8Array' ,
'Int16Array' ,
'Int32Array' ,
'Float32Array' ,
'Float64Array' ,
'Uint8ClampedArray' ,
'BigUint64Array' ,
'BigInt64Array' ,
'btoa' ,
'atob' ,
'AbortController' ,
'AbortSignal' ,
'MessageChannel' ,
'MessagePort' ,
'URL' ,
'URLSearchParams' ,
'ReadonlyArray' ,
'Event' ,
'EventTarget' ,
'BroadcastChannel' ,
'performance' ,
'Blob' ,
'crypto' ,
'File' ,
'fetch' ,
'RequestInit' ,
'Headers' ,
2025-03-01 02:01:53 +00:00
'Request' ,
2024-09-11 02:37:36 +00:00
'Response' ,
2025-03-01 02:01:53 +00:00
'Body' ,
'__type' ,
2024-09-11 02:37:36 +00:00
'__global' ,
2025-03-01 02:01:53 +00:00
'Performance' ,
2024-09-11 02:37:36 +00:00
'PerformanceMark' ,
'PerformanceObserver' ,
2025-03-01 02:01:53 +00:00
'ImportMeta' ,
2025-04-29 07:07:20 +00:00
'structuredClone' ,
2025-03-01 02:01:53 +00:00
// webcrypto has been available since Node.js 19, but still live in dom.d.ts
'Crypto' ,
2025-04-29 07:07:20 +00:00
'SubtleCrypto' ,
'JsonWebKey' ,
'MessageEvent' ,
2024-09-11 02:37:36 +00:00
] ;
// Types that are defined in a common layer but are known to be only
// available in native environments should not be allowed in browser
const NATIVE _TYPES = [
'NativeParsedArgs' ,
'INativeEnvironmentService' ,
'AbstractNativeEnvironmentService' ,
'INativeWindowConfiguration' ,
'ICommonNativeHostService' ,
'INativeHostService' ,
'IMainProcessService'
] ;
const RULES = [
// Tests: skip
{
target : '**/vs/**/test/**' ,
skip : true // -> skip all test files
} ,
// Common: vs/base/common/platform.ts
{
target : '**/vs/base/common/platform.ts' ,
allowedTypes : [
... CORE _TYPES ,
// Safe access to postMessage() and friends
'MessageEvent' ,
] ,
disallowedTypes : NATIVE _TYPES ,
disallowedDefinitions : [
'lib.dom.d.ts' , // no DOM
'@types/node' // no node.js
]
} ,
// Common: vs/base/common/async.ts
{
target : '**/vs/base/common/async.ts' ,
allowedTypes : [
... CORE _TYPES ,
// Safe access to requestIdleCallback & cancelIdleCallback
'requestIdleCallback' ,
'cancelIdleCallback'
] ,
disallowedTypes : NATIVE _TYPES ,
disallowedDefinitions : [
'lib.dom.d.ts' , // no DOM
'@types/node' // no node.js
]
} ,
2025-03-01 02:01:53 +00:00
// Common: vs/base/common/performance.ts
{
target : '**/vs/base/common/performance.ts' ,
allowedTypes : [
... CORE _TYPES ,
// Safe access to Performance
'Performance' ,
'PerformanceEntry' ,
'PerformanceTiming'
] ,
disallowedTypes : NATIVE _TYPES ,
disallowedDefinitions : [
'lib.dom.d.ts' , // no DOM
'@types/node' // no node.js
]
} ,
2024-09-11 02:37:36 +00:00
// Common: vs/platform/environment/common/*
{
target : '**/vs/platform/environment/common/*.ts' ,
allowedTypes : CORE _TYPES ,
disallowedTypes : [ /* Ignore native types that are defined from here */ ] ,
disallowedDefinitions : [
'lib.dom.d.ts' , // no DOM
'@types/node' // no node.js
]
} ,
// Common: vs/platform/window/common/window.ts
{
target : '**/vs/platform/window/common/window.ts' ,
allowedTypes : CORE _TYPES ,
disallowedTypes : [ /* Ignore native types that are defined from here */ ] ,
disallowedDefinitions : [
'lib.dom.d.ts' , // no DOM
'@types/node' // no node.js
]
} ,
// Common: vs/platform/native/common/native.ts
{
target : '**/vs/platform/native/common/native.ts' ,
allowedTypes : CORE _TYPES ,
disallowedTypes : [ /* Ignore native types that are defined from here */ ] ,
disallowedDefinitions : [
'lib.dom.d.ts' , // no DOM
'@types/node' // no node.js
]
} ,
// Common: vs/platform/native/common/nativeHostService.ts
{
target : '**/vs/platform/native/common/nativeHostService.ts' ,
allowedTypes : CORE _TYPES ,
disallowedTypes : [ /* Ignore native types that are defined from here */ ] ,
disallowedDefinitions : [
'lib.dom.d.ts' , // no DOM
'@types/node' // no node.js
]
} ,
// Common: vs/workbench/api/common/extHostExtensionService.ts
{
target : '**/vs/workbench/api/common/extHostExtensionService.ts' ,
allowedTypes : [
... CORE _TYPES ,
// Safe access to global
'global'
] ,
disallowedTypes : NATIVE _TYPES ,
disallowedDefinitions : [
'lib.dom.d.ts' , // no DOM
'@types/node' // no node.js
]
} ,
2025-03-01 02:01:53 +00:00
// Common: vs/base/parts/sandbox/electron-sandbox/preload.ts
2024-09-11 02:37:36 +00:00
{
2025-03-01 02:01:53 +00:00
target : '**/vs/base/parts/sandbox/electron-sandbox/preload.ts' ,
2024-09-11 02:37:36 +00:00
allowedTypes : [
... CORE _TYPES ,
// Safe access to a very small subset of node.js
'process' ,
'NodeJS'
] ,
disallowedTypes : NATIVE _TYPES ,
disallowedDefinitions : [
'@types/node' // no node.js
]
} ,
// Common
{
target : '**/vs/**/common/**' ,
allowedTypes : CORE _TYPES ,
disallowedTypes : NATIVE _TYPES ,
disallowedDefinitions : [
'lib.dom.d.ts' , // no DOM
'@types/node' // no node.js
]
} ,
// Browser
{
target : '**/vs/**/browser/**' ,
allowedTypes : CORE _TYPES ,
disallowedTypes : NATIVE _TYPES ,
allowedDefinitions : [
'@types/node/stream/consumers.d.ts' // node.js started to duplicate types from lib.dom.d.ts so we have to account for that
] ,
disallowedDefinitions : [
'@types/node' // no node.js
]
} ,
// Browser (editor contrib)
{
target : '**/src/vs/editor/contrib/**' ,
allowedTypes : CORE _TYPES ,
disallowedTypes : NATIVE _TYPES ,
disallowedDefinitions : [
'@types/node' // no node.js
]
} ,
// node.js
{
target : '**/vs/**/node/**' ,
allowedTypes : CORE _TYPES ,
disallowedDefinitions : [
'lib.dom.d.ts' // no DOM
]
} ,
// Electron (sandbox)
{
target : '**/vs/**/electron-sandbox/**' ,
allowedTypes : CORE _TYPES ,
disallowedDefinitions : [
'@types/node' // no node.js
]
} ,
2024-09-24 04:46:08 +00:00
// Electron (utility)
{
target : '**/vs/**/electron-utility/**' ,
allowedTypes : [
... CORE _TYPES ,
// --> types from electron.d.ts that duplicate from lib.dom.d.ts
'Event' ,
'Request'
] ,
disallowedTypes : [
'ipcMain' // not allowed, use validatedIpcMain instead
] ,
disallowedDefinitions : [
'lib.dom.d.ts' // no DOM
]
} ,
2024-09-11 02:37:36 +00:00
// Electron (main)
{
target : '**/vs/**/electron-main/**' ,
allowedTypes : [
... CORE _TYPES ,
// --> types from electron.d.ts that duplicate from lib.dom.d.ts
'Event' ,
'Request'
] ,
disallowedTypes : [
'ipcMain' // not allowed, use validatedIpcMain instead
] ,
disallowedDefinitions : [
'lib.dom.d.ts' // no DOM
]
}
] ;
const TS _CONFIG _PATH = ( 0 , path _1 . join ) ( _ _dirname , '../../' , 'src' , 'tsconfig.json' ) ;
let hasErrors = false ;
function checkFile ( program , sourceFile , rule ) {
checkNode ( sourceFile ) ;
function checkNode ( node ) {
2025-03-01 02:01:53 +00:00
if ( node . kind !== typescript _1 . default . SyntaxKind . Identifier ) {
return typescript _1 . default . forEachChild ( node , checkNode ) ; // recurse down
2024-09-11 02:37:36 +00:00
}
const checker = program . getTypeChecker ( ) ;
const symbol = checker . getSymbolAtLocation ( node ) ;
if ( ! symbol ) {
return ;
}
let _parentSymbol = symbol ;
while ( _parentSymbol . parent ) {
_parentSymbol = _parentSymbol . parent ;
}
const parentSymbol = _parentSymbol ;
const text = parentSymbol . getName ( ) ;
if ( rule . allowedTypes ? . some ( allowed => allowed === text ) ) {
return ; // override
}
if ( rule . disallowedTypes ? . some ( disallowed => disallowed === text ) ) {
const { line , character } = sourceFile . getLineAndCharacterOfPosition ( node . getStart ( ) ) ;
console . log ( ` [build/lib/layersChecker.ts]: Reference to type ' ${ text } ' violates layer ' ${ rule . target } ' ( ${ sourceFile . fileName } ( ${ line + 1 } , ${ character + 1 } ). Learn more about our source code organization at https://github.com/microsoft/vscode/wiki/Source-Code-Organization. ` ) ;
hasErrors = true ;
return ;
}
const declarations = symbol . declarations ;
if ( Array . isArray ( declarations ) ) {
DeclarationLoop : for ( const declaration of declarations ) {
if ( declaration ) {
const parent = declaration . parent ;
if ( parent ) {
const parentSourceFile = parent . getSourceFile ( ) ;
if ( parentSourceFile ) {
const definitionFileName = parentSourceFile . fileName ;
if ( rule . allowedDefinitions ) {
for ( const allowedDefinition of rule . allowedDefinitions ) {
if ( definitionFileName . indexOf ( allowedDefinition ) >= 0 ) {
continue DeclarationLoop ;
}
}
}
if ( rule . disallowedDefinitions ) {
for ( const disallowedDefinition of rule . disallowedDefinitions ) {
if ( definitionFileName . indexOf ( disallowedDefinition ) >= 0 ) {
const { line , character } = sourceFile . getLineAndCharacterOfPosition ( node . getStart ( ) ) ;
console . log ( ` [build/lib/layersChecker.ts]: Reference to symbol ' ${ text } ' from ' ${ disallowedDefinition } ' violates layer ' ${ rule . target } ' ( ${ sourceFile . fileName } ( ${ line + 1 } , ${ character + 1 } ) Learn more about our source code organization at https://github.com/microsoft/vscode/wiki/Source-Code-Organization. ` ) ;
hasErrors = true ;
return ;
}
}
}
}
}
}
}
}
}
}
function createProgram ( tsconfigPath ) {
2025-03-01 02:01:53 +00:00
const tsConfig = typescript _1 . default . readConfigFile ( tsconfigPath , typescript _1 . default . sys . readFile ) ;
const configHostParser = { fileExists : fs _1 . existsSync , readDirectory : typescript _1 . default . sys . readDirectory , readFile : file => ( 0 , fs _1 . readFileSync ) ( file , 'utf8' ) , useCaseSensitiveFileNames : process . platform === 'linux' } ;
const tsConfigParsed = typescript _1 . default . parseJsonConfigFileContent ( tsConfig . config , configHostParser , ( 0 , path _1 . resolve ) ( ( 0 , path _1 . dirname ) ( tsconfigPath ) ) , { noEmit : true } ) ;
const compilerHost = typescript _1 . default . createCompilerHost ( tsConfigParsed . options , true ) ;
return typescript _1 . default . createProgram ( tsConfigParsed . fileNames , tsConfigParsed . options , compilerHost ) ;
2024-09-11 02:37:36 +00:00
}
//
// Create program and start checking
//
const program = createProgram ( TS _CONFIG _PATH ) ;
for ( const sourceFile of program . getSourceFiles ( ) ) {
for ( const rule of RULES ) {
if ( ( 0 , minimatch _1 . match ) ( [ sourceFile . fileName ] , rule . target ) . length > 0 ) {
if ( ! rule . skip ) {
checkFile ( program , sourceFile , rule ) ;
}
break ;
}
}
}
if ( hasErrors ) {
process . exit ( 1 ) ;
}
//# sourceMappingURL=layersChecker.js.map