Reject internal tag on private decls, strip comments from private decls in dtsBundler (#58869)

This commit is contained in:
Jake Bailey 2024-06-18 16:14:29 -07:00 коммит произвёл GitHub
Родитель 4935e14901
Коммит 867476e57a
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
7 изменённых файлов: 55 добавлений и 125 удалений

Просмотреть файл

@ -39,6 +39,13 @@ console.log(`Bundling ${entrypoint} to ${output} and ${internalOutput}`);
const newLineKind = ts.NewLineKind.LineFeed;
const newLine = newLineKind === ts.NewLineKind.LineFeed ? "\n" : "\r\n";
/**
* @param {ts.Node} node
*/
function removeAllComments(node) {
/** @type {any} */ (ts).removeAllComments(node);
}
/**
* @param {ts.VariableDeclaration} node
* @returns {ts.VariableStatement}
@ -422,6 +429,15 @@ function emitAsNamespace(name, parent, moduleSymbol, needExportModifier) {
if (ts.isInternalDeclaration(node)) {
return undefined;
}
// TODO: remove after https://github.com/microsoft/TypeScript/pull/58187 is released
if (ts.canHaveModifiers(node)) {
for (const modifier of ts.getModifiers(node) ?? []) {
if (modifier.kind === ts.SyntaxKind.PrivateKeyword) {
removeAllComments(node);
break;
}
}
}
return node;
}, /*context*/ undefined);

Просмотреть файл

