Intro
[TypeScript] About tsconfig 1[TypeScript] Read source code of tsc 1(Parse options)
The result of parsing, the instance of BuildOptions is created.
compiler/tsbuildPublic.ts
export interface BuildOptions {
dry?: boolean;
force?: boolean;
verbose?: boolean;
/*@internal*/ clean?: boolean;
/*@internal*/ watch?: boolean;
/*@internal*/ help?: boolean;
/*@internal*/ preserveWatchOutput?: boolean;
/*@internal*/ listEmittedFiles?: boolean;
/*@internal*/ listFiles?: boolean;
/*@internal*/ pretty?: boolean;
incremental?: boolean;
assumeChangesOnlyAffectDirectDependencies?: boolean;
traceResolution?: boolean;
/* @internal */ diagnostics?: boolean;
/* @internal */ extendedDiagnostics?: boolean;
/* @internal */ locale?: string;
/* @internal */ generateCpuProfile?: string;
[option: string]: CompilerOptionsValue | undefined;
}
It includes "incremental".So this time, I read about "incremental".
Who uses "incremental"?
The "incremental" is eventual used in tsbuildPublic.ts's needsBuild.compiler/tsbuildPublic.ts
function needsBuild({ options }: SolutionBuilderState, status: UpToDateStatus, config: ParsedCommandLine) {
if (status.type !== UpToDateStatusType.OutOfDateWithPrepend || options.force) return true;
return config.fileNames.length === 0 ||
!!getConfigFileParsingDiagnostics(config).length ||
!isIncrementalCompilation(config.options);
}
compiler/utilities.ts
...
export function isIncrementalCompilation(options: CompilerOptions) {
return !!(options.incremental || options.composite);
}
...
!!
I have never seen "!!". What's this?The result is "if options.incremental or options.composite (or both) is true, it returns true".
In this context, "!!" does nothing.
But if the values aren't boolean type?
const incremental = false;
const composite1 = undefined;
const composite2 = 'hello';
const composite3 = 2
const composite4 = [2];
console.log('RESULT: undefined');
console.log((incremental || composite1));
console.log('RESULT: string');
console.log((incremental || composite2));
console.log('RESULT: number');
console.log((incremental || composite3));
console.log('RESULT: array');
console.log((incremental || composite4));
The results are ...[LOG]: RESULT: undefined [LOG]: undefined [LOG]: RESULT: string [LOG]: hello [LOG]: RESULT: number [LOG]: 2 [LOG]: RESULT: array [LOG]: [ 2 ]The types are changed from boolean.
For avoiding this, I can use "!!".
const incremental = false;
const composite1 = undefined;
const composite2 = 'hello';
const composite3 = 2
const composite4 = [2];
console.log('RESULT: undefined');
console.log(!!(incremental || composite1));
console.log('RESULT: string');
console.log(!!(incremental || composite2));
console.log('RESULT: number');
console.log(!!(incremental || composite3));
console.log('RESULT: array');
console.log(!!(incremental || composite4));
The results are ...[LOG]: RESULT: undefined [LOG]: false [LOG]: RESULT: string [LOG]: true [LOG]: RESULT: number [LOG]: true [LOG]: RESULT: array [LOG]: trueWhat's the double exclamation mark for in JavaScript? | Brian F Love
UpToDateStatus
In needsBuild function, I think "status.type" makes tsc build after the TypeScript file updated.Because the remaining conditions are "force" option or about existence of config file.
So I'm following the UpToDateStatus.
It's set by getUpToDateStatus in getNextInvalidatedProject of tsbuildPublic.ts.
compiler/tsbuildPublic.ts
...
function getNextInvalidatedProject<T extends BuilderProgram>(
state: SolutionBuilderState<T>,
buildOrder: AnyBuildOrder,
reportQueue: boolean
): InvalidatedProject<T> | undefined {
...
const status = getUpToDateStatus(state, config, projectPath);
verboseReportProjectStatus(state, project, status);
...
return createBuildOrUpdateInvalidedProject(
needsBuild(state, status, config) ?
InvalidatedProjectKind.Build :
InvalidatedProjectKind.UpdateBundle,
state,
project,
projectPath,
projectIndex,
config,
buildOrder,
);
}
return undefined;
}
...
function getUpToDateStatus(state: SolutionBuilderState, project: ParsedCommandLine | undefined, resolvedPath: ResolvedConfigFilePath): UpToDateStatus {
if (project === undefined) {
return { type: UpToDateStatusType.Unbuildable, reason: "File deleted mid-build" };
}
const prior = state.projectStatus.get(resolvedPath);
if (prior !== undefined) {
return prior;
}
const actual = getUpToDateStatusWorker(state, project, resolvedPath);
state.projectStatus.set(resolvedPath, actual);
return actual;
}
...
Because state.projectStatus is undefined this time, so I think state.projectStatus will be set by getUpToDateStatusWorker.
compiler/tsbuildPublic.ts
...
function getUpToDateStatusWorker(state: SolutionBuilderState, project: ParsedCommandLine, resolvedPath: ResolvedConfigFilePath): UpToDateStatus {
...
let pseudoUpToDate = false;
let usesPrepend = false;
let upstreamChangedProject: string | undefined;
if (project.projectReferences) {
// tsc executes here only when I add "watch" option
}
...
// if tsconfig.json's modified time is newer than tsconfig.buildinfo, "isOutOfDateWithInputs" becomes true
if (isOutOfDateWithInputs) {
return {
type: UpToDateStatusType.OutOfDateWithSelf,
outOfDateOutputFileName: oldestOutputFileName,
newerInputFileName: newestInputFileName
};
}
else {
// if there are multiple output files,
// and if tsconfig.json's modified time is newer than the oldest output file, the type is set as "UpToDateStatusType.OutOfDateWithSelf".
// Check tsconfig time
const configStatus = checkConfigFileUpToDateStatus(state, project.options.configFilePath!, oldestOutputFileTime, oldestOutputFileName);
if (configStatus) return configStatus;
// Check extended config time
const extendedConfigStatus = forEach(project.options.configFile!.extendedSourceFiles || emptyArray, configFile => checkConfigFileUpToDateStatus(state, configFile, oldestOutputFileTime, oldestOutputFileName));
if (extendedConfigStatus) return extendedConfigStatus;
}
if (!state.buildInfoChecked.has(resolvedPath)) {
state.buildInfoChecked.set(resolvedPath, true);
const buildInfoPath = getTsBuildInfoEmitOutputFilePath(project.options);
if (buildInfoPath) {
const value = state.readFileWithCache(buildInfoPath);
const buildInfo = value && getBuildInfo(value);
if (buildInfo && (buildInfo.bundle || buildInfo.program) && buildInfo.version !== version) {
return {
type: UpToDateStatusType.TsVersionOutputOfDate,
version: buildInfo.version
};
}
}
}
...
// Up to date
return {
type: pseudoUpToDate ? UpToDateStatusType.UpToDateWithUpstreamTypes : UpToDateStatusType.UpToDate,
newestDeclarationFileContentChangedTime,
newestInputFileTime,
newestOutputFileTime,
newestInputFileName,
newestOutputFileName,
oldestOutputFileName
};
}
According to getUpToDateStatusWorker, the condition of setting state.projectStatus as "UpToDateStatusType.OutOfDateWithPrepend" is only when I add "watch" option.
Thus, the first arguments of createBuildOrUpdateInvalidedProject is "InvalidatedProjectKind.Build".
コメント
コメントを投稿