📄 useProgramFromProjectService¶
📊 Analysis Summary¶
| Metric | Count |
|---|---|
| 🔧 Functions | 9 |
| 📦 Imports | 13 |
| 📊 Variables & Constants | 2 |
📚 Table of Contents¶
🛠️ File Location:¶
📂 packages/typescript-estree/src/useProgramFromProjectService.ts
📦 Imports¶
| Name | Source |
|---|---|
ProjectServiceAndMetadata |
@typescript-eslint/project-service |
debug |
debug |
minimatch |
minimatch |
path |
node:path |
util |
node:util |
ASTAndDefiniteProgram |
./create-program/shared |
ASTAndNoProgram |
./create-program/shared |
ASTAndProgram |
./create-program/shared |
MutableParseSettings |
./parseSettings |
createProjectProgram |
./create-program/createProjectProgram |
createNoProgram |
./create-program/createSourceFile |
DEFAULT_EXTRA_FILE_EXTENSIONS |
./create-program/shared |
DEFAULT_PROJECT_FILES_ERROR_EXPLANATION |
./create-program/validateDefaultProjectForFilesGlob |
Variables & Constants¶
| Name | Type | Kind | Value | Exported |
|---|---|---|---|---|
RELOAD_THROTTLE_MS |
250 |
const | 250 |
✗ |
serviceFileExtensions |
WeakMap<ts.server.ProjectService, str... |
const | new WeakMap<ts.server.ProjectService, string[]>() |
✗ |
Functions¶
useProgramFromProjectService(…): ASTAndProgram | undefined¶
Parameters:
serviceAndSettingsProjectServiceAndMetadataparseSettingsReadonly<MutableParseSettings>hasFullTypeInformationbooleandefaultProjectMatchedFilesSet<string>
Returns: ASTAndProgram | undefined
Code
updateExtraFileExtensions(service: ts.server.ProjectService, extraFileExtensions: string[]): void¶
Parameters:
servicets.server.ProjectServiceextraFileExtensionsstring[]
Returns: void
Calls:
serviceFileExtensions.getutil.isDeepStrictEquallogservice.setHostConfigurationextraFileExtensions.mapserviceFileExtensions.set
Code
(
service: ts.server.ProjectService,
extraFileExtensions: string[],
): void => {
const currentServiceFileExtensions = serviceFileExtensions.get(service) ?? [];
if (
!util.isDeepStrictEqual(currentServiceFileExtensions, extraFileExtensions)
) {
log(
'Updating extra file extensions: before=%s: after=%s',
currentServiceFileExtensions,
extraFileExtensions,
);
service.setHostConfiguration({
extraFileExtensions: extraFileExtensions.map(extension => ({
extension,
isMixedContent: false,
scriptKind: ts.ScriptKind.Deferred,
})),
});
serviceFileExtensions.set(service, extraFileExtensions);
log('Extra file extensions updated: %o', extraFileExtensions);
}
}
openClientFileFromProjectService(…): ts.server.OpenConfiguredProjectResult¶
Parameters:
defaultProjectMatchedFilesSet<string>isDefaultProjectAllowedbooleanfilePathAbsolutestringparseSettingsReadonly<MutableParseSettings>serviceAndSettingsProjectServiceAndMetadata
Returns: ts.server.OpenConfiguredProjectResult
Calls:
openClientFileAndMaybeReloadlogpath.extnameDEFAULT_EXTRA_FILE_EXTENSIONS.hasextraFileExtensions.includespath.relative[ baseMessage,allowDefaultProject is set to ${JSON.stringify(allowDefaultProject)}, which does not match '${relativeFilePath}'., ].joinJSON.stringifydefaultProjectMatchedFiles.add[...defaultProjectMatchedFiles].slicefilesToPrint.map(file =>- ${file}).joinserviceAndSettings.service.openClientFileopenClientFileperformance.nowserviceAndSettings.service.reloadProjects
Internal Comments:
// No a configFileName indicates this file wasn't included in a TSConfig.
// That means it must get its type information from the default project.
/* scriptKind */
// If no project included the file and we're not in single-run mode,
// we might be running in an editor with outdated file info.
// We can try refreshing the project service - debounced for performance.
Code
function openClientFileFromProjectService(
defaultProjectMatchedFiles: Set<string>,
isDefaultProjectAllowed: boolean,
filePathAbsolute: string,
parseSettings: Readonly<MutableParseSettings>,
serviceAndSettings: ProjectServiceAndMetadata,
): ts.server.OpenConfiguredProjectResult {
const opened = openClientFileAndMaybeReload();
log('Result from attempting to open client file: %o', opened);
log(
'Default project allowed path: %s, based on config file: %s',
isDefaultProjectAllowed,
opened.configFileName,
);
if (opened.configFileName) {
if (isDefaultProjectAllowed) {
throw new Error(
`${parseSettings.filePath} was included by allowDefaultProject but also was found in the project service. Consider removing it from allowDefaultProject.`,
);
}
} else {
const wasNotFound = `${parseSettings.filePath} was not found by the project service`;
const fileExtension = path.extname(parseSettings.filePath);
const extraFileExtensions = parseSettings.extraFileExtensions;
if (
!DEFAULT_EXTRA_FILE_EXTENSIONS.has(fileExtension) &&
!extraFileExtensions.includes(fileExtension)
) {
const nonStandardExt = `${wasNotFound} because the extension for the file (\`${fileExtension}\`) is non-standard`;
if (extraFileExtensions.length > 0) {
throw new Error(
`${nonStandardExt}. It should be added to your existing \`parserOptions.extraFileExtensions\`.`,
);
} else {
throw new Error(
`${nonStandardExt}. You should add \`parserOptions.extraFileExtensions\` to your config.`,
);
}
}
if (!isDefaultProjectAllowed) {
const baseMessage = `${wasNotFound}. Consider either including it in the tsconfig.json or including it in allowDefaultProject.`;
const allowDefaultProject =
parseSettings.projectService?.allowDefaultProject;
if (!allowDefaultProject) {
throw new Error(baseMessage);
}
const relativeFilePath = path.relative(
parseSettings.tsconfigRootDir,
filePathAbsolute,
);
throw new Error(
[
baseMessage,
`allowDefaultProject is set to ${JSON.stringify(allowDefaultProject)}, which does not match '${relativeFilePath}'.`,
].join('\n'),
);
}
}
// No a configFileName indicates this file wasn't included in a TSConfig.
// That means it must get its type information from the default project.
if (!opened.configFileName) {
defaultProjectMatchedFiles.add(filePathAbsolute);
if (
defaultProjectMatchedFiles.size >
serviceAndSettings.maximumDefaultProjectFileMatchCount
) {
const filePrintLimit = 20;
const filesToPrint = [...defaultProjectMatchedFiles].slice(
0,
filePrintLimit,
);
const truncatedFileCount =
defaultProjectMatchedFiles.size - filesToPrint.length;
throw new Error(
`Too many files (>${serviceAndSettings.maximumDefaultProjectFileMatchCount}) have matched the default project.${DEFAULT_PROJECT_FILES_ERROR_EXPLANATION}
Matching files:
${filesToPrint.map(file => `- ${file}`).join('\n')}
${truncatedFileCount ? `...and ${truncatedFileCount} more files\n` : ''}
If you absolutely need more files included, set parserOptions.projectService.maximumDefaultProjectFileMatchCount_THIS_WILL_SLOW_DOWN_LINTING to a larger value.
`,
);
}
}
return opened;
function openClientFile(): ts.server.OpenConfiguredProjectResult {
return serviceAndSettings.service.openClientFile(
filePathAbsolute,
parseSettings.codeFullText,
/* scriptKind */ undefined,
parseSettings.tsconfigRootDir,
);
}
function openClientFileAndMaybeReload(): ts.server.OpenConfiguredProjectResult {
log('Opening project service client file at path: %s', filePathAbsolute);
let opened = openClientFile();
// If no project included the file and we're not in single-run mode,
// we might be running in an editor with outdated file info.
// We can try refreshing the project service - debounced for performance.
if (
!opened.configFileErrors &&
!opened.configFileName &&
!parseSettings.singleRun &&
!isDefaultProjectAllowed &&
performance.now() - serviceAndSettings.lastReloadTimestamp >
RELOAD_THROTTLE_MS
) {
log('No config file found; reloading project service and retrying.');
serviceAndSettings.service.reloadProjects();
opened = openClientFile();
serviceAndSettings.lastReloadTimestamp = performance.now();
}
return opened;
}
}
createNoProgramWithProjectService(filePathAbsolute: string, parseSettings: Readonly<MutableParseSettings>, service: ts.server.ProjectService): ASTAndNoProgram¶
Parameters:
filePathAbsolutestringparseSettingsReadonly<MutableParseSettings>servicets.server.ProjectService
Returns: ASTAndNoProgram
Calls:
logservice.getScriptInfoservice.openClientFilecreateNoProgram (from ./create-program/createSourceFile)
Internal Comments:
// If the project service knows about this file, this informs if of changes.
// Doing so ensures that:
// - if the file is not part of a project, we don't waste time creating a program (fast non-type-aware linting)
// - otherwise, we refresh the file in the project service (moderately fast, since the project is already loaded)
/* scriptKind */
Code
function createNoProgramWithProjectService(
filePathAbsolute: string,
parseSettings: Readonly<MutableParseSettings>,
service: ts.server.ProjectService,
): ASTAndNoProgram {
log('No project service information available. Creating no program.');
// If the project service knows about this file, this informs if of changes.
// Doing so ensures that:
// - if the file is not part of a project, we don't waste time creating a program (fast non-type-aware linting)
// - otherwise, we refresh the file in the project service (moderately fast, since the project is already loaded)
if (service.getScriptInfo(filePathAbsolute)) {
log('Script info available. Opening client file in project service.');
service.openClientFile(
filePathAbsolute,
parseSettings.codeFullText,
/* scriptKind */ undefined,
parseSettings.tsconfigRootDir,
);
}
return createNoProgram(parseSettings);
}
retrieveASTAndProgramFor(filePathAbsolute: string, parseSettings: Readonly<MutableParseSettings>, serviceAndSettings: ProjectServiceAndMetadata): ASTAndDefiniteProgram | undefined¶
Parameters:
filePathAbsolutestringparseSettingsReadonly<MutableParseSettings>serviceAndSettingsProjectServiceAndMetadata
Returns: ASTAndDefiniteProgram | undefined
Calls:
logserviceAndSettings.service.getScriptInfoserviceAndSettings.service .getDefaultProjectForFile(scriptInfo!.fileName, true)! .getLanguageService(/*ensureSynchronized*/ true) .getProgramcreateProjectProgram (from ./create-program/createProjectProgram)
Internal Comments:
/* eslint-disable @typescript-eslint/no-non-null-assertion */ (x2)
/* eslint-enable @typescript-eslint/no-non-null-assertion */
Code
function retrieveASTAndProgramFor(
filePathAbsolute: string,
parseSettings: Readonly<MutableParseSettings>,
serviceAndSettings: ProjectServiceAndMetadata,
): ASTAndDefiniteProgram | undefined {
log('Retrieving script info and then program for: %s', filePathAbsolute);
const scriptInfo = serviceAndSettings.service.getScriptInfo(filePathAbsolute);
/* eslint-disable @typescript-eslint/no-non-null-assertion */
const program = serviceAndSettings.service
.getDefaultProjectForFile(scriptInfo!.fileName, true)!
.getLanguageService(/*ensureSynchronized*/ true)
.getProgram();
/* eslint-enable @typescript-eslint/no-non-null-assertion */
if (!program) {
log('Could not find project service program for: %s', filePathAbsolute);
return undefined;
}
log('Found project service program for: %s', filePathAbsolute);
return createProjectProgram(parseSettings, [program]);
}
absolutify(filePath: string, serviceAndSettings: ProjectServiceAndMetadata): string¶
Parameters:
filePathstringserviceAndSettingsProjectServiceAndMetadata
Returns: string
Calls:
path.isAbsolutepath.joinserviceAndSettings.service.host.getCurrentDirectory
Code
filePathMatchedBy(filePath: string, allowDefaultProject: string[] | undefined): boolean¶
Parameters:
filePathstringallowDefaultProjectstring[] | undefined
Returns: boolean
Calls:
allowDefaultProject?.someminimatch (from minimatch)
Code
Internal helpers¶
Declared inside another function in this file.
openClientFile(): ts.server.OpenConfiguredProjectResult¶
Returns: ts.server.OpenConfiguredProjectResult
Calls:
serviceAndSettings.service.openClientFile
Internal Comments:
Code
openClientFileAndMaybeReload(): ts.server.OpenConfiguredProjectResult¶
Returns: ts.server.OpenConfiguredProjectResult
Calls:
logopenClientFileperformance.nowserviceAndSettings.service.reloadProjects
Internal Comments:
// If no project included the file and we're not in single-run mode,
// we might be running in an editor with outdated file info.
// We can try refreshing the project service - debounced for performance.
Code
function openClientFileAndMaybeReload(): ts.server.OpenConfiguredProjectResult {
log('Opening project service client file at path: %s', filePathAbsolute);
let opened = openClientFile();
// If no project included the file and we're not in single-run mode,
// we might be running in an editor with outdated file info.
// We can try refreshing the project service - debounced for performance.
if (
!opened.configFileErrors &&
!opened.configFileName &&
!parseSettings.singleRun &&
!isDefaultProjectAllowed &&
performance.now() - serviceAndSettings.lastReloadTimestamp >
RELOAD_THROTTLE_MS
) {
log('No config file found; reloading project service and retrying.');
serviceAndSettings.service.reloadProjects();
opened = openClientFile();
serviceAndSettings.lastReloadTimestamp = performance.now();
}
return opened;
}
Generated by Syntax Scribe