@ -12,6 +12,7 @@ module.exports = createRule({
multipleJSDocError: `Declaration has multiple JSDoc comments.`,
internalCommentOnParameterProperty: `@internal cannot appear on a JSDoc comment; use a declared property and an assignment in the constructor instead.`,
internalCommentOnUnexported: `@internal should not appear on an unexported declaration.`,
internalCommentOnPrivate: `@internal should not appear on a private declaration.`,
},
schema: [],
type: "problem",
@ -56,16 +57,9 @@ module.exports = createRule({
/** @type {(c: import("@typescript-eslint/utils").TSESTree.Comment, indexInComment: number) => import("@typescript-eslint/utils").TSESTree.SourceLocation} */
const getAtInternalLoc = (c, indexInComment) => {
const line = c.loc.start.line;
return {
start: {
line,
column: c.loc.start.column + indexInComment,
},
end: {
line,
column: c.loc.start.column + indexInComment + atInternal.length,
},
start: context.sourceCode.getLocFromIndex(c.range[0] + indexInComment),
end: context.sourceCode.getLocFromIndex(c.range[0] + indexInComment + atInternal.length),
};
};
@ -113,6 +107,10 @@ module.exports = createRule({
else if (!isExported(node)) {
context.report({ messageId: "internalCommentOnUnexported", node: c, loc: getAtInternalLoc(c, indexInComment) });
}
// eslint-disable-next-line local/no-in-operator
else if ("accessibility" in node && node.accessibility === "private") {
context.report({ messageId: "internalCommentOnPrivate", node: c, loc: getAtInternalLoc(c, indexInComment) });
}
else if (i !== last) {
context.report({ messageId: "internalCommentNotLastError", node: c, loc: getAtInternalLoc(c, indexInComment) });
}

Просмотреть файл

@ -1302,16 +1302,12 @@ export class ProjectService {
/** @internal */
readonly watchFactory: WatchFactory<WatchType, Project | NormalizedPath>;
/** @internal */
private readonly sharedExtendedConfigFileWatchers = new Map<Path, SharedExtendedConfigFileWatcher<NormalizedPath>>();
/** @internal */
private readonly extendedConfigCache = new Map<string, ExtendedConfigCacheEntry>();
/** @internal */
readonly packageJsonCache: PackageJsonCache;
/** @internal */
private packageJsonFilesMap: Map<Path, PackageJsonWatcher> | undefined;
/** @internal */
private incompleteCompletionsCache: IncompleteCompletionsCache | undefined;
/** @internal */
readonly session: Session<unknown> | undefined;
@ -1841,8 +1837,6 @@ export class ProjectService {
/**
* This is to watch whenever files are added or removed to the wildcard directories
*
* @internal
*/
private watchWildcardDirectory(directory: string, flags: WatchDirectoryFlags, configFileName: NormalizedPath, config: ParsedConfig) {
let watcher: FileWatcher | undefined = this.watchFactory.watchDirectory(
@ -1941,7 +1935,6 @@ export class ProjectService {
return result;
}
/** @internal */
private delayUpdateProjectsFromParsedConfigOnConfigFileChange(canonicalConfigFilePath: NormalizedPath, loadReason: string) {
const configFileExistenceInfo = this.configFileExistenceInfoCache.get(canonicalConfigFilePath);
if (!configFileExistenceInfo?.config) return false;
@ -1978,7 +1971,6 @@ export class ProjectService {
return scheduledAnyProjectUpdate;
}
/** @internal */
private onConfigFileChanged(configFileName: NormalizedPath, canonicalConfigFilePath: NormalizedPath, eventKind: FileWatcherEventKind) {
const configFileExistenceInfo = this.configFileExistenceInfoCache.get(canonicalConfigFilePath)!;
const project = this.getConfiguredProjectByCanonicalConfigFilePath(canonicalConfigFilePath);
@ -2280,7 +2272,6 @@ export class ProjectService {
return exists;
}
/** @internal */
private createConfigFileWatcherForParsedConfig(configFileName: NormalizedPath, canonicalConfigFilePath: NormalizedPath, forProject: ConfiguredProject) {
const configFileExistenceInfo = this.configFileExistenceInfoCache.get(canonicalConfigFilePath)!;
// When watching config file for parsed config, remove the noopFileWatcher that can be created for open files impacted by config file and watch for real
@ -2745,8 +2736,6 @@ export class ProjectService {
/**
* Read the config file of the project, and update the project root file names.
*
* @internal
*/
private loadConfiguredProject(project: ConfiguredProject, reason: string) {
tracing?.push(tracing.Phase.Session, "loadConfiguredProject", { configFilePath: project.canonicalConfigFilePath });
@ -3031,7 +3020,6 @@ export class ProjectService {
return project.updateGraph();
}
/** @internal */
private reloadFileNamesOfParsedConfig(configFileName: NormalizedPath, config: ParsedConfig) {
if (config.updateLevel === undefined) return config.parsedCommandLine!.fileNames;
Debug.assert(config.updateLevel === ProgramUpdateLevel.RootNamesAndUpdate);
@ -3085,7 +3073,6 @@ export class ProjectService {
updateWithTriggerFile(project, project.triggerFileForConfigFileDiag ?? project.getConfigFilePath(), /*isReload*/ true);
}
/** @internal */
private clearSemanticCache(project: Project) {
project.originalConfiguredProjects = undefined;
project.resolutionCache.clear();
@ -3800,7 +3787,6 @@ export class ProjectService {
return this.getWatchOptionsFromProjectWatchOptions(project.getWatchOptions(), project.getCurrentDirectory());
}
/** @internal */
private getWatchOptionsFromProjectWatchOptions(projectOptions: WatchOptions | undefined, basePath: string) {
const hostWatchOptions = !this.hostConfiguration.beforeSubstitution ? this.hostConfiguration.watchOptions :
handleWatchOptionsConfigDirTemplateSubstitution(
@ -5007,7 +4993,6 @@ export class ProjectService {
/**
* Performs the remaining steps of enabling a plugin after its module has been instantiated.
* @internal
*/
private endEnablePlugin(project: Project, { pluginConfigEntry, resolvedModule, errorLogs }: BeginEnablePluginResult) {
if (resolvedModule) {
@ -5162,7 +5147,6 @@ export class ProjectService {
});
}
/** @internal */
private watchPackageJsonFile(file: string, path: Path, project: Project | WildcardWatcher) {
Debug.assert(project !== undefined);
let result = (this.packageJsonFilesMap ??= new Map()).get(path);
@ -5204,7 +5188,6 @@ export class ProjectService {
(project.packageJsonWatches ??= new Set()).add(result);
}
/** @internal */
private onPackageJsonChange(result: PackageJsonWatcher) {
result.projects.forEach(project => (project as Project).onPackageJsonChange?.());
}

Просмотреть файл

@ -327,9 +327,7 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo
/** @internal */
lastCachedUnresolvedImportsList: SortedReadonlyArray<string> | undefined;
/** @internal */
private hasAddedorRemovedFiles = false;
/** @internal */
private hasAddedOrRemovedSymlinks = false;
/** @internal */
@ -390,7 +388,6 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo
/** @internal */
typingFiles: SortedReadonlyArray<string> = emptyArray;
/** @internal */
private typingWatchers: TypingWatchers | undefined;
/** @internal */
@ -492,13 +489,9 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo
/** @internal */
public readonly getCanonicalFileName: GetCanonicalFileName;
/** @internal */
private exportMapCache: ExportInfoMap | undefined;
/** @internal */
private changedFilesForExportMapCache: Set<Path> | undefined;
/** @internal */
private moduleSpecifierCache = createModuleSpecifierCache(this);
/** @internal */
private symlinks: SymlinkCache | undefined;
/** @internal */
autoImportProviderHost: AutoImportProviderProject | false | undefined;
@ -1418,13 +1411,11 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo
}
}
/** @internal */
private closeWatchingTypingLocations() {
if (this.typingWatchers) clearMap(this.typingWatchers, closeFileWatcher);
this.typingWatchers = undefined;
}
/** @internal */
private onTypingInstallerWatchInvoke() {
this.typingWatchers!.isInvoked = true;
this.projectService.updateTypingsForProject({ projectName: this.getProjectName(), kind: ActionInvalidate });
@ -1828,7 +1819,6 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo
return this.filesToStringWorker(writeProjectFileNames, /*writeFileExplaination*/ true, /*writeFileVersionAndText*/ false);
}
/** @internal */
private filesToStringWorker(writeProjectFileNames: boolean, writeFileExplaination: boolean, writeFileVersionAndText: boolean) {
if (this.isInitialLoadPending()) return "\tFiles (0) InitialLoadPending\n";
if (!this.program) return "\tFiles (0) NoProgram\n";
@ -2203,7 +2193,6 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo
}
}
/** @internal */
private isDefaultProjectForOpenFiles(): boolean {
return !!forEachEntry(
this.projectService.openFiles,
@ -2250,7 +2239,6 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo
}
}
/** @internal */
private getCompilerOptionsForNoDtsResolutionProject() {
return {
...this.getCompilerOptions(),
@ -2443,7 +2431,6 @@ export class AuxiliaryProject extends Project {
}
export class AutoImportProviderProject extends Project {
/** @internal */
private static readonly maxDependencies = 10;
/** @internal */
@ -2781,7 +2768,6 @@ export class ConfiguredProject extends Project {
/** @internal */
sendLoadingProjectFinish = false;
/** @internal */
private compilerHost?: CompilerHost;
/** @internal */
@ -2845,7 +2831,6 @@ export class ConfiguredProject extends Project {
this.releaseParsedConfig(asNormalizedPath(this.projectService.toCanonicalFileName(asNormalizedPath(normalizePath(fileName)))));
}
/** @internal */
private releaseParsedConfig(canonicalConfigFilePath: NormalizedPath) {
this.projectService.stopWatchingWildCards(canonicalConfigFilePath, this);
this.projectService.releaseParsedConfig(canonicalConfigFilePath, this);

Просмотреть файл

@ -382,8 +382,6 @@ export class ScriptInfo {
/**
* Set to real path if path is different from info.path
*
* @internal
*/
private realpath: Path | undefined;

Просмотреть файл

@ -113,7 +113,6 @@ export abstract class TypingsInstaller {
private readonly knownCachesSet = new Set<string>();
private readonly projectWatchers = new Map<string, Set<string>>();
private safeList: JsTyping.SafeList | undefined;
/** @internal */
private pendingRunRequests: PendingRequest[] = [];
private installRunCount = 1;

113
tests/baselines/reference/api/typescript.d.ts поставляемый
Просмотреть файл

@ -2523,6 +2523,7 @@ declare namespace ts {
private readonly knownCachesSet;
private readonly projectWatchers;
private safeList;
private pendingRunRequests;
private installRunCount;
private inFlightRequestCount;
abstract readonly typesRegistry: Map<string, MapLike<string>>;
@ -2715,6 +2716,7 @@ declare namespace ts {
readonly containingProjects: Project[];
private formatSettings;
private preferences;
private realpath;
constructor(host: ServerHost, fileName: NormalizedPath, scriptKind: ScriptKind, hasMixedContent: boolean, path: Path, initialVersion?: number);
isScriptOpen(): boolean;
open(newText: string | undefined): void;
@ -2802,29 +2804,27 @@ declare namespace ts {
private externalFiles;
private missingFilesMap;
private generatedFilesMap;
private hasAddedorRemovedFiles;
private hasAddedOrRemovedSymlinks;
protected languageService: LanguageService;
languageServiceEnabled: boolean;
readonly trace?: (s: string) => void;
readonly realpath?: (path: string) => string;
private builderState;
/**
* Set of files names that were updated since the last call to getChangesSinceVersion.
*/
private updatedFileNames;
/**
* Set of files that was returned from the last call to getChangesSinceVersion.
*/
private lastReportedFileNames;
/**
* Last version that was reported.
*/
private lastReportedVersion;
protected projectErrors: Diagnostic[] | undefined;
protected isInitialLoadPending: () => boolean;
private typingWatchers;
private readonly cancellationToken;
isNonTsProject(): boolean;
isJsOnlyProject(): boolean;
static resolveModule(moduleName: string, initialDir: string, host: ServerHost, log: (message: string) => void): {} | undefined;
private exportMapCache;
private changedFilesForExportMapCache;
private moduleSpecifierCache;
private symlinks;
readonly jsDocParsingMode: JSDocParsingMode | undefined;
isKnownTypesPackageName(name: string): boolean;
installPackage(options: InstallPackageOptions): Promise<ApplyCodeActionCommandResult>;
@ -2895,6 +2895,8 @@ declare namespace ts {
* @returns: true if set of files in the project stays the same and false - otherwise.
*/
updateGraph(): boolean;
private closeWatchingTypingLocations;
private onTypingInstallerWatchInvoke;
protected removeExistingTypings(include: string[]): string[];
private updateGraphWorker;
private detachScriptInfoFromProject;
@ -2906,6 +2908,7 @@ declare namespace ts {
getScriptInfoForNormalizedPath(fileName: NormalizedPath): ScriptInfo | undefined;
getScriptInfo(uncheckedFileName: string): ts.server.ScriptInfo | undefined;
filesToString(writeProjectFileNames: boolean): string;
private filesToStringWorker;
setCompilerOptions(compilerOptions: CompilerOptions): void;
setTypeAcquisition(newTypeAcquisition: TypeAcquisition | undefined): void;
getTypeAcquisition(): ts.TypeAcquisition;
@ -2914,6 +2917,8 @@ declare namespace ts {
protected enablePlugin(pluginConfigEntry: PluginImport, searchPaths: string[]): void;
/** Starts a new check for diagnostics. Call this if some file has updated that would cause diagnostics to be changed. */
refreshDiagnostics(): void;
private isDefaultProjectForOpenFiles;
private getCompilerOptionsForNoDtsResolutionProject;
}
/**
* If a file is opened and no tsconfig (or jsconfig) is found,
@ -2933,6 +2938,7 @@ declare namespace ts {
}
class AutoImportProviderProject extends Project {
private hostProject;
private static readonly maxDependencies;
private rootFileNames;
updateGraph(): boolean;
hasRoots(): boolean;
@ -2949,6 +2955,8 @@ declare namespace ts {
class ConfiguredProject extends Project {
readonly canonicalConfigFilePath: NormalizedPath;
private projectReferences;
private compilerHost?;
private releaseParsedConfig;
/**
* If the project has reload from disk pending, it reloads (and then updates graph as part of that) instead of just updating the graph
* @returns: true if set of files in the project stays the same and false - otherwise.
@ -3164,16 +3172,8 @@ declare namespace ts {
}
class ProjectService {
private readonly nodeModulesWatchers;
/**
* Contains all the deleted script info's version information so that
* it does not reset when creating script info again
* (and could have potentially collided with version where contents mismatch)
*/
private readonly filenameToScriptInfoVersion;
private readonly allJsFilesForOpenFileTelemetry;
/**
* maps external project file name to list of config files that were the part of this project
*/
private readonly externalProjectToConfiguredProjectMap;
/**
* external projects (configuration and list of root files is not controlled by tsserver)
@ -3191,13 +3191,8 @@ declare namespace ts {
* Open files: with value being project root path, and key being Path of the file that is open
*/
readonly openFiles: Map<Path, NormalizedPath | undefined>;
/** Config files looked up and cached config files for open script info */
private readonly configFileForOpenFiles;
/** Set of open script infos that are root of inferred project */
private rootOfInferredProjects;
/**
* Map of open files that are opened without complete path but have projectRoot as current directory
*/
private readonly openFilesWithNonRootedDiskPath;
private compilerOptionsForInferredProjects;
private compilerOptionsForInferredProjectsPerProjectRoot;
@ -3205,18 +3200,11 @@ declare namespace ts {
private watchOptionsForInferredProjectsPerProjectRoot;
private typeAcquisitionForInferredProjects;
private typeAcquisitionForInferredProjectsPerProjectRoot;
/**
* Project size for configured or external projects
*/
private readonly projectToSizeMap;
private readonly hostConfiguration;
private safelist;
private readonly legacySafelist;
private pendingProjectUpdates;
/**
* All the open script info that needs recalculation of the default project,
* this also caches config file info before config file change was detected to use it in case projects are not updated yet
*/
private pendingOpenFileProjectUpdates?;
readonly currentDirectory: NormalizedPath;
readonly toCanonicalFileName: (f: string) => string;
@ -3234,8 +3222,11 @@ declare namespace ts {
readonly allowLocalPluginLoads: boolean;
readonly typesMapLocation: string | undefined;
readonly serverMode: LanguageServiceMode;
/** Tracks projects that we have already sent telemetry for. */
private readonly seenProjects;
private readonly sharedExtendedConfigFileWatchers;
private readonly extendedConfigCache;
private packageJsonFilesMap;
private incompleteCompletionsCache;
private performanceEventHandler?;
private pendingPluginEnablements?;
private currentPluginEnablementPromise?;
@ -3249,20 +3240,9 @@ declare namespace ts {
setCompilerOptionsForInferredProjects(projectCompilerOptions: protocol.InferredProjectCompilerOptions, projectRootPath?: string): void;
findProject(projectName: string): Project | undefined;
getDefaultProjectForFile(fileName: NormalizedPath, ensureProject: boolean): Project | undefined;
/**
* If there is default project calculation pending for this file,
* then it completes that calculation so that correct default project is used for the project
*/
private tryGetDefaultProjectForEnsuringConfiguredProjectForFile;
private doEnsureDefaultProjectForFile;
getScriptInfoEnsuringProjectsUptoDate(uncheckedFileName: string): ScriptInfo | undefined;
/**
* Ensures the project structures are upto date
* This means,
* - we go through all the projects and update them if they are dirty
* - if updates reflect some change in structure or there was pending request to ensure projects for open files
* ensure that each open script info has project
*/
private ensureProjectStructuresUptoDate;
getFormatCodeOptions(file: NormalizedPath): FormatCodeSettings;
getPreferences(file: NormalizedPath): protocol.UserPreferences;
@ -3273,37 +3253,29 @@ declare namespace ts {
private delayUpdateSourceInfoProjects;
private delayUpdateProjectsOfScriptInfoPath;
private handleDeletedFile;
private watchWildcardDirectory;
private delayUpdateProjectsFromParsedConfigOnConfigFileChange;
private onConfigFileChanged;
private removeProject;
private assignOrphanScriptInfosToInferredProject;
/**
* Remove this file from the set of open, non-configured files.
* @param info The file that has been closed or newly configured
*/
private closeOpenFile;
private deleteScriptInfo;
private configFileExists;
/**
* This function tries to search for a tsconfig.json for the given file.
* This is different from the method the compiler uses because
* the compiler can assume it will always start searching in the
* current directory (the directory in which tsc was invoked).
* The server must start searching from the directory containing
* the newly opened file.
*/
private createConfigFileWatcherForParsedConfig;
private forEachConfigFileLocation;
/** Get cached configFileName for scriptInfo or ancestor of open script info */
private getConfigFileNameForFileFromCache;
/** Caches the configFilename for script info or ancestor of open script info */
private setConfigFileNameForFileInCache;
private printProjects;
private getConfiguredProjectByCanonicalConfigFilePath;
private findExternalProjectByProjectName;
/** Get a filename if the language service exceeds the maximum allowed program size; otherwise returns undefined. */
private getFilenameForExceededTotalSizeLimitForNonTsFiles;
private createExternalProject;
private addFilesToNonInferredProject;
private loadConfiguredProject;
private updateNonInferredProjectFiles;
private updateRootAndOptionsOfNonInferredProject;
private reloadFileNamesOfParsedConfig;
private clearSemanticCache;
private getOrCreateInferredProjectForProjectRootPathIfEnabled;
private getOrCreateSingleInferredProjectIfEnabled;
private getOrCreateSingleInferredWithoutProjectRoot;
@ -3329,23 +3301,14 @@ declare namespace ts {
private addSourceInfoToSourceMap;
private addMissingSourceMapFile;
setHostConfiguration(args: protocol.ConfigureRequestArguments): void;
private getWatchOptionsFromProjectWatchOptions;
closeLog(): void;
/**
* This function rebuilds the project for every file opened by the client
* This does not reload contents of open files from disk. But we could do that if needed
*/
reloadProjects(): void;
/**
* Remove the root of inferred project if script info is part of another project
*/
private removeRootOfInferredProjectIfNowPartOfOtherProject;
/**
* This function is to update the project structure for every inferred project.
* It is called on the premise that all the configured projects are
* up to date.
* This will go through open files and assign them to inferred project if open file is not part of any other project
* After that all the inferred project graphs are updated
*/
private ensureProjectForOpenFiles;
/**
* Open file whose contents is managed by the client
@ -3356,16 +3319,7 @@ declare namespace ts {
private findExternalProjectContainingOpenScriptInfo;
private getOrCreateOpenScriptInfo;
private assignProjectToOpenedScriptInfo;
/**
* Finds the default configured project for given info
* For any tsconfig found, it looks into that project, if not then all its references,
* The search happens for all tsconfigs till projectRootPath
*/
private tryFindDefaultConfiguredProjectForOpenScriptInfo;
/**
* Finds the default configured project, if found, it creates the solution projects (does not load them right away)
* with Find: finds the projects even if the project is deferredClosed
*/
private tryFindDefaultConfiguredProjectAndLoadAncestorsForOpenScriptInfo;
private ensureProjectChildren;
private cleanupConfiguredProjects;
@ -3381,7 +3335,6 @@ declare namespace ts {
private collectChanges;
closeExternalProject(uncheckedFileName: string): void;
openExternalProjects(projects: protocol.ExternalProject[]): void;
/** Makes a filename safe to insert in a RegExp */
private static readonly filenameEscapeRegexp;
private static escapeFilenameForRegex;
resetSafeList(): void;
@ -3389,9 +3342,12 @@ declare namespace ts {
private applySafeListWorker;
openExternalProject(proj: protocol.ExternalProject): void;
hasDeferredExtension(): boolean;
private endEnablePlugin;
private enableRequestedPluginsAsync;
private enableRequestedPluginsWorker;
configurePlugin(args: protocol.ConfigurePluginRequestArguments): void;
private watchPackageJsonFile;
private onPackageJsonChange;
}
function formatMessage<T extends protocol.Message>(msg: T, logger: Logger, byteLength: (s: string, encoding: BufferEncoding) => number, newLine: string): string;
interface ServerCancellationToken extends HostCancellationToken {
@ -3471,7 +3427,6 @@ declare namespace ts {
private suggestionCheck;
private regionSemanticCheck;
private sendDiagnosticsEvent;
/** It is the caller's responsibility to verify that `!this.suppressDiagnosticEvents`. */
private updateErrorCheck;
private cleanProjects;
private cleanup;
@ -3518,10 +3473,6 @@ declare namespace ts {
private toSpanGroups;
private getReferences;
private getFileReferences;
/**
* @param fileName is the name of the file to be opened
* @param fileContent is a version of the file content that is known to be more up to date than the one on disk
*/
private openClientFile;
private getPosition;
private getPositionInFile;