Skip to content

Commit 0bacf8f

Browse files
author
Yui
committed
Merge pull request #959 from Microsoft/refactorRefFilesPath
Refactor ref files path
2 parents d634ab8 + dc3c5c5 commit 0bacf8f

File tree

11 files changed

+413
-304
lines changed

11 files changed

+413
-304
lines changed

Jakefile

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,9 @@ var harnessSources = [
8282
].map(function (f) {
8383
return path.join(harnessDirectory, f);
8484
}).concat([
85-
"services/colorization.ts",
86-
"services/documentRegistry.ts"
85+
"services/colorization.ts",
86+
"services/documentRegistry.ts",
87+
"services/preProcessFile.ts"
8788
].map(function (f) {
8889
return path.join(unittestsDirectory, f);
8990
}));

src/compiler/parser.ts

Lines changed: 50 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -745,6 +745,47 @@ module ts {
745745
nodeIsNestedInLabel(label: Identifier, requireIterationStatement: boolean, stopAtFunctionBoundary: boolean): ControlBlockContext;
746746
}
747747

748+
interface ReferencePathMatchResult {
749+
fileReference?: FileReference
750+
diagnostic?: DiagnosticMessage
751+
isNoDefaultLib?: boolean
752+
}
753+
754+
export function getFileReferenceFromReferencePath(comment: string, commentRange: CommentRange): ReferencePathMatchResult {
755+
var simpleReferenceRegEx = /^\/\/\/\s*<reference\s+/gim;
756+
var isNoDefaultLibRegEx = /^(\/\/\/\s*<reference\s+no-default-lib\s*=\s*)('|")(.+?)\2\s*\/>/gim;
757+
if (simpleReferenceRegEx.exec(comment)) {
758+
if (isNoDefaultLibRegEx.exec(comment)) {
759+
return {
760+
isNoDefaultLib: true
761+
}
762+
}
763+
else {
764+
var matchResult = fullTripleSlashReferencePathRegEx.exec(comment);
765+
if (matchResult) {
766+
var start = commentRange.pos;
767+
var end = commentRange.end;
768+
var fileRef = {
769+
pos: start,
770+
end: end,
771+
filename: matchResult[3]
772+
};
773+
return {
774+
fileReference: fileRef,
775+
isNoDefaultLib: false
776+
};
777+
}
778+
else {
779+
return {
780+
diagnostic: Diagnostics.Invalid_reference_directive_syntax,
781+
isNoDefaultLib: false
782+
};
783+
}
784+
}
785+
}
786+
return undefined;
787+
}
788+
748789
export function isKeyword(token: SyntaxKind): boolean {
749790
return SyntaxKind.FirstKeyword <= token && token <= SyntaxKind.LastKeyword;
750791
}
@@ -4168,28 +4209,16 @@ module ts {
41684209
for (var i = 0; i < commentRanges.length; i++) {
41694210
var range = commentRanges[i];
41704211
var comment = sourceText.substring(range.pos, range.end);
4171-
var simpleReferenceRegEx = /^\/\/\/\s*<reference\s+/gim;
4172-
if (simpleReferenceRegEx.exec(comment)) {
4173-
var isNoDefaultLibRegEx = /^(\/\/\/\s*<reference\s+no-default-lib=)('|")(.+?)\2\s*\/>/gim;
4174-
if (isNoDefaultLibRegEx.exec(comment)) {
4175-
file.hasNoDefaultLib = true;
4212+
var referencePathMatchResult = getFileReferenceFromReferencePath(comment, range);
4213+
if (referencePathMatchResult) {
4214+
var fileReference = referencePathMatchResult.fileReference;
4215+
file.hasNoDefaultLib = referencePathMatchResult.isNoDefaultLib;
4216+
var diagnostic = referencePathMatchResult.diagnostic;
4217+
if (fileReference) {
4218+
referencedFiles.push(fileReference);
41764219
}
4177-
else {
4178-
var matchResult = fullTripleSlashReferencePathRegEx.exec(comment);
4179-
var start = range.pos;
4180-
var end = range.end;
4181-
var length = end - start;
4182-
4183-
if (!matchResult) {
4184-
errorAtPos(start, length, Diagnostics.Invalid_reference_directive_syntax);
4185-
}
4186-
else {
4187-
referencedFiles.push({
4188-
pos: start,
4189-
end: end,
4190-
filename: matchResult[3]
4191-
});
4192-
}
4220+
if (diagnostic) {
4221+
errorAtPos(range.pos, range.end - range.pos, diagnostic);
41934222
}
41944223
}
41954224
else {

src/harness/fourslash.ts

Lines changed: 76 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -136,10 +136,11 @@ module FourSlash {
136136
outDir: 'outDir',
137137
sourceMap: 'sourceMap',
138138
sourceRoot: 'sourceRoot',
139+
resolveReference: 'ResolveReference', // This flag is used to specify entry file for resolve file references. The flag is only allow once per test file
139140
};
140141

141142
// List of allowed metadata names
142-
var fileMetadataNames = [testOptMetadataNames.filename, testOptMetadataNames.emitThisFile];
143+
var fileMetadataNames = [testOptMetadataNames.filename, testOptMetadataNames.emitThisFile, testOptMetadataNames.resolveReference];
143144
var globalMetadataNames = [testOptMetadataNames.baselineFile, testOptMetadataNames.declaration,
144145
testOptMetadataNames.mapRoot, testOptMetadataNames.module, testOptMetadataNames.out,
145146
testOptMetadataNames.outDir, testOptMetadataNames.sourceMap, testOptMetadataNames.sourceRoot]
@@ -236,6 +237,25 @@ module FourSlash {
236237
throw new Error("Operation should be cancelled");
237238
}
238239

240+
// This function creates IScriptSnapshot object for testing getPreProcessedFileInfo
241+
// Return object may lack some functionalities for other purposes.
242+
function createScriptSnapShot(sourceText: string): TypeScript.IScriptSnapshot {
243+
return {
244+
getText: (start: number, end: number) => {
245+
return sourceText.substr(start, end - start);
246+
},
247+
getLength: () => {
248+
return sourceText.length;
249+
},
250+
getLineStartPositions: () => {
251+
return <number[]>[];
252+
},
253+
getChangeRange: (oldSnapshot: TypeScript.IScriptSnapshot) => {
254+
return <TypeScript.TextChangeRange>undefined;
255+
}
256+
};
257+
}
258+
239259
export class TestState {
240260
// Language service instance
241261
public languageServiceShimHost: Harness.LanguageService.TypeScriptLS;
@@ -264,6 +284,16 @@ module FourSlash {
264284
private scenarioActions: string[] = [];
265285
private taoInvalidReason: string = null;
266286

287+
private inputFiles: ts.Map<string> = {}; // Map between inputFile's filename and its content for easily looking up when resolving references
288+
289+
// Add input file which has matched file name with the given reference-file path.
290+
// This is necessary when resolveReference flag is specified
291+
private addMatchedInputFile(referenceFilePath: string) {
292+
var inputFile = this.inputFiles[referenceFilePath];
293+
if (inputFile && !Harness.isLibraryFile(referenceFilePath)) {
294+
this.languageServiceShimHost.addScript(referenceFilePath, inputFile);
295+
}
296+
}
267297

268298
constructor(public testData: FourSlashData) {
269299
// Initialize the language service with all the scripts
@@ -273,57 +303,57 @@ module FourSlash {
273303
var compilationSettings = convertGlobalOptionsToCompilationSettings(this.testData.globalOptions);
274304
this.languageServiceShimHost.setCompilationSettings(compilationSettings);
275305

276-
var inputFiles: { unitName: string; content: string }[] = [];
306+
var startResolveFileRef: FourSlashFile = undefined;
277307

278-
testData.files.forEach(file => {
279-
var fixedPath = file.fileName.substr(file.fileName.indexOf('tests/'));
280-
});
281-
282-
// NEWTODO: disable resolution for now.
283-
// If the last unit contains require( or /// reference then consider it the only input file
284-
// and the rest will be added via resolution. If not, then assume we have multiple files
285-
// with 0 references in any of them. We could be smarter here to allow scenarios like
286-
// 2 files without references and 1 file with a reference but we have 0 tests like that
287-
// at the moment and an exhaustive search of the test files for that content could be quite slow.
288-
var lastFile = testData.files[testData.files.length - 1];
289-
//if (/require\(/.test(lastFile.content) || /reference\spath/.test(lastFile.content)) {
290-
// inputFiles.push({ unitName: lastFile.fileName, content: lastFile.content });
291-
//} else {
292-
inputFiles = testData.files.map(file => {
293-
return { unitName: file.fileName, content: file.content };
308+
ts.forEach(testData.files, file => {
309+
// Create map between fileName and its content for easily looking up when resolveReference flag is specified
310+
this.inputFiles[file.fileName] = file.content;
311+
if (!startResolveFileRef && file.fileOptions[testOptMetadataNames.resolveReference]) {
312+
startResolveFileRef = file;
313+
} else if (startResolveFileRef) {
314+
// If entry point for resolving file references is already specified, report duplication error
315+
throw new Error("There exists a Fourslash file which has resolveReference flag specified; remove duplicated resolveReference flag");
316+
}
294317
});
295-
//}
296-
297-
298-
// NEWTODO: Re-implement commented-out section
299-
//harnessCompiler.addInputFiles(inputFiles);
300-
//try {
301-
// var resolvedFiles = harnessCompiler.resolve();
302318

303-
// resolvedFiles.forEach(file => {
304-
// if (!Harness.isLibraryFile(file.path)) {
305-
// var fixedPath = file.path.substr(file.path.indexOf('tests/'));
306-
// var content = harnessCompiler.getContentForFile(fixedPath);
307-
// this.languageServiceShimHost.addScript(fixedPath, content);
308-
// }
309-
// });
319+
if (startResolveFileRef) {
320+
// Add the entry-point file itself into the languageServiceShimHost
321+
this.languageServiceShimHost.addScript(startResolveFileRef.fileName, startResolveFileRef.content);
322+
323+
var jsonResolvedResult = JSON.parse(this.languageServiceShimHost.getCoreService().getPreProcessedFileInfo(startResolveFileRef.fileName,
324+
createScriptSnapShot(startResolveFileRef.content)));
325+
var resolvedResult = jsonResolvedResult.result;
326+
var referencedFiles: ts.IFileReference[] = resolvedResult.referencedFiles;
327+
var importedFiles: ts.IFileReference[] = resolvedResult.importedFiles;
328+
329+
// Add triple reference files into language-service host
330+
ts.forEach(referencedFiles, referenceFile => {
331+
// Fourslash insert tests/cases/fourslash into inputFile.unitName so we will properly append the same base directory to refFile path
332+
var referenceFilePath = "tests/cases/fourslash/" + referenceFile.path;
333+
this.addMatchedInputFile(referenceFilePath);
334+
});
310335

311-
// this.languageServiceShimHost.addScript('lib.d.ts', Harness.Compiler.libTextMinimal);
312-
//}
313-
//finally {
314-
// // harness no longer needs the results of the above work, make sure the next test operations are in a clean state
315-
// harnessCompiler.reset();
316-
//}
336+
// Add import files into language-service host
337+
ts.forEach(importedFiles, importedFile => {
338+
// Fourslash insert tests/cases/fourslash into inputFile.unitName and import statement doesn't require ".ts"
339+
// so convert them before making appropriate comparison
340+
var importedFilePath = "tests/cases/fourslash/" + importedFile.path + ".ts";
341+
this.addMatchedInputFile(importedFilePath);
342+
});
317343

318-
/// NEWTODO: For now do not resolve, just use the input files
319-
inputFiles.forEach(file => {
320-
if (!Harness.isLibraryFile(file.unitName)) {
321-
this.languageServiceShimHost.addScript(file.unitName, file.content);
344+
// Check if no-default-lib flag is false and if so add default library
345+
if (!resolvedResult.isLibFile) {
346+
this.languageServiceShimHost.addDefaultLibrary();
322347
}
323-
});
324-
325-
this.languageServiceShimHost.addDefaultLibrary();
326-
348+
} else {
349+
// resolveReference file-option is not specified then do not resolve any files and include all inputFiles
350+
ts.forEachKey(this.inputFiles, fileName => {
351+
if (!Harness.isLibraryFile(fileName)) {
352+
this.languageServiceShimHost.addScript(fileName, this.inputFiles[fileName]);
353+
}
354+
});
355+
this.languageServiceShimHost.addDefaultLibrary();
356+
}
327357

328358
// Sneak into the language service and get its compiler so we can examine the syntax trees
329359
this.languageService = this.languageServiceShimHost.getLanguageService().languageService;

src/harness/harnessLanguageService.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,10 @@ module Harness.LanguageService {
258258
return new TypeScript.Services.TypeScriptServicesFactory().createClassifierShim(this);
259259
}
260260

261+
public getCoreService(): ts.CoreServicesShim {
262+
return new TypeScript.Services.TypeScriptServicesFactory().createCoreServicesShim(this);
263+
}
264+
261265
/** Parse file given its source text */
262266
public parseSourceText(fileName: string, sourceText: TypeScript.IScriptSnapshot): TypeScript.SourceUnitSyntax {
263267
return TypeScript.Parser.parse(fileName, TypeScript.SimpleText.fromScriptSnapshot(sourceText), ts.ScriptTarget.Latest, TypeScript.isDTSFile(fileName)).sourceUnit();

0 commit comments

Comments
 (0)