Merge branch 'master' of https://github.com/Microsoft/TypeScript into feature/eslint
This commit is contained in:
commit
810303542d
|
@ -418,6 +418,7 @@ task("runtests-parallel").flags = {
|
|||
" --workers=<number>": "The number of parallel workers to use.",
|
||||
" --timeout=<ms>": "Overrides the default test timeout.",
|
||||
" --built": "Compile using the built version of the compiler.",
|
||||
" --skipPercent=<number>": "Skip expensive tests with <percent> chance to miss an edit. Default 5%.",
|
||||
};
|
||||
|
||||
task("diff", () => exec(getDiffTool(), [refBaseline, localBaseline], { ignoreExitCode: true }));
|
||||
|
|
|
@ -87,6 +87,7 @@
|
|||
"prex": "^0.4.3",
|
||||
"q": "latest",
|
||||
"remove-internal": "^2.9.2",
|
||||
"simple-git": "^1.113.0",
|
||||
"source-map-support": "latest",
|
||||
"through2": "latest",
|
||||
"travis-fold": "latest",
|
||||
|
@ -106,7 +107,8 @@
|
|||
"gulp": "gulp",
|
||||
"jake": "gulp",
|
||||
"lint": "gulp lint",
|
||||
"setup-hooks": "node scripts/link-hooks.js"
|
||||
"setup-hooks": "node scripts/link-hooks.js",
|
||||
"update-costly-tests": "node scripts/costly-tests.js"
|
||||
},
|
||||
"browser": {
|
||||
"fs": false,
|
||||
|
|
|
@ -14,6 +14,7 @@ module.exports = minimist(process.argv.slice(2), {
|
|||
"ru": "runners", "runner": "runners",
|
||||
"r": "reporter",
|
||||
"c": "colors", "color": "colors",
|
||||
"skip-percent": "skipPercent",
|
||||
"w": "workers",
|
||||
"f": "fix"
|
||||
},
|
||||
|
@ -69,4 +70,4 @@ if (module.exports.built) {
|
|||
*
|
||||
* @typedef {import("minimist").ParsedArgs & TypedOptions} CommandLineOptions
|
||||
*/
|
||||
void 0;
|
||||
void 0;
|
||||
|
|
|
@ -31,6 +31,7 @@ async function runConsoleTests(runJs, defaultReporter, runInParallel, watchMode,
|
|||
const inspect = cmdLineOptions.inspect;
|
||||
const runners = cmdLineOptions.runners;
|
||||
const light = cmdLineOptions.light;
|
||||
const skipPercent = process.env.CI === "true" ? 0 : cmdLineOptions.skipPercent;
|
||||
const stackTraceLimit = cmdLineOptions.stackTraceLimit;
|
||||
const testConfigFile = "test.config";
|
||||
const failed = cmdLineOptions.failed;
|
||||
|
@ -62,8 +63,8 @@ async function runConsoleTests(runJs, defaultReporter, runInParallel, watchMode,
|
|||
testTimeout = 400000;
|
||||
}
|
||||
|
||||
if (tests || runners || light || testTimeout || taskConfigsFolder || keepFailed) {
|
||||
writeTestConfigFile(tests, runners, light, taskConfigsFolder, workerCount, stackTraceLimit, testTimeout, keepFailed);
|
||||
if (tests || runners || light || testTimeout || taskConfigsFolder || keepFailed || skipPercent !== undefined) {
|
||||
writeTestConfigFile(tests, runners, light, skipPercent, taskConfigsFolder, workerCount, stackTraceLimit, testTimeout, keepFailed);
|
||||
}
|
||||
|
||||
const colors = cmdLineOptions.colors;
|
||||
|
@ -158,17 +159,19 @@ exports.cleanTestDirs = cleanTestDirs;
|
|||
* @param {string} tests
|
||||
* @param {string} runners
|
||||
* @param {boolean} light
|
||||
* @param {string} skipPercent
|
||||
* @param {string} [taskConfigsFolder]
|
||||
* @param {string | number} [workerCount]
|
||||
* @param {string} [stackTraceLimit]
|
||||
* @param {string | number} [timeout]
|
||||
* @param {boolean} [keepFailed]
|
||||
*/
|
||||
function writeTestConfigFile(tests, runners, light, taskConfigsFolder, workerCount, stackTraceLimit, timeout, keepFailed) {
|
||||
function writeTestConfigFile(tests, runners, light, skipPercent, taskConfigsFolder, workerCount, stackTraceLimit, timeout, keepFailed) {
|
||||
const testConfigContents = JSON.stringify({
|
||||
test: tests ? [tests] : undefined,
|
||||
runners: runners ? runners.split(",") : undefined,
|
||||
light,
|
||||
skipPercent,
|
||||
workerCount,
|
||||
stackTraceLimit,
|
||||
taskConfigsFolder,
|
||||
|
|
103
scripts/costly-tests.js
Normal file
103
scripts/costly-tests.js
Normal file
|
@ -0,0 +1,103 @@
|
|||
// @ts-check
|
||||
const fs = require("fs");
|
||||
const git = require('simple-git/promise')('.')
|
||||
const readline = require('readline')
|
||||
|
||||
/** @typedef {{ [s: string]: number}} Histogram */
|
||||
|
||||
async function main() {
|
||||
/** @type {Histogram} */
|
||||
const edits = Object.create(null)
|
||||
/** @type {Histogram} */
|
||||
const perf = JSON.parse(fs.readFileSync('.parallelperf.json', 'utf8'))
|
||||
|
||||
await collectCommits(git, "release-2.3", "master", /*author*/ undefined, files => fillMap(files, edits))
|
||||
|
||||
const totalTime = Object.values(perf).reduce((n,m) => n + m, 0)
|
||||
const untouched = Object.values(perf).length - Object.values(edits).length
|
||||
const totalEdits = Object.values(edits).reduce((n,m) => n + m, 0) + untouched + Object.values(edits).length
|
||||
|
||||
let i = 0
|
||||
/** @type {{ name: string, time: number, edits: number, cost: number }[]} */
|
||||
let data = []
|
||||
for (const k in perf) {
|
||||
const otherk = k.replace(/tsrunner-[a-z-]+?:\/\//, '')
|
||||
const percentTime = perf[k] / totalTime
|
||||
const percentHits = (1 + (edits[otherk] || 0)) / totalEdits
|
||||
const cost = 5 + Math.log(percentTime / percentHits)
|
||||
data.push({ name: otherk, time: perf[k], edits: 1 + (edits[otherk] || 0), cost})
|
||||
if (edits[otherk])
|
||||
i++
|
||||
}
|
||||
const output = {
|
||||
totalTime,
|
||||
totalEdits,
|
||||
data: data.sort((x,y) => y.cost - x.cost).map(x => ({ ...x, cost: x.cost.toFixed(2) }))
|
||||
}
|
||||
|
||||
fs.writeFileSync('tests/.test-cost.json', JSON.stringify(output), 'utf8')
|
||||
}
|
||||
|
||||
main().catch(e => {
|
||||
console.log(e);
|
||||
process.exit(1);
|
||||
})
|
||||
|
||||
/**
|
||||
* @param {string[]} files
|
||||
* @param {Histogram} histogram
|
||||
*/
|
||||
function fillMap(files, histogram) {
|
||||
// keep edits to test cases (but not /users), and not file moves
|
||||
const tests = files.filter(f => f.startsWith('tests/cases/') && !f.startsWith('tests/cases/user') && !/=>/.test(f))
|
||||
for (const test of tests) {
|
||||
histogram[test] = (histogram[test] || 0) + 1
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} s
|
||||
*/
|
||||
function isSquashMergeMessage(s) {
|
||||
return /\(#[0-9]+\)$/.test(s)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} s
|
||||
*/
|
||||
function isMergeCommit(s) {
|
||||
return /Merge pull request #[0-9]+/.test(s)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} s
|
||||
*/
|
||||
function parseFiles(s) {
|
||||
const lines = s.split('\n')
|
||||
// Note that slice(2) only works for merge commits, which have an empty newline after the title
|
||||
return lines.slice(2, lines.length - 2).map(line => line.split("|")[0].trim())
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import('simple-git/promise').SimpleGit} git
|
||||
* @param {string} from
|
||||
* @param {string} to
|
||||
* @param {string | undefined} author - only include commits from this author
|
||||
* @param {(files: string[]) => void} update
|
||||
*/
|
||||
async function collectCommits(git, from, to, author, update) {
|
||||
let i = 0
|
||||
for (const commit of (await git.log({ from, to })).all) {
|
||||
i++
|
||||
if ((!author || commit.author_name === author) && isMergeCommit(commit.message) || isSquashMergeMessage(commit.message)) {
|
||||
readline.clearLine(process.stdout, /*left*/ -1)
|
||||
readline.cursorTo(process.stdout, 0)
|
||||
process.stdout.write(i + ": " + commit.date)
|
||||
const files = parseFiles(await git.show([commit.hash, "--stat=1000,960,40", "--pretty=oneline"]))
|
||||
update(files)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -18,7 +18,7 @@ async function main() {
|
|||
if (!prnums.length) {
|
||||
return; // No enlisted PRs, nothing to update
|
||||
}
|
||||
if (!prnums.some(n => n === triggeredPR)) {
|
||||
if (triggeredPR && !prnums.some(n => n === triggeredPR)) {
|
||||
return; // Only have work to do for enlisted PRs
|
||||
}
|
||||
console.log(`Performing experimental branch updating and merging for pull requests ${prnums.join(", ")}`);
|
||||
|
@ -51,9 +51,8 @@ async function main() {
|
|||
issue_number: num,
|
||||
body: `This PR is configured as an experiment, and currently has rebase conflicts with master - please rebase onto master and fix the conflicts.`
|
||||
});
|
||||
throw new Error(`Rebase conflict detected in PR ${num} with master`);
|
||||
}
|
||||
return; // A PR is currently in conflict, give up
|
||||
throw new Error(`Rebase conflict detected in PR ${num} with master`); // A PR is currently in conflict, give up
|
||||
}
|
||||
runSequence([
|
||||
["git", ["fetch", "origin", `pull/${num}/head:${num}`]],
|
||||
|
|
|
@ -10099,9 +10099,9 @@ namespace ts {
|
|||
return false;
|
||||
}
|
||||
|
||||
function getPropertyTypeForIndexType(originalObjectType: Type, objectType: Type, indexType: Type, fullIndexType: Type, suppressNoImplicitAnyError: boolean, accessNode: ElementAccessExpression | IndexedAccessTypeNode | PropertyName | BindingName | SyntheticExpression | undefined, accessFlags: AccessFlags) {
|
||||
function getPropertyNameFromIndex(indexType: Type, accessNode: StringLiteral | Identifier | ObjectBindingPattern | ArrayBindingPattern | ComputedPropertyName | NumericLiteral | IndexedAccessTypeNode | ElementAccessExpression | SyntheticExpression | undefined) {
|
||||
const accessExpression = accessNode && accessNode.kind === SyntaxKind.ElementAccessExpression ? accessNode : undefined;
|
||||
const propName = isTypeUsableAsPropertyName(indexType) ?
|
||||
return isTypeUsableAsPropertyName(indexType) ?
|
||||
getPropertyNameFromType(indexType) :
|
||||
accessExpression && checkThatExpressionIsProperSymbolReference(accessExpression.argumentExpression, indexType, /*reportError*/ false) ?
|
||||
getPropertyNameForKnownSymbolName(idText((<PropertyAccessExpression>accessExpression.argumentExpression).name)) :
|
||||
|
@ -10109,6 +10109,11 @@ namespace ts {
|
|||
// late bound names are handled in the first branch, so here we only need to handle normal names
|
||||
getPropertyNameForPropertyNameNode(accessNode) :
|
||||
undefined;
|
||||
}
|
||||
|
||||
function getPropertyTypeForIndexType(originalObjectType: Type, objectType: Type, indexType: Type, fullIndexType: Type, suppressNoImplicitAnyError: boolean, accessNode: ElementAccessExpression | IndexedAccessTypeNode | PropertyName | BindingName | SyntheticExpression | undefined, accessFlags: AccessFlags) {
|
||||
const accessExpression = accessNode && accessNode.kind === SyntaxKind.ElementAccessExpression ? accessNode : undefined;
|
||||
const propName = getPropertyNameFromIndex(indexType, accessNode);
|
||||
if (propName !== undefined) {
|
||||
const prop = getPropertyOfType(objectType, propName);
|
||||
if (prop) {
|
||||
|
@ -13314,7 +13319,14 @@ namespace ts {
|
|||
}
|
||||
}
|
||||
else if (isReadonlyArrayType(target) ? isArrayType(source) || isTupleType(source) : isArrayType(target) && isTupleType(source) && !source.target.readonly) {
|
||||
return isRelatedTo(getIndexTypeOfType(source, IndexKind.Number) || anyType, getIndexTypeOfType(target, IndexKind.Number) || anyType, reportErrors);
|
||||
if (relation !== identityRelation) {
|
||||
return isRelatedTo(getIndexTypeOfType(source, IndexKind.Number) || anyType, getIndexTypeOfType(target, IndexKind.Number) || anyType, reportErrors);
|
||||
}
|
||||
else {
|
||||
// By flags alone, we know that the `target` is a readonly array while the source is a normal array or tuple
|
||||
// or `target` is an array and source is a tuple - in both cases the types cannot be identical, by construction
|
||||
return Ternary.False;
|
||||
}
|
||||
}
|
||||
// Consider a fresh empty object literal type "closed" under the subtype relationship - this way `{} <- {[idx: string]: any} <- fresh({})`
|
||||
// and not `{} <- fresh({}) <- {[idx: string]: any}`
|
||||
|
@ -20018,6 +20030,7 @@ namespace ts {
|
|||
}
|
||||
|
||||
function checkJsxExpression(node: JsxExpression, checkMode?: CheckMode) {
|
||||
checkGrammarJsxExpression(node);
|
||||
if (node.expression) {
|
||||
const type = checkExpression(node.expression, checkMode);
|
||||
if (node.dotDotDotToken && type !== anyType && !isArrayType(type)) {
|
||||
|
@ -22494,7 +22507,10 @@ namespace ts {
|
|||
case SyntaxKind.ElementAccessExpression:
|
||||
const expr = (<PropertyAccessExpression | ElementAccessExpression>node).expression;
|
||||
if (isIdentifier(expr)) {
|
||||
const symbol = getSymbolAtLocation(expr);
|
||||
let symbol = getSymbolAtLocation(expr);
|
||||
if (symbol && symbol.flags & SymbolFlags.Alias) {
|
||||
symbol = resolveAlias(symbol);
|
||||
}
|
||||
return !!(symbol && (symbol.flags & SymbolFlags.Enum) && getEnumKind(symbol) === EnumKind.Literal);
|
||||
}
|
||||
}
|
||||
|
@ -25321,7 +25337,7 @@ namespace ts {
|
|||
forEach(node.types, checkSourceElement);
|
||||
}
|
||||
|
||||
function checkIndexedAccessIndexType(type: Type, accessNode: Node) {
|
||||
function checkIndexedAccessIndexType(type: Type, accessNode: IndexedAccessTypeNode | ElementAccessExpression) {
|
||||
if (!(type.flags & TypeFlags.IndexedAccess)) {
|
||||
return type;
|
||||
}
|
||||
|
@ -25337,9 +25353,20 @@ namespace ts {
|
|||
}
|
||||
// Check if we're indexing with a numeric type and if either object or index types
|
||||
// is a generic type with a constraint that has a numeric index signature.
|
||||
if (getIndexInfoOfType(getApparentType(objectType), IndexKind.Number) && isTypeAssignableToKind(indexType, TypeFlags.NumberLike)) {
|
||||
const apparentObjectType = getApparentType(objectType);
|
||||
if (getIndexInfoOfType(apparentObjectType, IndexKind.Number) && isTypeAssignableToKind(indexType, TypeFlags.NumberLike)) {
|
||||
return type;
|
||||
}
|
||||
if (isGenericObjectType(objectType)) {
|
||||
const propertyName = getPropertyNameFromIndex(indexType, accessNode);
|
||||
if (propertyName) {
|
||||
const propertySymbol = forEachType(apparentObjectType, t => getPropertyOfType(t, propertyName));
|
||||
if (propertySymbol && getDeclarationModifierFlagsFromSymbol(propertySymbol) & ModifierFlags.NonPublicAccessibilityModifier) {
|
||||
error(accessNode, Diagnostics.Private_or_protected_member_0_cannot_be_accessed_on_a_type_parameter, unescapeLeadingUnderscores(propertyName));
|
||||
return errorType;
|
||||
}
|
||||
}
|
||||
}
|
||||
error(accessNode, Diagnostics.Type_0_cannot_be_used_to_index_type_1, typeToString(indexType), typeToString(objectType));
|
||||
return errorType;
|
||||
}
|
||||
|
@ -31889,6 +31916,12 @@ namespace ts {
|
|||
}
|
||||
}
|
||||
|
||||
function checkGrammarJsxExpression(node: JsxExpression) {
|
||||
if (node.expression && isCommaSequence(node.expression)) {
|
||||
return grammarErrorOnNode(node.expression, Diagnostics.JSX_expressions_may_not_use_the_comma_operator_Did_you_mean_to_write_an_array);
|
||||
}
|
||||
}
|
||||
|
||||
function checkGrammarForInOrForOfStatement(forInOrOfStatement: ForInOrOfStatement): boolean {
|
||||
if (checkGrammarStatementInAmbientContext(forInOrOfStatement)) {
|
||||
return true;
|
||||
|
|
|
@ -2963,6 +2963,10 @@
|
|||
"category": "Error",
|
||||
"code": 4104
|
||||
},
|
||||
"Private or protected member '{0}' cannot be accessed on a type parameter.": {
|
||||
"category": "Error",
|
||||
"code": 4105
|
||||
},
|
||||
|
||||
"The current host does not support the '{0}' option.": {
|
||||
"category": "Error",
|
||||
|
@ -5005,5 +5009,9 @@
|
|||
"Classes may not have a field named 'constructor'.": {
|
||||
"category": "Error",
|
||||
"code": 18006
|
||||
},
|
||||
"JSX expressions may not use the comma operator. Did you mean to write an array?": {
|
||||
"category": "Error",
|
||||
"code": 18007
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4430,14 +4430,18 @@ namespace ts {
|
|||
|
||||
if (token() !== SyntaxKind.CloseBraceToken) {
|
||||
node.dotDotDotToken = parseOptionalToken(SyntaxKind.DotDotDotToken);
|
||||
node.expression = parseAssignmentExpressionOrHigher();
|
||||
// Only an AssignmentExpression is valid here per the JSX spec,
|
||||
// but we can unambiguously parse a comma sequence and provide
|
||||
// a better error message in grammar checking.
|
||||
node.expression = parseExpression();
|
||||
}
|
||||
if (inExpressionContext) {
|
||||
parseExpected(SyntaxKind.CloseBraceToken);
|
||||
}
|
||||
else {
|
||||
parseExpected(SyntaxKind.CloseBraceToken, /*message*/ undefined, /*shouldAdvance*/ false);
|
||||
scanJsxText();
|
||||
if (parseExpected(SyntaxKind.CloseBraceToken, /*message*/ undefined, /*shouldAdvance*/ false)) {
|
||||
scanJsxText();
|
||||
}
|
||||
}
|
||||
|
||||
return finishNode(node);
|
||||
|
|
|
@ -583,6 +583,21 @@ namespace FourSlash {
|
|||
});
|
||||
}
|
||||
|
||||
public verifyErrorExistsAtRange(range: Range, code: number, expectedMessage?: string) {
|
||||
const span = ts.createTextSpanFromRange(range);
|
||||
const hasMatchingError = ts.some(
|
||||
this.getDiagnostics(range.fileName),
|
||||
({ code, messageText, start, length }) =>
|
||||
code === code &&
|
||||
(!expectedMessage || expectedMessage === messageText) &&
|
||||
ts.isNumber(start) && ts.isNumber(length) &&
|
||||
ts.textSpansEqual(span, { start, length }));
|
||||
|
||||
if (!hasMatchingError) {
|
||||
this.raiseError(`No error with code ${code} found at provided range.`);
|
||||
}
|
||||
}
|
||||
|
||||
public verifyNumberOfErrorsInCurrentFile(expected: number) {
|
||||
const errors = this.getDiagnostics(this.activeFile.fileName);
|
||||
const actual = errors.length;
|
||||
|
@ -4009,6 +4024,10 @@ namespace FourSlashInterface {
|
|||
this.state.verifyNoErrors();
|
||||
}
|
||||
|
||||
public errorExistsAtRange(range: FourSlash.Range, code: number, message?: string) {
|
||||
this.state.verifyErrorExistsAtRange(range, code, message);
|
||||
}
|
||||
|
||||
public numberOfErrorsInCurrentFile(expected: number) {
|
||||
this.state.verifyNumberOfErrorsInCurrentFile(expected);
|
||||
}
|
||||
|
|
33
src/services/formatting/README.md
Normal file
33
src/services/formatting/README.md
Normal file
|
@ -0,0 +1,33 @@
|
|||
# How does TypeScript formatting work?
|
||||
|
||||
To format code you need to have a formatting context and a `SourceFile`. The formatting context contains
|
||||
all user settings like tab size, newline character, etc.
|
||||
|
||||
The end result of formatting is represented by TextChange objects which hold the new string content, and
|
||||
the text to replace it with.
|
||||
|
||||
```ts
|
||||
export interface TextChange {
|
||||
span: TextSpan; // start, length
|
||||
newText: string;
|
||||
}
|
||||
```
|
||||
|
||||
## Internals
|
||||
|
||||
Most of the exposed APIs internally are `format*` and they all set up and configure `formatSpan` which could be considered the root call for formatting. Span in this case refers to the range of
|
||||
the sourcefile which should be formatted.
|
||||
|
||||
The formatSpan then uses a scanner (either with or without JSX support) which starts at the highest
|
||||
node the covers the span of text and recurses down through the node's children.
|
||||
|
||||
As it recurses, `processNode` is called on the children setting the indentation is decided and passed
|
||||
through into each of that node's children.
|
||||
|
||||
The meat of formatting decisions is made via `processPair`, the pair here being the current node and the previous node. `processPair` which mutates the formatting context to represent the current place in the scanner and requests a set of rules which can be applied to the items via `createRulesMap`.
|
||||
|
||||
There are a lot of rules, which you can find in [rules.ts](./rules.ts) each one has a left and right reference to nodes or token ranges and note of what action should be applied by the formatter.
|
||||
|
||||
### Where is this used?
|
||||
|
||||
The formatter is used mainly from any language service operation that inserts or modifies code. The formatter is not exported publicly, and so all usage can only come through the language server.
|
|
@ -229,6 +229,7 @@ namespace ts.formatting {
|
|||
|
||||
rule("NoSpaceBeforeNonNullAssertionOperator", anyToken, SyntaxKind.ExclamationToken, [isNonJsxSameLineTokenContext, isNonNullAssertionContext], RuleAction.Delete),
|
||||
rule("NoSpaceAfterNewKeywordOnConstructorSignature", SyntaxKind.NewKeyword, SyntaxKind.OpenParenToken, [isNonJsxSameLineTokenContext, isConstructorSignatureContext], RuleAction.Delete),
|
||||
rule("SpaceLessThanAndNonJSXTypeAnnotation", SyntaxKind.LessThanToken, SyntaxKind.LessThanToken, [isNonJsxSameLineTokenContext], RuleAction.Space),
|
||||
];
|
||||
|
||||
// These rules are applied after high priority
|
||||
|
@ -349,6 +350,18 @@ namespace ts.formatting {
|
|||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* A rule takes a two tokens (left/right) and a particular context
|
||||
* for which you're meant to look at them. You then declare what should the
|
||||
* whitespace annotation be between these tokens via the action param.
|
||||
*
|
||||
* @param debugName Name to print
|
||||
* @param left The left side of the comparison
|
||||
* @param right The right side of the comparison
|
||||
* @param context A set of filters to narrow down the space in which this formatter rule applies
|
||||
* @param action a declaration of the expected whitespace
|
||||
* @param flags whether the rule deletes a line or not, defaults to no-op
|
||||
*/
|
||||
function rule(
|
||||
debugName: string,
|
||||
left: SyntaxKind | ReadonlyArray<SyntaxKind> | TokenRange,
|
||||
|
|
|
@ -143,6 +143,7 @@ class CompilerTest {
|
|||
this.tsConfigFiles = [];
|
||||
if (testCaseContent.tsConfig) {
|
||||
assert.equal(testCaseContent.tsConfig.fileNames.length, 0, `list of files in tsconfig is not currently supported`);
|
||||
assert.equal(testCaseContent.tsConfig.raw.exclude, undefined, `exclude in tsconfig is not currently supported`);
|
||||
|
||||
tsConfigOptions = ts.cloneCompilerOptions(testCaseContent.tsConfig.options);
|
||||
this.tsConfigFiles.push(this.createHarnessTestFile(testCaseContent.tsConfigFileUnitData!, rootDir, ts.combinePaths(rootDir, tsConfigOptions.configFilePath)));
|
||||
|
|
|
@ -14,7 +14,7 @@ namespace Harness.Parallel.Host {
|
|||
const isatty = tty.isatty(1) && tty.isatty(2);
|
||||
const path = require("path") as typeof import("path");
|
||||
const { fork } = require("child_process") as typeof import("child_process");
|
||||
const { statSync } = require("fs") as typeof import("fs");
|
||||
const { statSync, readFileSync } = require("fs") as typeof import("fs");
|
||||
|
||||
// NOTE: paths for module and types for FailedTestReporter _do not_ line up due to our use of --outFile for run.js
|
||||
// tslint:disable-next-line:variable-name
|
||||
|
@ -192,6 +192,31 @@ namespace Harness.Parallel.Host {
|
|||
return `tsrunner-${runner}://${test}`;
|
||||
}
|
||||
|
||||
function skipCostlyTests(tasks: Task[]) {
|
||||
if (statSync("tests/.test-cost.json")) {
|
||||
const costs = JSON.parse(readFileSync("tests/.test-cost.json", "utf8")) as {
|
||||
totalTime: number,
|
||||
totalEdits: number,
|
||||
data: { name: string, time: number, edits: number, costs: number }[]
|
||||
};
|
||||
let skippedEdits = 0;
|
||||
let skippedTime = 0;
|
||||
const skippedTests = new Set<string>();
|
||||
let i = 0;
|
||||
for (; i < costs.data.length && (skippedEdits / costs.totalEdits) < (skipPercent / 100); i++) {
|
||||
skippedEdits += costs.data[i].edits;
|
||||
skippedTime += costs.data[i].time;
|
||||
skippedTests.add(costs.data[i].name);
|
||||
}
|
||||
console.log(`Skipped ${i} expensive tests; estimated time savings of ${(skippedTime / costs.totalTime * 100).toFixed(2)}% with --skipPercent=${skipPercent.toFixed(2)} chance of missing a test.`);
|
||||
return tasks.filter(t => !skippedTests.has(t.file));
|
||||
}
|
||||
else {
|
||||
console.log("No cost analysis discovered.");
|
||||
return tasks;
|
||||
}
|
||||
}
|
||||
|
||||
function startDelayed(perfData: { [testHash: string]: number } | undefined, totalCost: number) {
|
||||
console.log(`Discovered ${tasks.length} unittest suites` + (newTasks.length ? ` and ${newTasks.length} new suites.` : "."));
|
||||
console.log("Discovering runner-based tests...");
|
||||
|
@ -231,6 +256,7 @@ namespace Harness.Parallel.Host {
|
|||
}
|
||||
tasks.sort((a, b) => a.size - b.size);
|
||||
tasks = tasks.concat(newTasks);
|
||||
tasks = skipCostlyTests(tasks);
|
||||
const batchCount = workerCount;
|
||||
const packfraction = 0.9;
|
||||
const chunkSize = 1000; // ~1KB or 1s for sending batches near the end of a test
|
||||
|
|
|
@ -65,6 +65,7 @@ let runUnitTests: boolean | undefined;
|
|||
let stackTraceLimit: number | "full" | undefined;
|
||||
let noColors = false;
|
||||
let keepFailed = false;
|
||||
let skipPercent = 5;
|
||||
|
||||
interface TestConfig {
|
||||
light?: boolean;
|
||||
|
@ -78,6 +79,7 @@ interface TestConfig {
|
|||
noColors?: boolean;
|
||||
timeout?: number;
|
||||
keepFailed?: boolean;
|
||||
skipPercent?: number;
|
||||
}
|
||||
|
||||
interface TaskSet {
|
||||
|
@ -109,6 +111,9 @@ function handleTestConfig() {
|
|||
if (testConfig.keepFailed) {
|
||||
keepFailed = true;
|
||||
}
|
||||
if (testConfig.skipPercent !== undefined) {
|
||||
skipPercent = testConfig.skipPercent;
|
||||
}
|
||||
|
||||
if (testConfig.stackTraceLimit === "full") {
|
||||
(<any>Error).stackTraceLimit = Infinity;
|
||||
|
|
1
tests/.test-cost.json
Normal file
1
tests/.test-cost.json
Normal file
File diff suppressed because one or more lines are too long
33
tests/baselines/reference/constAssertionOnEnum.js
Normal file
33
tests/baselines/reference/constAssertionOnEnum.js
Normal file
|
@ -0,0 +1,33 @@
|
|||
//// [tests/cases/conformance/expressions/typeAssertions/constAssertionOnEnum.ts] ////
|
||||
|
||||
//// [enum.ts]
|
||||
export enum Foo {
|
||||
A,
|
||||
B,
|
||||
}
|
||||
|
||||
//// [test.ts]
|
||||
import {Foo} from './enum';
|
||||
|
||||
enum Bar {
|
||||
A,
|
||||
B,
|
||||
}
|
||||
let foo = Foo.A as const;
|
||||
let bar = Bar.A as const;
|
||||
|
||||
//// [enum.js]
|
||||
export var Foo;
|
||||
(function (Foo) {
|
||||
Foo[Foo["A"] = 0] = "A";
|
||||
Foo[Foo["B"] = 1] = "B";
|
||||
})(Foo || (Foo = {}));
|
||||
//// [test.js]
|
||||
import { Foo } from './enum';
|
||||
var Bar;
|
||||
(function (Bar) {
|
||||
Bar[Bar["A"] = 0] = "A";
|
||||
Bar[Bar["B"] = 1] = "B";
|
||||
})(Bar || (Bar = {}));
|
||||
let foo = Foo.A;
|
||||
let bar = Bar.A;
|
36
tests/baselines/reference/constAssertionOnEnum.symbols
Normal file
36
tests/baselines/reference/constAssertionOnEnum.symbols
Normal file
|
@ -0,0 +1,36 @@
|
|||
=== tests/cases/conformance/expressions/typeAssertions/enum.ts ===
|
||||
export enum Foo {
|
||||
>Foo : Symbol(Foo, Decl(enum.ts, 0, 0))
|
||||
|
||||
A,
|
||||
>A : Symbol(Foo.A, Decl(enum.ts, 0, 17))
|
||||
|
||||
B,
|
||||
>B : Symbol(Foo.B, Decl(enum.ts, 1, 6))
|
||||
}
|
||||
|
||||
=== tests/cases/conformance/expressions/typeAssertions/test.ts ===
|
||||
import {Foo} from './enum';
|
||||
>Foo : Symbol(Foo, Decl(test.ts, 0, 8))
|
||||
|
||||
enum Bar {
|
||||
>Bar : Symbol(Bar, Decl(test.ts, 0, 27))
|
||||
|
||||
A,
|
||||
>A : Symbol(Bar.A, Decl(test.ts, 2, 10))
|
||||
|
||||
B,
|
||||
>B : Symbol(Bar.B, Decl(test.ts, 3, 6))
|
||||
}
|
||||
let foo = Foo.A as const;
|
||||
>foo : Symbol(foo, Decl(test.ts, 6, 3))
|
||||
>Foo.A : Symbol(Foo.A, Decl(enum.ts, 0, 17))
|
||||
>Foo : Symbol(Foo, Decl(test.ts, 0, 8))
|
||||
>A : Symbol(Foo.A, Decl(enum.ts, 0, 17))
|
||||
|
||||
let bar = Bar.A as const;
|
||||
>bar : Symbol(bar, Decl(test.ts, 7, 3))
|
||||
>Bar.A : Symbol(Bar.A, Decl(test.ts, 2, 10))
|
||||
>Bar : Symbol(Bar, Decl(test.ts, 0, 27))
|
||||
>A : Symbol(Bar.A, Decl(test.ts, 2, 10))
|
||||
|
38
tests/baselines/reference/constAssertionOnEnum.types
Normal file
38
tests/baselines/reference/constAssertionOnEnum.types
Normal file
|
@ -0,0 +1,38 @@
|
|||
=== tests/cases/conformance/expressions/typeAssertions/enum.ts ===
|
||||
export enum Foo {
|
||||
>Foo : Foo
|
||||
|
||||
A,
|
||||
>A : Foo.A
|
||||
|
||||
B,
|
||||
>B : Foo.B
|
||||
}
|
||||
|
||||
=== tests/cases/conformance/expressions/typeAssertions/test.ts ===
|
||||
import {Foo} from './enum';
|
||||
>Foo : typeof Foo
|
||||
|
||||
enum Bar {
|
||||
>Bar : Bar
|
||||
|
||||
A,
|
||||
>A : Bar.A
|
||||
|
||||
B,
|
||||
>B : Bar.B
|
||||
}
|
||||
let foo = Foo.A as const;
|
||||
>foo : Foo.A
|
||||
>Foo.A as const : Foo.A
|
||||
>Foo.A : Foo.A
|
||||
>Foo : typeof Foo
|
||||
>A : Foo.A
|
||||
|
||||
let bar = Bar.A as const;
|
||||
>bar : Bar.A
|
||||
>Bar.A as const : Bar.A
|
||||
>Bar.A : Bar.A
|
||||
>Bar : typeof Bar
|
||||
>A : Bar.A
|
||||
|
|
@ -9,12 +9,8 @@ Starting "rush rebuild"
|
|||
|
||||
Executing a maximum of 1 simultaneous processes...
|
||||
|
||||
[@azure/abort-controller] started
|
||||
XX of XX: [@azure/abort-controller] completed successfully in ? seconds
|
||||
[@azure/cosmos] started
|
||||
XX of XX: [@azure/cosmos] completed successfully in ? seconds
|
||||
[@azure/event-hubs] started
|
||||
XX of XX: [@azure/event-hubs] completed successfully in ? seconds
|
||||
[@azure/service-bus] started
|
||||
Warning: You have changed the public API signature for this project. Updating review/service-bus.api.md
|
||||
[@azure/storage-blob] started
|
||||
|
@ -27,6 +23,8 @@ XX of XX: [@azure/storage-file] completed successfully in ? seconds
|
|||
XX of XX: [@azure/storage-queue] completed successfully in ? seconds
|
||||
[@azure/template] started
|
||||
XX of XX: [@azure/template] completed successfully in ? seconds
|
||||
[@azure/abort-controller] started
|
||||
XX of XX: [@azure/abort-controller] completed successfully in ? seconds
|
||||
[@azure/core-http] started
|
||||
XX of XX: [@azure/core-http] completed successfully in ? seconds
|
||||
[@azure/core-paging] started
|
||||
|
@ -37,21 +35,20 @@ XX of XX: [@azure/event-processor-host] completed successfully in ? seconds
|
|||
XX of XX: [testhub] completed successfully in ? seconds
|
||||
[@azure/identity] started
|
||||
XX of XX: [@azure/identity] completed successfully in ? seconds
|
||||
[@azure/core-amqp] started
|
||||
[@azure/keyvault-certificates] started
|
||||
XX of XX: [@azure/keyvault-certificates] completed successfully in ? seconds
|
||||
[@azure/keyvault-keys] started
|
||||
XX of XX: [@azure/keyvault-keys] completed successfully in ? seconds
|
||||
[@azure/keyvault-secrets] started
|
||||
XX of XX: [@azure/keyvault-secrets] completed successfully in ? seconds
|
||||
[@azure/core-amqp] started
|
||||
|
||||
SUCCESS (16)
|
||||
SUCCESS (15)
|
||||
================================
|
||||
@azure/abort-controller (? seconds)
|
||||
@azure/core-http (? seconds)
|
||||
@azure/core-paging (? seconds)
|
||||
@azure/cosmos (? seconds)
|
||||
@azure/event-hubs (? seconds)
|
||||
@azure/event-processor-host (? seconds)
|
||||
@azure/identity (? seconds)
|
||||
@azure/keyvault-certificates (? seconds)
|
||||
|
@ -71,14 +68,19 @@ SUCCESS WITH WARNINGS (1)
|
|||
Warning: You have changed the public API signature for this project. Updating review/service-bus.api.md
|
||||
================================
|
||||
|
||||
BLOCKED (1)
|
||||
================================
|
||||
@azure/event-hubs
|
||||
================================
|
||||
|
||||
FAILURE (1)
|
||||
================================
|
||||
@azure/core-amqp (? seconds)
|
||||
>>> @azure/core-amqp
|
||||
tsc -p . && rollup -c 2>&1
|
||||
src/errors.ts(579,20): error TS7053: Element implicitly has an 'any' type because expression of type 'any' can't be used to index type 'typeof ConditionErrorNameMapper'.
|
||||
src/errors.ts(600,34): error TS7053: Element implicitly has an 'any' type because expression of type 'any' can't be used to index type 'typeof SystemErrorConditionMapper'.
|
||||
src/errors.ts(601,20): error TS7053: Element implicitly has an 'any' type because expression of type 'any' can't be used to index type 'typeof ConditionErrorNameMapper'.
|
||||
src/errors.ts(586,20): error TS7053: Element implicitly has an 'any' type because expression of type 'any' can't be used to index type 'typeof ConditionErrorNameMapper'.
|
||||
src/errors.ts(607,34): error TS7053: Element implicitly has an 'any' type because expression of type 'any' can't be used to index type 'typeof SystemErrorConditionMapper'.
|
||||
src/errors.ts(608,20): error TS7053: Element implicitly has an 'any' type because expression of type 'any' can't be used to index type 'typeof ConditionErrorNameMapper'.
|
||||
================================
|
||||
|
||||
|
||||
|
@ -92,4 +94,5 @@ Your version of Node.js (12.4.0) has not been tested with this release of Rush.
|
|||
XX of XX: [@azure/service-bus] completed with warnings in ? seconds
|
||||
|
||||
XX of XX: [@azure/core-amqp] failed to build!
|
||||
XX of XX: [@azure/event-hubs] blocked by [@azure/core-amqp]!
|
||||
[@azure/core-amqp] Returned error code: 2
|
||||
|
|
|
@ -307,7 +307,7 @@ ts-jest[versions] (WARN) Version X.X.X-insiders.xxxxxxxx of typescript installed
|
|||
ts-jest[versions] (WARN) Version X.X.X-insiders.xxxxxxxx of typescript installed has not been tested with ts-jest. If you're experiencing issues, consider using a supported version (>=2.7.0 <4.0.0). Please do not report issues in ts-jest if you are using unsupported versions.
|
||||
================================
|
||||
|
||||
BLOCKED (26)
|
||||
BLOCKED (27)
|
||||
================================
|
||||
@uifabric/api-docs
|
||||
@uifabric/azure-themes
|
||||
|
@ -320,6 +320,7 @@ BLOCKED (26)
|
|||
@uifabric/fluent-theme
|
||||
@uifabric/foundation-scenarios
|
||||
@uifabric/lists
|
||||
@uifabric/mdl2-theme
|
||||
@uifabric/pr-deploy-site
|
||||
@uifabric/react-cards
|
||||
@uifabric/theme-samples
|
||||
|
@ -411,6 +412,7 @@ XX of XX: [@uifabric/foundation-scenarios] blocked by [@uifabric/foundation]!
|
|||
XX of XX: [@uifabric/lists] blocked by [@uifabric/foundation]!
|
||||
XX of XX: [@uifabric/fluent-theme] blocked by [@uifabric/foundation]!
|
||||
XX of XX: [@uifabric/tsx-editor] blocked by [@uifabric/foundation]!
|
||||
XX of XX: [@uifabric/mdl2-theme] blocked by [@uifabric/foundation]!
|
||||
XX of XX: [@uifabric/theme-samples] blocked by [@uifabric/foundation]!
|
||||
XX of XX: [@uifabric/variants] blocked by [@uifabric/foundation]!
|
||||
XX of XX: [server-rendered-app] blocked by [@uifabric/foundation]!
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
tests/cases/compiler/indexedAccessPrivateMemberOfGenericConstraint.ts(9,24): error TS4105: Private or protected member 'a' cannot be accessed on a type parameter.
|
||||
tests/cases/compiler/indexedAccessPrivateMemberOfGenericConstraint.ts(9,32): error TS4105: Private or protected member 'a' cannot be accessed on a type parameter.
|
||||
tests/cases/compiler/indexedAccessPrivateMemberOfGenericConstraint.ts(10,27): error TS4105: Private or protected member 'a' cannot be accessed on a type parameter.
|
||||
tests/cases/compiler/indexedAccessPrivateMemberOfGenericConstraint.ts(11,27): error TS4105: Private or protected member 'a' cannot be accessed on a type parameter.
|
||||
|
||||
|
||||
==== tests/cases/compiler/indexedAccessPrivateMemberOfGenericConstraint.ts (4 errors) ====
|
||||
class A {
|
||||
private a: number;
|
||||
}
|
||||
|
||||
class B {
|
||||
private a: string;
|
||||
}
|
||||
|
||||
type X<T extends A> = [T["a"], (T | B)["a"]];
|
||||
~~~~~~
|
||||
!!! error TS4105: Private or protected member 'a' cannot be accessed on a type parameter.
|
||||
~~~~~~~~~~~~
|
||||
!!! error TS4105: Private or protected member 'a' cannot be accessed on a type parameter.
|
||||
type Y<T extends A | B> = T["a"];
|
||||
~~~~~~
|
||||
!!! error TS4105: Private or protected member 'a' cannot be accessed on a type parameter.
|
||||
type Z<T extends A & B> = T["a"];
|
||||
~~~~~~
|
||||
!!! error TS4105: Private or protected member 'a' cannot be accessed on a type parameter.
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
//// [indexedAccessPrivateMemberOfGenericConstraint.ts]
|
||||
class A {
|
||||
private a: number;
|
||||
}
|
||||
|
||||
class B {
|
||||
private a: string;
|
||||
}
|
||||
|
||||
type X<T extends A> = [T["a"], (T | B)["a"]];
|
||||
type Y<T extends A | B> = T["a"];
|
||||
type Z<T extends A & B> = T["a"];
|
||||
|
||||
|
||||
//// [indexedAccessPrivateMemberOfGenericConstraint.js]
|
||||
var A = /** @class */ (function () {
|
||||
function A() {
|
||||
}
|
||||
return A;
|
||||
}());
|
||||
var B = /** @class */ (function () {
|
||||
function B() {
|
||||
}
|
||||
return B;
|
||||
}());
|
|
@ -0,0 +1,37 @@
|
|||
=== tests/cases/compiler/indexedAccessPrivateMemberOfGenericConstraint.ts ===
|
||||
class A {
|
||||
>A : Symbol(A, Decl(indexedAccessPrivateMemberOfGenericConstraint.ts, 0, 0))
|
||||
|
||||
private a: number;
|
||||
>a : Symbol(A.a, Decl(indexedAccessPrivateMemberOfGenericConstraint.ts, 0, 9))
|
||||
}
|
||||
|
||||
class B {
|
||||
>B : Symbol(B, Decl(indexedAccessPrivateMemberOfGenericConstraint.ts, 2, 1))
|
||||
|
||||
private a: string;
|
||||
>a : Symbol(B.a, Decl(indexedAccessPrivateMemberOfGenericConstraint.ts, 4, 9))
|
||||
}
|
||||
|
||||
type X<T extends A> = [T["a"], (T | B)["a"]];
|
||||
>X : Symbol(X, Decl(indexedAccessPrivateMemberOfGenericConstraint.ts, 6, 1))
|
||||
>T : Symbol(T, Decl(indexedAccessPrivateMemberOfGenericConstraint.ts, 8, 7))
|
||||
>A : Symbol(A, Decl(indexedAccessPrivateMemberOfGenericConstraint.ts, 0, 0))
|
||||
>T : Symbol(T, Decl(indexedAccessPrivateMemberOfGenericConstraint.ts, 8, 7))
|
||||
>T : Symbol(T, Decl(indexedAccessPrivateMemberOfGenericConstraint.ts, 8, 7))
|
||||
>B : Symbol(B, Decl(indexedAccessPrivateMemberOfGenericConstraint.ts, 2, 1))
|
||||
|
||||
type Y<T extends A | B> = T["a"];
|
||||
>Y : Symbol(Y, Decl(indexedAccessPrivateMemberOfGenericConstraint.ts, 8, 45))
|
||||
>T : Symbol(T, Decl(indexedAccessPrivateMemberOfGenericConstraint.ts, 9, 7))
|
||||
>A : Symbol(A, Decl(indexedAccessPrivateMemberOfGenericConstraint.ts, 0, 0))
|
||||
>B : Symbol(B, Decl(indexedAccessPrivateMemberOfGenericConstraint.ts, 2, 1))
|
||||
>T : Symbol(T, Decl(indexedAccessPrivateMemberOfGenericConstraint.ts, 9, 7))
|
||||
|
||||
type Z<T extends A & B> = T["a"];
|
||||
>Z : Symbol(Z, Decl(indexedAccessPrivateMemberOfGenericConstraint.ts, 9, 33))
|
||||
>T : Symbol(T, Decl(indexedAccessPrivateMemberOfGenericConstraint.ts, 10, 7))
|
||||
>A : Symbol(A, Decl(indexedAccessPrivateMemberOfGenericConstraint.ts, 0, 0))
|
||||
>B : Symbol(B, Decl(indexedAccessPrivateMemberOfGenericConstraint.ts, 2, 1))
|
||||
>T : Symbol(T, Decl(indexedAccessPrivateMemberOfGenericConstraint.ts, 10, 7))
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
=== tests/cases/compiler/indexedAccessPrivateMemberOfGenericConstraint.ts ===
|
||||
class A {
|
||||
>A : A
|
||||
|
||||
private a: number;
|
||||
>a : number
|
||||
}
|
||||
|
||||
class B {
|
||||
>B : B
|
||||
|
||||
private a: string;
|
||||
>a : string
|
||||
}
|
||||
|
||||
type X<T extends A> = [T["a"], (T | B)["a"]];
|
||||
>X : [T["a"], (B | T)["a"]]
|
||||
|
||||
type Y<T extends A | B> = T["a"];
|
||||
>Y : T["a"]
|
||||
|
||||
type Z<T extends A & B> = T["a"];
|
||||
>Z : T["a"]
|
||||
|
|
@ -28,18 +28,21 @@ var foo = /** @class */ (function () {
|
|||
return foo;
|
||||
}());
|
||||
var x;
|
||||
x = <any> {test} <any></any> };
|
||||
x = <any> {test}: <any></any> };
|
||||
|
||||
x = <any><any></any>;
|
||||
|
||||
x = <foo>hello {<foo>} </foo>}
|
||||
x = <foo>hello {<foo>} </foo>};
|
||||
|
||||
x = <foo test={<foo>}>hello</foo>}/>
|
||||
|
||||
x = <foo test={<foo>}>hello{<foo>}</foo>}
|
||||
x = <foo test={<foo>}>hello{<foo>}</foo>};
|
||||
|
||||
x = <foo>x</foo>, x = <foo />;
|
||||
|
||||
<foo>{<foo><foo>{/foo/.test(x) ? <foo><foo></foo> : <foo><foo></foo>}</foo>}</foo>
|
||||
:
|
||||
}</></>}</></>}/></></></>;
|
||||
}
|
||||
|
||||
|
||||
</></>}</></>}/></></></>;
|
||||
|
|
|
@ -123,7 +123,7 @@ var x = <div>one</div>, <div>two</div>;
|
|||
var x = <div>one</div> /* intervening comment */, /* intervening comment */ <div>two</div>;
|
||||
;
|
||||
//// [20.jsx]
|
||||
<a>{"str"}}</a>;
|
||||
<a>{"str"};}</a>;
|
||||
//// [21.jsx]
|
||||
<span className="a" id="b"/>;
|
||||
//// [22.jsx]
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
tests/cases/conformance/jsx/file.tsx(11,36): error TS1005: '}' expected.
|
||||
tests/cases/conformance/jsx/file.tsx(11,44): error TS1003: Identifier expected.
|
||||
tests/cases/conformance/jsx/file.tsx(11,46): error TS1161: Unterminated regular expression literal.
|
||||
tests/cases/conformance/jsx/file.tsx(11,30): error TS2695: Left side of comma operator is unused and has no side effects.
|
||||
tests/cases/conformance/jsx/file.tsx(11,30): error TS18007: JSX expressions may not use the comma operator. Did you mean to write an array?
|
||||
|
||||
|
||||
==== tests/cases/conformance/jsx/file.tsx (3 errors) ====
|
||||
==== tests/cases/conformance/jsx/file.tsx (2 errors) ====
|
||||
declare module JSX {
|
||||
interface Element { }
|
||||
interface IntrinsicElements {
|
||||
|
@ -15,10 +14,8 @@ tests/cases/conformance/jsx/file.tsx(11,46): error TS1161: Unterminated regular
|
|||
const class1 = "foo";
|
||||
const class2 = "bar";
|
||||
const elem = <div className={class1, class2}/>;
|
||||
~
|
||||
!!! error TS1005: '}' expected.
|
||||
~
|
||||
!!! error TS1003: Identifier expected.
|
||||
|
||||
!!! error TS1161: Unterminated regular expression literal.
|
||||
~~~~~~
|
||||
!!! error TS2695: Left side of comma operator is unused and has no side effects.
|
||||
~~~~~~~~~~~~~~
|
||||
!!! error TS18007: JSX expressions may not use the comma operator. Did you mean to write an array?
|
||||
|
|
@ -16,5 +16,4 @@ const elem = <div className={class1, class2}/>;
|
|||
// This should be a parse error
|
||||
var class1 = "foo";
|
||||
var class2 = "bar";
|
||||
var elem = <div className={class1} class2/>;
|
||||
/>;;
|
||||
var elem = <div className={class1, class2}/>;
|
||||
|
|
|
@ -25,5 +25,5 @@ const elem = <div className={class1, class2}/>;
|
|||
>div : Symbol(JSX.IntrinsicElements, Decl(file.tsx, 1, 22))
|
||||
>className : Symbol(className, Decl(file.tsx, 10, 17))
|
||||
>class1 : Symbol(class1, Decl(file.tsx, 8, 5))
|
||||
>class2 : Symbol(class2, Decl(file.tsx, 10, 36))
|
||||
>class2 : Symbol(class2, Decl(file.tsx, 9, 5))
|
||||
|
||||
|
|
|
@ -18,10 +18,10 @@ const class2 = "bar";
|
|||
|
||||
const elem = <div className={class1, class2}/>;
|
||||
>elem : JSX.Element
|
||||
><div className={class1, class2 : JSX.Element
|
||||
><div className={class1, class2}/> : JSX.Element
|
||||
>div : any
|
||||
>className : string
|
||||
>class1, class2 : "bar"
|
||||
>class1 : "foo"
|
||||
>class2 : true
|
||||
>/>; : RegExp
|
||||
>class2 : "bar"
|
||||
|
||||
|
|
|
@ -8,8 +8,7 @@
|
|||
"module": "commonjs",
|
||||
"moduleResolution": "node",
|
||||
"outDir": "bin"
|
||||
},
|
||||
"exclude": [ "node_modules" ]
|
||||
}
|
||||
}
|
||||
==== /index.ts (1 errors) ====
|
||||
/// <reference path="/typings/index.d.ts" />
|
||||
|
|
|
@ -1,26 +1,14 @@
|
|||
tests/cases/conformance/jsx/file.tsx(4,11): error TS17008: JSX element 'div' has no corresponding closing tag.
|
||||
tests/cases/conformance/jsx/file.tsx(4,19): error TS1109: Expression expected.
|
||||
tests/cases/conformance/jsx/file.tsx(7,11): error TS2304: Cannot find name 'a'.
|
||||
tests/cases/conformance/jsx/file.tsx(7,12): error TS1005: '}' expected.
|
||||
tests/cases/conformance/jsx/file.tsx(8,1): error TS1005: '</' expected.
|
||||
|
||||
|
||||
==== tests/cases/conformance/jsx/file.tsx (5 errors) ====
|
||||
==== tests/cases/conformance/jsx/file.tsx (1 errors) ====
|
||||
declare namespace JSX { interface Element { } }
|
||||
|
||||
function foo() {
|
||||
var x = <div> { </div>
|
||||
~~~
|
||||
!!! error TS17008: JSX element 'div' has no corresponding closing tag.
|
||||
~~
|
||||
!!! error TS1109: Expression expected.
|
||||
}
|
||||
// Shouldn't see any errors down here
|
||||
var y = { a: 1 };
|
||||
~
|
||||
!!! error TS2304: Cannot find name 'a'.
|
||||
~
|
||||
!!! error TS1005: '}' expected.
|
||||
|
||||
|
||||
!!! error TS1005: '</' expected.
|
||||
|
|
@ -10,9 +10,7 @@ var y = { a: 1 };
|
|||
|
||||
//// [file.jsx]
|
||||
function foo() {
|
||||
var x = <div> {}div>
|
||||
}
|
||||
// Shouldn't see any errors down here
|
||||
var y = {a} 1 };
|
||||
</>;
|
||||
var x = <div> {} </div>;
|
||||
}
|
||||
// Shouldn't see any errors down here
|
||||
var y = { a: 1 };
|
||||
|
|
|
@ -11,4 +11,6 @@ function foo() {
|
|||
}
|
||||
// Shouldn't see any errors down here
|
||||
var y = { a: 1 };
|
||||
>y : Symbol(y, Decl(file.tsx, 6, 3))
|
||||
>a : Symbol(a, Decl(file.tsx, 6, 9))
|
||||
|
||||
|
|
|
@ -6,13 +6,15 @@ function foo() {
|
|||
|
||||
var x = <div> { </div>
|
||||
>x : JSX.Element
|
||||
><div> { </div>}// Shouldn't see any errors down herevar y = { a: 1 }; : JSX.Element
|
||||
><div> { </div> : JSX.Element
|
||||
>div : any
|
||||
> : any
|
||||
>div : any
|
||||
}
|
||||
// Shouldn't see any errors down here
|
||||
var y = { a: 1 };
|
||||
>a : any
|
||||
|
||||
> : any
|
||||
>y : { a: number; }
|
||||
>{ a: 1 } : { a: number; }
|
||||
>a : number
|
||||
>1 : 1
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ node_modules/adonis-framework/src/Encryption/index.js(85,23): error TS8024: JSDo
|
|||
node_modules/adonis-framework/src/Encryption/index.js(87,15): error TS2304: Cannot find name 'Mixed'.
|
||||
node_modules/adonis-framework/src/Encryption/index.js(101,62): error TS2345: Argument of type 'string' is not assignable to parameter of type 'Utf8AsciiBinaryEncoding'.
|
||||
node_modules/adonis-framework/src/Encryption/index.js(114,15): error TS2304: Cannot find name 'Mixed'.
|
||||
node_modules/adonis-framework/src/Encryption/index.js(119,18): error TS2554: Expected 2 arguments, but got 1.
|
||||
node_modules/adonis-framework/src/Encryption/index.js(119,23): error TS2554: Expected 2 arguments, but got 1.
|
||||
node_modules/adonis-framework/src/Encryption/index.js(183,15): error TS2304: Cannot find name 'Mixed'.
|
||||
node_modules/adonis-framework/src/Encryption/index.js(197,15): error TS2304: Cannot find name 'Mixed'.
|
||||
node_modules/adonis-framework/src/Encryption/index.js(209,14): error TS8024: JSDoc '@param' tag has name 'object', but there is no parameter with that name.
|
||||
|
@ -69,7 +69,7 @@ node_modules/adonis-framework/src/File/index.js(273,5): error TS2322: Type 'bool
|
|||
Type '""' is not assignable to type 'boolean'.
|
||||
node_modules/adonis-framework/src/Helpers/index.js(105,3): error TS2322: Type 'null' is not assignable to type 'string'.
|
||||
node_modules/adonis-framework/src/Helpers/index.js(106,3): error TS2322: Type 'null' is not assignable to type 'string'.
|
||||
node_modules/adonis-framework/src/Helpers/index.js(164,10): error TS2554: Expected 3 arguments, but got 2.
|
||||
node_modules/adonis-framework/src/Helpers/index.js(164,18): error TS2554: Expected 3 arguments, but got 2.
|
||||
node_modules/adonis-framework/src/Helpers/index.js(178,45): error TS2345: Argument of type 'string | undefined' is not assignable to parameter of type 'string'.
|
||||
Type 'undefined' is not assignable to type 'string'.
|
||||
node_modules/adonis-framework/src/Helpers/index.js(224,45): error TS2345: Argument of type 'string | undefined' is not assignable to parameter of type 'string'.
|
||||
|
@ -100,8 +100,8 @@ node_modules/adonis-framework/src/Request/index.js(482,15): error TS2304: Cannot
|
|||
node_modules/adonis-framework/src/Request/index.js(499,17): error TS2551: Property '_params' does not exist on type 'Request'. Did you mean 'param'?
|
||||
node_modules/adonis-framework/src/Request/index.js(523,15): error TS2304: Cannot find name 'Objecr'.
|
||||
node_modules/adonis-framework/src/Request/index.js(572,23): error TS8029: JSDoc '@param' tag has name 'pattern', but there is no parameter with that name. It would match 'arguments' if it had an array type.
|
||||
node_modules/adonis-framework/src/Request/index.js(600,12): error TS2554: Expected 2 arguments, but got 1.
|
||||
node_modules/adonis-framework/src/Request/index.js(600,35): error TS2554: Expected 2 arguments, but got 1.
|
||||
node_modules/adonis-framework/src/Request/index.js(600,17): error TS2554: Expected 2 arguments, but got 1.
|
||||
node_modules/adonis-framework/src/Request/index.js(600,40): error TS2554: Expected 2 arguments, but got 1.
|
||||
node_modules/adonis-framework/src/Request/index.js(663,23): error TS8024: JSDoc '@param' tag has name 'encodings', but there is no parameter with that name.
|
||||
node_modules/adonis-framework/src/Response/index.js(44,7): error TS1056: Accessors are only available when targeting ECMAScript 5 and higher.
|
||||
node_modules/adonis-framework/src/Response/index.js(56,7): error TS1056: Accessors are only available when targeting ECMAScript 5 and higher.
|
||||
|
@ -157,7 +157,7 @@ node_modules/adonis-framework/src/Route/resource.js(296,15): error TS2304: Canno
|
|||
node_modules/adonis-framework/src/Route/resource.js(314,62): error TS2345: Argument of type 'IArguments' is not assignable to parameter of type 'any[]'.
|
||||
node_modules/adonis-framework/src/Server/helpers.js(17,29): error TS8024: JSDoc '@param' tag has name 'appNamespace', but there is no parameter with that name.
|
||||
node_modules/adonis-framework/src/Server/index.js(17,21): error TS2307: Cannot find module 'adonis-fold'.
|
||||
node_modules/adonis-framework/src/Server/index.js(54,21): error TS2554: Expected 4 arguments, but got 3.
|
||||
node_modules/adonis-framework/src/Server/index.js(54,29): error TS2554: Expected 4 arguments, but got 3.
|
||||
node_modules/adonis-framework/src/Server/index.js(137,25): error TS8024: JSDoc '@param' tag has name 'handlers', but there is no parameter with that name.
|
||||
node_modules/adonis-framework/src/Server/index.js(252,15): error TS2304: Cannot find name 'instance'.
|
||||
node_modules/adonis-framework/src/Server/index.js(252,24): error TS1005: '}' expected.
|
||||
|
@ -211,7 +211,7 @@ node_modules/adonis-framework/src/View/Form/index.js(147,63): error TS2345: Argu
|
|||
node_modules/adonis-framework/src/View/Form/index.js(151,58): error TS2345: Argument of type 'string | any[]' is not assignable to parameter of type 'any[]'.
|
||||
Type 'string' is not assignable to type 'any[]'.
|
||||
node_modules/adonis-framework/src/View/Form/index.js(415,37): error TS2345: Argument of type 'null' is not assignable to parameter of type 'string'.
|
||||
node_modules/adonis-framework/src/View/Form/index.js(578,20): error TS2554: Expected 2 arguments, but got 1.
|
||||
node_modules/adonis-framework/src/View/Form/index.js(578,25): error TS2554: Expected 2 arguments, but got 1.
|
||||
node_modules/adonis-framework/src/View/Form/index.js(601,51): error TS2345: Argument of type 'number | any[]' is not assignable to parameter of type 'string | any[]'.
|
||||
Type 'number' is not assignable to type 'string | any[]'.
|
||||
node_modules/adonis-framework/src/View/index.js(50,23): error TS8024: JSDoc '@param' tag has name 'template_path', but there is no parameter with that name.
|
||||
|
|
|
@ -19,7 +19,7 @@ lib/adapters/xhr.js(81,51): error TS2345: Argument of type 'null' is not assigna
|
|||
lib/adapters/xhr.js(84,7): error TS2322: Type 'null' is not assignable to type 'XMLHttpRequest'.
|
||||
lib/adapters/xhr.js(93,7): error TS2322: Type 'null' is not assignable to type 'XMLHttpRequest'.
|
||||
lib/adapters/xhr.js(163,9): error TS2322: Type 'null' is not assignable to type 'XMLHttpRequest'.
|
||||
lib/axios.js(23,3): error TS2554: Expected 3 arguments, but got 2.
|
||||
lib/axios.js(23,9): error TS2554: Expected 3 arguments, but got 2.
|
||||
lib/axios.js(25,3): error TS2739: Type '(...args: any[]) => any' is missing the following properties from type 'Axios': defaults, interceptors, request, getUri
|
||||
lib/axios.js(32,7): error TS2339: Property 'Axios' does not exist on type 'Axios'.
|
||||
lib/axios.js(35,7): error TS2339: Property 'create' does not exist on type 'Axios'.
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,7 +1,6 @@
|
|||
// @filename: /foo/tsconfig.json
|
||||
{
|
||||
"compilerOptions": { "composite": true },
|
||||
"exclude": [ "node_modules" ]
|
||||
"compilerOptions": { "composite": true }
|
||||
}
|
||||
|
||||
// @filename: /foo/node_modules/myModule/index.ts
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
class A {
|
||||
private a: number;
|
||||
}
|
||||
|
||||
class B {
|
||||
private a: string;
|
||||
}
|
||||
|
||||
type X<T extends A> = [T["a"], (T | B)["a"]];
|
||||
type Y<T extends A | B> = T["a"];
|
||||
type Z<T extends A & B> = T["a"];
|
|
@ -11,8 +11,7 @@
|
|||
"module": "commonjs",
|
||||
"moduleResolution": "node",
|
||||
"outDir": "bin"
|
||||
},
|
||||
"exclude": [ "node_modules" ]
|
||||
}
|
||||
}
|
||||
// @filename: /node_modules/shortid/node_modules/z/index.js
|
||||
// z will not be found because maxNodeModulesJsDepth: 0
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
// @strict: true
|
||||
// @target: esnext
|
||||
|
||||
// @filename: enum.ts
|
||||
export enum Foo {
|
||||
A,
|
||||
B,
|
||||
}
|
||||
|
||||
// @filename: test.ts
|
||||
import {Foo} from './enum';
|
||||
|
||||
enum Bar {
|
||||
A,
|
||||
B,
|
||||
}
|
||||
let foo = Foo.A as const;
|
||||
let bar = Bar.A as const;
|
8
tests/cases/fourslash/formattingDoubleLessThan.ts
Normal file
8
tests/cases/fourslash/formattingDoubleLessThan.ts
Normal file
|
@ -0,0 +1,8 @@
|
|||
///<reference path="fourslash.ts"/>
|
||||
// https://github.com/microsoft/TypeScript/issues/14589
|
||||
|
||||
/////*1*/if (<number>foo < <number>bar) {}
|
||||
|
||||
format.document();
|
||||
goTo.marker("1")
|
||||
verify.currentLineContentIs(`if (<number>foo < <number>bar) { }`)
|
|
@ -42,6 +42,8 @@
|
|||
//
|
||||
// TODO: figure out a better solution to the API exposure problem.
|
||||
|
||||
/// <reference path="../../../src/compiler/diagnosticInformationMap.generated.ts" />
|
||||
|
||||
declare module ts {
|
||||
export type MapKey = string | number;
|
||||
export interface Map<T> {
|
||||
|
@ -70,6 +72,21 @@ declare module ts {
|
|||
text: string;
|
||||
}
|
||||
|
||||
enum DiagnosticCategory {
|
||||
Warning,
|
||||
Error,
|
||||
Suggestion,
|
||||
Message
|
||||
}
|
||||
|
||||
interface DiagnosticMessage {
|
||||
key: string;
|
||||
category: DiagnosticCategory;
|
||||
code: number;
|
||||
message: string;
|
||||
reportsUnnecessary?: {};
|
||||
}
|
||||
|
||||
function flatMap<T, U>(array: ReadonlyArray<T>, mapfn: (x: T, i: number) => U | ReadonlyArray<U> | undefined): U[];
|
||||
}
|
||||
|
||||
|
@ -238,6 +255,7 @@ declare namespace FourSlashInterface {
|
|||
signatureHelp(...options: VerifySignatureHelpOptions[], ): void;
|
||||
// Checks that there are no compile errors.
|
||||
noErrors(): void;
|
||||
errorExistsAtRange(range: Range, code: number, message?: string): void;
|
||||
numberOfErrorsInCurrentFile(expected: number): void;
|
||||
baselineCurrentFileBreakpointLocations(): void;
|
||||
baselineCurrentFileNameOrDottedNameSpans(): void;
|
||||
|
|
12
tests/cases/fourslash/jsxExpressionFollowedByIdentifier.ts
Normal file
12
tests/cases/fourslash/jsxExpressionFollowedByIdentifier.ts
Normal file
|
@ -0,0 +1,12 @@
|
|||
/// <reference path="fourslash.ts" />
|
||||
|
||||
//@Filename: jsxExpressionFollowedByIdentifier.tsx
|
||||
////declare var React: any;
|
||||
////const a = <div>{<div />[|x|]}</div>
|
||||
////const b = <div x={<div />[|x|]} />
|
||||
|
||||
test.ranges().forEach(range => {
|
||||
verify.errorExistsAtRange(range, ts.Diagnostics._0_expected.code, "'}' expected.");
|
||||
// This is just to ensure getting quick info doesn’t crash
|
||||
verify.not.quickInfoExists();
|
||||
});
|
11
tests/cases/fourslash/jsxExpressionWithCommaExpression.ts
Normal file
11
tests/cases/fourslash/jsxExpressionWithCommaExpression.ts
Normal file
|
@ -0,0 +1,11 @@
|
|||
/// <reference path="fourslash.ts" />
|
||||
|
||||
//@Filename: jsxExpressionWithCommaExpression.tsx
|
||||
//@jsx: react
|
||||
////declare var React: any;
|
||||
////declare var x: string;
|
||||
////const a = <div x={[|x, x|]} />
|
||||
////const b = <div>{[|x, x|]}</div>
|
||||
|
||||
verify.getSyntacticDiagnostics([]);
|
||||
test.ranges().forEach(range => verify.errorExistsAtRange(range, 18006));
|
|
@ -0,0 +1,15 @@
|
|||
/// <reference path="fourslash.ts" />
|
||||
////type TypeEq<A, B> = (<T>() => T extends A ? 1 : 2) extends (<T>() => T extends B ? 1 : 2) ? true : false;
|
||||
////
|
||||
////const /*2*/test1: TypeEq<number[], [number, ...number[]]> = false;
|
||||
////
|
||||
////declare const foo: [number, ...number[]];
|
||||
////declare const bar: number[];
|
||||
////
|
||||
////const /*1*/test2: TypeEq<typeof foo, typeof bar> = false;
|
||||
|
||||
goTo.marker("1");
|
||||
verify.quickInfoIs("const test2: false");
|
||||
|
||||
goTo.marker("2");
|
||||
verify.quickInfoIs("const test1: false");
|
Loading…
Reference in a new issue