diff --git a/.dprint.jsonc b/.dprint.jsonc index aaa8e9927a0ae..6ac867ac7debc 100644 --- a/.dprint.jsonc +++ b/.dprint.jsonc @@ -29,15 +29,9 @@ "exportDeclaration.sortNamedExports": "caseInsensitive", "importDeclaration.sortNamedImports": "caseInsensitive" }, - "prettier": { - "newLineKind": "lf", - "associations": [ - "**/*.{yaml,yml}" - ], - "yml.tabWidth": 2, - "yaml.tabWidth": 2, - "yml.singleQuote": true, - "yaml.singleQuote": true + "yaml": { + "indentWidth": 2, + "quotes": "preferSingle" }, "json": { // This would be good to do in known-JSONC files, but VS Code warns on trailing commas. @@ -61,6 +55,6 @@ "plugins": [ "https://plugins.dprint.dev/typescript-0.91.6.wasm", "https://plugins.dprint.dev/json-0.19.3.wasm", - "https://plugins.dprint.dev/prettier-0.46.1.json@e5bd083088a8dfc6e5ce2d3c9bee81489b065bd5345ef55b59f5d96627928b7a" + "https://plugins.dprint.dev/g-plane/pretty_yaml-v0.5.0.wasm" ] } diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index ae238b633d5e4..c6a94e41b7f26 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -46,7 +46,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@429e1977040da7a23b6822b13c129cd1ba93dbb2 # v3.26.2 + uses: github/codeql-action/init@2c779ab0d087cd7fe7b826087247c2c81f27bfa6 # v3.26.5 with: config-file: ./.github/codeql/codeql-configuration.yml # Override language selection by uncommenting this and choosing your languages @@ -56,7 +56,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below). - name: Autobuild - uses: github/codeql-action/autobuild@429e1977040da7a23b6822b13c129cd1ba93dbb2 # v3.26.2 + uses: github/codeql-action/autobuild@2c779ab0d087cd7fe7b826087247c2c81f27bfa6 # v3.26.5 # â„šī¸ Command-line programs to run using the OS shell. # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun @@ -70,4 +70,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@429e1977040da7a23b6822b13c129cd1ba93dbb2 # v3.26.2 + uses: github/codeql-action/analyze@2c779ab0d087cd7fe7b826087247c2c81f27bfa6 # v3.26.5 diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 8dca835f7bd40..981902d12738d 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -55,6 +55,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: 'Upload to code-scanning' - uses: github/codeql-action/upload-sarif@429e1977040da7a23b6822b13c129cd1ba93dbb2 # v3.26.2 + uses: github/codeql-action/upload-sarif@2c779ab0d087cd7fe7b826087247c2c81f27bfa6 # v3.26.5 with: sarif_file: results.sarif diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 13523516bab99..a6561122df5fe 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -39818,6 +39818,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.NewExpression: case SyntaxKind.PropertyAccessExpression: case SyntaxKind.YieldExpression: + case SyntaxKind.ThisKeyword: return PredicateSemantics.Sometimes; case SyntaxKind.BinaryExpression: // List of operators that can produce null/undefined: diff --git a/src/services/completions.ts b/src/services/completions.ts index 99c2becb47540..65de51651a0f1 100644 --- a/src/services/completions.ts +++ b/src/services/completions.ts @@ -336,6 +336,7 @@ import { rangeContainsPosition, rangeContainsPositionExclusive, rangeIsOnSingleLine, + scanner, ScriptElementKind, ScriptElementKindModifier, ScriptTarget, @@ -1889,9 +1890,16 @@ function createCompletionEntry( if (parentNamedImportOrExport) { const languageVersion = getEmitScriptTarget(host.getCompilationSettings()); if (!isIdentifierText(name, languageVersion)) { - insertText = JSON.stringify(name); + insertText = quotePropertyName(sourceFile, preferences, name); + if (parentNamedImportOrExport.kind === SyntaxKind.NamedImports) { - insertText += " as " + generateIdentifierForArbitraryString(name, languageVersion); + // check if it is import { ^here as name } from '...' + // we have to access the scanner here to check if it is { ^here as name } or { ^here, as, name }. + scanner.setText(sourceFile.text); + scanner.resetTokenState(position); + if (!(scanner.scan() === SyntaxKind.AsKeyword && scanner.scan() === SyntaxKind.Identifier)) { + insertText += " as " + generateIdentifierForArbitraryString(name, languageVersion); + } } } else if (parentNamedImportOrExport.kind === SyntaxKind.NamedImports) { @@ -4948,7 +4956,10 @@ function getCompletionData( return !isFromObjectTypeDeclaration(contextToken); case SyntaxKind.Identifier: { - if (containingNodeKind === SyntaxKind.ImportSpecifier && + if (( + containingNodeKind === SyntaxKind.ImportSpecifier || + containingNodeKind === SyntaxKind.ExportSpecifier + ) && contextToken === (parent as ImportSpecifier).name && (contextToken as Identifier).text === "type" ) { diff --git a/tests/baselines/reference/predicateSemantics.errors.txt b/tests/baselines/reference/predicateSemantics.errors.txt index 883ce4570983b..14251121358c4 100644 --- a/tests/baselines/reference/predicateSemantics.errors.txt +++ b/tests/baselines/reference/predicateSemantics.errors.txt @@ -73,4 +73,8 @@ predicateSemantics.ts(36,8): error TS2872: This kind of expression is always tru // Should be OK console.log((cond || undefined) && 1 / cond); - \ No newline at end of file + + function foo(this: Object | undefined) { + // Should be OK + return this ?? 0; + } \ No newline at end of file diff --git a/tests/baselines/reference/predicateSemantics.js b/tests/baselines/reference/predicateSemantics.js index 4ed294189332c..eb0b66516b62c 100644 --- a/tests/baselines/reference/predicateSemantics.js +++ b/tests/baselines/reference/predicateSemantics.js @@ -40,7 +40,11 @@ while ((({}))) { } // Should be OK console.log((cond || undefined) && 1 / cond); - + +function foo(this: Object | undefined) { + // Should be OK + return this ?? 0; +} //// [predicateSemantics.js] var _a, _b, _c, _d, _e, _f; @@ -80,3 +84,7 @@ while (({})) { } while ((({}))) { } // Should be OK console.log((cond || undefined) && 1 / cond); +function foo() { + // Should be OK + return this !== null && this !== void 0 ? this : 0; +} diff --git a/tests/baselines/reference/predicateSemantics.symbols b/tests/baselines/reference/predicateSemantics.symbols index 39ce291427a74..790e965f988cc 100644 --- a/tests/baselines/reference/predicateSemantics.symbols +++ b/tests/baselines/reference/predicateSemantics.symbols @@ -70,3 +70,12 @@ console.log((cond || undefined) && 1 / cond); >undefined : Symbol(undefined) >cond : Symbol(cond, Decl(predicateSemantics.ts, 0, 11)) +function foo(this: Object | undefined) { +>foo : Symbol(foo, Decl(predicateSemantics.ts, 38, 45)) +>this : Symbol(this, Decl(predicateSemantics.ts, 40, 13)) +>Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) + + // Should be OK + return this ?? 0; +>this : Symbol(this, Decl(predicateSemantics.ts, 40, 13)) +} diff --git a/tests/baselines/reference/predicateSemantics.types b/tests/baselines/reference/predicateSemantics.types index b4f418ce33943..3d3eba6683e25 100644 --- a/tests/baselines/reference/predicateSemantics.types +++ b/tests/baselines/reference/predicateSemantics.types @@ -219,3 +219,18 @@ console.log((cond || undefined) && 1 / cond); >cond : any > : ^^^ +function foo(this: Object | undefined) { +>foo : (this: Object | undefined) => Object | 0 +> : ^ ^^ ^^^^^^^^^^^^^^^ +>this : Object +> : ^^^^^^ + + // Should be OK + return this ?? 0; +>this ?? 0 : 0 | Object +> : ^^^^^^^^^^ +>this : Object +> : ^^^^^^ +>0 : 0 +> : ^ +} diff --git a/tests/cases/compiler/predicateSemantics.ts b/tests/cases/compiler/predicateSemantics.ts index 4069c1da6eec7..d6e12b297b25b 100644 --- a/tests/cases/compiler/predicateSemantics.ts +++ b/tests/cases/compiler/predicateSemantics.ts @@ -37,3 +37,8 @@ while ((({}))) { } // Should be OK console.log((cond || undefined) && 1 / cond); + +function foo(this: Object | undefined) { + // Should be OK + return this ?? 0; +} \ No newline at end of file diff --git a/tests/cases/fourslash/completionsImportOrExportSpecifier.ts b/tests/cases/fourslash/completionsImportOrExportSpecifier.ts index 533c6f315d031..90548400ef928 100644 --- a/tests/cases/fourslash/completionsImportOrExportSpecifier.ts +++ b/tests/cases/fourslash/completionsImportOrExportSpecifier.ts @@ -4,9 +4,11 @@ //// export let foo = 1; //// let someValue = 2; //// let someType = 3; +//// type someType2 = 4; //// export { //// someValue as "__some value", //// someType as "__some type", +//// type someType2 as "__some type2", //// }; // @Filename: values.ts @@ -14,6 +16,8 @@ //// import { /*valueImport1*/ as valueImport1 } from "./exports"; //// import { foo as /*valueImport2*/ } from "./exports"; //// import { foo, /*valueImport3*/ as valueImport3 } from "./exports"; +//// import * as _a from "./exports"; +//// _a./*namespaceImport1*/; //// //// export { /*valueExport0*/ } from "./exports"; //// export { /*valueExport1*/ as valueExport1 } from "./exports"; @@ -25,6 +29,7 @@ //// import { type /*typeImport1*/ as typeImport1 } from "./exports"; //// import { type foo as /*typeImport2*/ } from "./exports"; //// import { type foo, type /*typeImport3*/ as typeImport3 } from "./exports"; +//// import * as _a from "./exports"; //// //// export { type /*typeExport0*/ } from "./exports"; //// export { type /*typeExport1*/ as typeExport1 } from "./exports"; @@ -32,27 +37,34 @@ //// export { type foo, type /*typeExport3*/ } from "./exports"; const __some_type = { name: "__some type", insertText: '"__some type"' } +const __some_type2 = { name: "__some type2", insertText: '"__some type2"' } const __some_value = { name: "__some value", insertText: '"__some value"' } const __some_type_as = { name: "__some type", insertText: '"__some type" as __some_type' } +const __some_type_squared = { name: "__some type", insertText: '["__some type"]' } +const __some_type2_as = { name: "__some type2", insertText: '"__some type2" as __some_type2' } +const __some_type2_squared = { name: "__some type2", insertText: '["__some type2"]' } const __some_value_as = { name: "__some value", insertText: '"__some value" as __some_value' } +const __some_value_squared = { name: "__some value", insertText: '["__some value"]' } const typeKeyword = { name: "type", sortText: completion.SortText.GlobalsOrKeywords } -verify.completions({ marker: "valueImport0", exact: [__some_type_as, __some_value_as, "foo", typeKeyword] }); -verify.completions({ marker: "valueImport1", exact: [__some_type_as, __some_value_as, "foo", typeKeyword] }); +verify.completions({ marker: "valueImport0", exact: [__some_type_as, __some_type2_as, __some_value_as, "foo", typeKeyword] }); +verify.completions({ marker: "valueImport1", exact: [__some_type, __some_type2, __some_value, "foo", typeKeyword] }); verify.completions({ marker: "valueImport2", exact: [] }); -verify.completions({ marker: "valueImport3", exact: [__some_type_as, __some_value_as, typeKeyword] }); +verify.completions({ marker: "valueImport3", exact: [__some_type, __some_type2, __some_value, typeKeyword] }); +// see https://github.com/microsoft/TypeScript/issues/58815 +verify.completions({ marker: 'namespaceImport1', exact: [/* __some_type_squared, __some_value_squared, */ 'foo'] }) -verify.completions({ marker: "valueExport0", exact: [__some_type, __some_value, "foo", typeKeyword] }); -verify.completions({ marker: "valueExport1", exact: [__some_type, __some_value, "foo", typeKeyword] }); +verify.completions({ marker: "valueExport0", exact: [__some_type, __some_type2, __some_value, "foo", typeKeyword] }); +verify.completions({ marker: "valueExport1", exact: [__some_type, __some_type2, __some_value, "foo", typeKeyword] }); verify.completions({ marker: "valueExport2", exact: [] }); -verify.completions({ marker: "valueExport3", exact: [__some_type, __some_value, typeKeyword] }); +verify.completions({ marker: "valueExport3", exact: [__some_type, __some_type2, __some_value, typeKeyword] }); -verify.completions({ marker: "typeImport0", exact: [__some_type_as, __some_value_as, "foo"] }); -verify.completions({ marker: "typeImport1", exact: [__some_type_as, __some_value_as, "foo"] }); +verify.completions({ marker: "typeImport0", exact: [__some_type_as, __some_type2_as, __some_value_as, "foo"] }); +verify.completions({ marker: "typeImport1", exact: [__some_type, __some_type2, __some_value, "foo"] }); verify.completions({ marker: "typeImport2", exact: [] }); -verify.completions({ marker: "typeImport3", exact: [__some_type_as, __some_value_as] }); +verify.completions({ marker: "typeImport3", exact: [__some_type, __some_type2, __some_value] }); -verify.completions({ marker: "typeExport0", exact: [] }); -verify.completions({ marker: "typeExport1", exact: [__some_type, __some_value, "foo"] }); +verify.completions({ marker: "typeExport0", exact: [__some_type, __some_type2, __some_value, "foo"] }); +verify.completions({ marker: "typeExport1", exact: [__some_type, __some_type2, __some_value, "foo"] }); verify.completions({ marker: "typeExport2", exact: [] }); -verify.completions({ marker: "typeExport3", exact: [] }); +verify.completions({ marker: "typeExport3", exact: [__some_type, __some_type2, __some_value] });