mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Allow allowJs and declaration to be used together (#32372)
* Allow allowJs and declaration to be used together This intorduces a new symbol-based declaration emitter - currently this is only used for JSON and JavaScript, as the output is likely worse than what the other declaration emitter is capable of. In addition, it is still incomplete - it does not yet support serializaing namespaces. * Add tests for various import/export forms, add notes on export as namespace and fix export * from * Tests & fixes for computed names * Add test with current @enum tag behavior * fix declaration emit for jsdoc @enum tags * Small adjustments to base class serialization to fix bugs in it * Guard against type/type parameter confusion when using typeParameterToName a bit * Integrate feedback from PR * Fix issue with export= declarations visibility calculation and type declaration emit that impacted all forms of declaration emit * Only make one merged getCommonJsExportEquals symbol for a symbol * Support preserving type reference directives in js declarations * Skip declare mdoifiers for namespace members in ambient contexts * FAKE ALIASES AND NAMESPACES EVERYWHERE * Dont do namespace sugar when type members contain keyword names * Fix json source file export modifier under new output * Such clean nested aliasing, very wow * Fix lint * Add visibility errors, reuse type nodes where possible * Suppoer having correctly named import types in bundled js declaration emit & adjust binding to allow namespaces with aliases to merge when the aliases look to be type-only * Better support for module.exports = class expression * Fix discovered crash bug * Allow export assigned class expressions to be reachable symbols from external declarations * Add missing semicolon * Support @enum tag post-merge * preserve comments on signatures and declarations where possible * Basic support for js classy functions * Add example we should do better with * Prototype assignments make things a bit wonky, but the example from the PR seems OK * Make a ton of changes to support the new way js classes are bound * Remove some old comments, fix import and export default names * Fix bug in object define handling and add tests for object define property declaration emit * Fix organization nits from PR comments * Preserve comments from jsdoc declarations on properties and js declaration type aliases * Merge export declarations with identical specifiers * Remove completed TODO comment * Split lint * Remove now-unused function * PR feedback * Add some project references tests, remove some checks from project refs codepaths that are now invalid * Update project references tests again * Merge and update project references tests * Rename case * Update test to include declaration output * Remove yet another project refernces redirect extension check * Update comment * Add additional import ref to test * Add shorthand prop to test * Fix comment text * Extract var to temp * Simplify function and add whitespace * Update project refs test to use incremental edit entry * Stylistic refactors in the symbol serializer * Another round of PR feedback, mostly style, small bugfix with constructors, and test showing bug in export assigned class expression name shadowing * Use x instead of index
This commit is contained in:
@@ -99,6 +99,7 @@
|
||||
"unittests/tsbuild/emptyFiles.ts",
|
||||
"unittests/tsbuild/graphOrdering.ts",
|
||||
"unittests/tsbuild/inferredTypeFromTransitiveModule.ts",
|
||||
"unittests/tsbuild/javascriptProjectEmit.ts",
|
||||
"unittests/tsbuild/lateBoundSymbol.ts",
|
||||
"unittests/tsbuild/missingExtendedFile.ts",
|
||||
"unittests/tsbuild/moduleSpecifiers.ts",
|
||||
|
||||
@@ -0,0 +1,286 @@
|
||||
namespace ts {
|
||||
describe("unittests:: tsbuild:: javascriptProjectEmit:: loads js-based projects and emits them correctly", () => {
|
||||
verifyTsc({
|
||||
scenario: "javascriptProjectEmit",
|
||||
subScenario: `loads js-based projects and emits them correctly`,
|
||||
fs: () => loadProjectFromFiles({
|
||||
"/src/common/nominal.js": utils.dedent`
|
||||
/**
|
||||
* @template T, Name
|
||||
* @typedef {T & {[Symbol.species]: Name}} Nominal
|
||||
*/
|
||||
module.exports = {};
|
||||
`,
|
||||
"/src/common/tsconfig.json": utils.dedent`
|
||||
{
|
||||
"extends": "../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"composite": true
|
||||
},
|
||||
"include": ["nominal.js"]
|
||||
}`,
|
||||
"/src/sub-project/index.js": utils.dedent`
|
||||
import { Nominal } from '../common/nominal';
|
||||
|
||||
/**
|
||||
* @typedef {Nominal<string, 'MyNominal'>} MyNominal
|
||||
*/
|
||||
`,
|
||||
"/src/sub-project/tsconfig.json": utils.dedent`
|
||||
{
|
||||
"extends": "../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"composite": true
|
||||
},
|
||||
"references": [
|
||||
{ "path": "../common" }
|
||||
],
|
||||
"include": ["./index.js"]
|
||||
}`,
|
||||
"/src/sub-project-2/index.js": utils.dedent`
|
||||
import { MyNominal } from '../sub-project/index';
|
||||
|
||||
const variable = {
|
||||
key: /** @type {MyNominal} */('value'),
|
||||
};
|
||||
|
||||
/**
|
||||
* @return {keyof typeof variable}
|
||||
*/
|
||||
export function getVar() {
|
||||
return 'key';
|
||||
}
|
||||
`,
|
||||
"/src/sub-project-2/tsconfig.json": utils.dedent`
|
||||
{
|
||||
"extends": "../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"composite": true
|
||||
},
|
||||
"references": [
|
||||
{ "path": "../sub-project" }
|
||||
],
|
||||
"include": ["./index.js"]
|
||||
}`,
|
||||
"/src/tsconfig.json": utils.dedent`
|
||||
{
|
||||
"compilerOptions": {
|
||||
"composite": true
|
||||
},
|
||||
"references": [
|
||||
{ "path": "./sub-project" },
|
||||
{ "path": "./sub-project-2" }
|
||||
],
|
||||
"include": []
|
||||
}`,
|
||||
"/src/tsconfig.base.json": utils.dedent`
|
||||
{
|
||||
"compilerOptions": {
|
||||
"skipLibCheck": true,
|
||||
"rootDir": "./",
|
||||
"outDir": "../lib",
|
||||
"allowJs": true,
|
||||
"checkJs": true,
|
||||
"declaration": true
|
||||
}
|
||||
}`,
|
||||
}, symbolLibContent),
|
||||
commandLineArgs: ["-b", "/src"]
|
||||
});
|
||||
});
|
||||
|
||||
describe("unittests:: tsbuild:: javascriptProjectEmit:: loads outfile js projects and concatenates them correctly", () => {
|
||||
let projFs: vfs.FileSystem;
|
||||
before(() => {
|
||||
projFs = loadProjectFromFiles({
|
||||
"/src/common/nominal.js": utils.dedent`
|
||||
/**
|
||||
* @template T, Name
|
||||
* @typedef {T & {[Symbol.species]: Name}} Nominal
|
||||
*/
|
||||
`,
|
||||
"/src/common/tsconfig.json": utils.dedent`
|
||||
{
|
||||
"extends": "../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"outFile": "common.js"
|
||||
},
|
||||
"include": ["nominal.js"]
|
||||
}`,
|
||||
"/src/sub-project/index.js": utils.dedent`
|
||||
/**
|
||||
* @typedef {Nominal<string, 'MyNominal'>} MyNominal
|
||||
*/
|
||||
const c = /** @type {*} */(null);
|
||||
`,
|
||||
"/src/sub-project/tsconfig.json": utils.dedent`
|
||||
{
|
||||
"extends": "../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"outFile": "sub-project.js"
|
||||
},
|
||||
"references": [
|
||||
{ "path": "../common", "prepend": true }
|
||||
],
|
||||
"include": ["./index.js"]
|
||||
}`,
|
||||
"/src/sub-project-2/index.js": utils.dedent`
|
||||
const variable = {
|
||||
key: /** @type {MyNominal} */('value'),
|
||||
};
|
||||
|
||||
/**
|
||||
* @return {keyof typeof variable}
|
||||
*/
|
||||
function getVar() {
|
||||
return 'key';
|
||||
}
|
||||
`,
|
||||
"/src/sub-project-2/tsconfig.json": utils.dedent`
|
||||
{
|
||||
"extends": "../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"outFile": "sub-project-2.js"
|
||||
},
|
||||
"references": [
|
||||
{ "path": "../sub-project", "prepend": true }
|
||||
],
|
||||
"include": ["./index.js"]
|
||||
}`,
|
||||
"/src/tsconfig.json": utils.dedent`
|
||||
{
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"outFile": "src.js"
|
||||
},
|
||||
"references": [
|
||||
{ "path": "./sub-project", "prepend": true },
|
||||
{ "path": "./sub-project-2", "prepend": true }
|
||||
],
|
||||
"include": []
|
||||
}`,
|
||||
"/src/tsconfig.base.json": utils.dedent`
|
||||
{
|
||||
"compilerOptions": {
|
||||
"skipLibCheck": true,
|
||||
"rootDir": "./",
|
||||
"allowJs": true,
|
||||
"checkJs": true,
|
||||
"declaration": true
|
||||
}
|
||||
}`,
|
||||
}, symbolLibContent);
|
||||
});
|
||||
after(() => {
|
||||
projFs = undefined!;
|
||||
});
|
||||
verifyTsc({
|
||||
scenario: "javascriptProjectEmit",
|
||||
subScenario: `loads outfile js projects and concatenates them correctly`,
|
||||
fs: () => projFs,
|
||||
commandLineArgs: ["-b", "/src"]
|
||||
});
|
||||
verifyTscIncrementalEdits({
|
||||
scenario: "javascriptProjectEmit",
|
||||
subScenario: `modifies outfile js projects and concatenates them correctly`,
|
||||
fs: () => projFs,
|
||||
commandLineArgs: ["-b", "/src"],
|
||||
incrementalScenarios: [{
|
||||
buildKind: BuildKind.IncrementalDtsUnchanged,
|
||||
modifyFs: fs => replaceText(fs, "/src/sub-project/index.js", "null", "undefined")
|
||||
}]
|
||||
});
|
||||
});
|
||||
|
||||
describe("unittests:: tsbuild:: javascriptProjectEmit:: loads js-based projects with non-moved json files and emits them correctly", () => {
|
||||
verifyTsc({
|
||||
scenario: "javascriptProjectEmit",
|
||||
subScenario: `loads js-based projects with non-moved json files and emits them correctly`,
|
||||
fs: () => loadProjectFromFiles({
|
||||
"/src/common/obj.json": utils.dedent`
|
||||
{
|
||||
"val": 42
|
||||
}`,
|
||||
"/src/common/index.ts": utils.dedent`
|
||||
import x = require("./obj.json");
|
||||
export = x;
|
||||
`,
|
||||
"/src/common/tsconfig.json": utils.dedent`
|
||||
{
|
||||
"extends": "../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"outDir": null
|
||||
"composite": true
|
||||
},
|
||||
"include": ["index.ts", "obj.json"]
|
||||
}`,
|
||||
"/src/sub-project/index.js": utils.dedent`
|
||||
import mod from '../common';
|
||||
|
||||
export const m = mod;
|
||||
`,
|
||||
"/src/sub-project/tsconfig.json": utils.dedent`
|
||||
{
|
||||
"extends": "../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"composite": true
|
||||
},
|
||||
"references": [
|
||||
{ "path": "../common" }
|
||||
],
|
||||
"include": ["./index.js"]
|
||||
}`,
|
||||
"/src/sub-project-2/index.js": utils.dedent`
|
||||
import { m } from '../sub-project/index';
|
||||
|
||||
const variable = {
|
||||
key: m,
|
||||
};
|
||||
|
||||
export function getVar() {
|
||||
return variable;
|
||||
}
|
||||
`,
|
||||
"/src/sub-project-2/tsconfig.json": utils.dedent`
|
||||
{
|
||||
"extends": "../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"composite": true
|
||||
},
|
||||
"references": [
|
||||
{ "path": "../sub-project" }
|
||||
],
|
||||
"include": ["./index.js"]
|
||||
}`,
|
||||
"/src/tsconfig.json": utils.dedent`
|
||||
{
|
||||
"compilerOptions": {
|
||||
"composite": true
|
||||
},
|
||||
"references": [
|
||||
{ "path": "./sub-project" },
|
||||
{ "path": "./sub-project-2" }
|
||||
],
|
||||
"include": []
|
||||
}`,
|
||||
"/src/tsconfig.base.json": utils.dedent`
|
||||
{
|
||||
"compilerOptions": {
|
||||
"skipLibCheck": true,
|
||||
"rootDir": "./",
|
||||
"outDir": "../out",
|
||||
"allowJs": true,
|
||||
"checkJs": true,
|
||||
"resolveJsonModule": true,
|
||||
"esModuleInterop": true,
|
||||
"declaration": true
|
||||
}
|
||||
}`,
|
||||
}, symbolLibContent),
|
||||
commandLineArgs: ["-b", "/src"]
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -52,7 +52,12 @@ namespace ts {
|
||||
|
||||
export default hello.hello`);
|
||||
const allExpectedOutputs = ["/src/dist/src/index.js", "/src/dist/src/index.d.ts", "/src/dist/src/index.json"];
|
||||
verifyProjectWithResolveJsonModuleWithFs(fs, "/src/tsconfig_withIncludeOfJson.json", allExpectedOutputs);
|
||||
verifyProjectWithResolveJsonModuleWithFs(
|
||||
fs,
|
||||
"/src/tsconfig_withIncludeOfJson.json",
|
||||
allExpectedOutputs,
|
||||
errorDiagnostic([Diagnostics.Cannot_write_file_0_because_it_would_be_overwritten_by_multiple_input_files, "/src/dist/src/index.d.ts"])
|
||||
);
|
||||
});
|
||||
|
||||
it("with resolveJsonModule and files containing json file", () => {
|
||||
|
||||
@@ -885,8 +885,8 @@ namespace ts.tscWatch {
|
||||
// More comment`;
|
||||
const configFileContentAfterComment = `
|
||||
"compilerOptions": {
|
||||
"allowJs": true,
|
||||
"declaration": true
|
||||
"inlineSourceMap": true,
|
||||
"mapRoot": "./"
|
||||
}
|
||||
}`;
|
||||
const configFileContentWithComment = configFileContentBeforeComment + configFileContentComment + configFileContentAfterComment;
|
||||
@@ -900,8 +900,9 @@ namespace ts.tscWatch {
|
||||
const host = createWatchedSystem(files);
|
||||
const watch = createWatchOfConfigFile(configFile.path, host);
|
||||
const errors = () => [
|
||||
getDiagnosticOfFile(watch().getCompilerOptions().configFile!, configFile.content.indexOf('"allowJs"'), '"allowJs"'.length, Diagnostics.Option_0_cannot_be_specified_with_option_1, "allowJs", "declaration"),
|
||||
getDiagnosticOfFile(watch().getCompilerOptions().configFile!, configFile.content.indexOf('"declaration"'), '"declaration"'.length, Diagnostics.Option_0_cannot_be_specified_with_option_1, "allowJs", "declaration")
|
||||
getDiagnosticOfFile(watch().getCompilerOptions().configFile!, configFile.content.indexOf('"inlineSourceMap"'), '"inlineSourceMap"'.length, Diagnostics.Option_0_cannot_be_specified_with_option_1, "mapRoot", "inlineSourceMap"),
|
||||
getDiagnosticOfFile(watch().getCompilerOptions().configFile!, configFile.content.indexOf('"mapRoot"'), '"mapRoot"'.length, Diagnostics.Option_0_cannot_be_specified_with_option_1, "mapRoot", "inlineSourceMap"),
|
||||
getDiagnosticOfFile(watch().getCompilerOptions().configFile!, configFile.content.indexOf('"mapRoot"'), '"mapRoot"'.length, Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1_or_option_2, "mapRoot", "sourceMap", "declarationMap")
|
||||
];
|
||||
const intialErrors = errors();
|
||||
checkOutputErrorsInitial(host, intialErrors);
|
||||
|
||||
@@ -849,8 +849,8 @@ declare module '@custom/plugin' {
|
||||
// comment`;
|
||||
const configFileContentAfterComment = `
|
||||
"compilerOptions": {
|
||||
"allowJs": true,
|
||||
"declaration": true
|
||||
"inlineSourceMap": true,
|
||||
"mapRoot": "./"
|
||||
}
|
||||
}`;
|
||||
const configFileContentWithComment = configFileContentBeforeComment + configFileContentComment + configFileContentAfterComment;
|
||||
@@ -874,7 +874,7 @@ declare module '@custom/plugin' {
|
||||
seq: 2,
|
||||
arguments: { file: configFile.path, projectFileName: projectName, includeLinePosition: true }
|
||||
}).response as readonly server.protocol.DiagnosticWithLinePosition[];
|
||||
assert.isTrue(diags.length === 2);
|
||||
assert.isTrue(diags.length === 3);
|
||||
|
||||
configFile.content = configFileContentWithoutCommentLine;
|
||||
host.reloadFS([file, configFile]);
|
||||
@@ -885,10 +885,11 @@ declare module '@custom/plugin' {
|
||||
seq: 2,
|
||||
arguments: { file: configFile.path, projectFileName: projectName, includeLinePosition: true }
|
||||
}).response as readonly server.protocol.DiagnosticWithLinePosition[];
|
||||
assert.isTrue(diagsAfterEdit.length === 2);
|
||||
assert.isTrue(diagsAfterEdit.length === 3);
|
||||
|
||||
verifyDiagnostic(diags[0], diagsAfterEdit[0]);
|
||||
verifyDiagnostic(diags[1], diagsAfterEdit[1]);
|
||||
verifyDiagnostic(diags[2], diagsAfterEdit[2]);
|
||||
|
||||
function verifyDiagnostic(beforeEditDiag: server.protocol.DiagnosticWithLinePosition, afterEditDiag: server.protocol.DiagnosticWithLinePosition) {
|
||||
assert.equal(beforeEditDiag.message, afterEditDiag.message);
|
||||
|
||||
Reference in New Issue
Block a user