diff --git a/src/properties-minifier.ts b/src/properties-minifier.ts index 57f59aa..fbbf1fa 100644 --- a/src/properties-minifier.ts +++ b/src/properties-minifier.ts @@ -201,7 +201,7 @@ function isPrivateNonStaticClassMember(symbol: ts.Symbol | undefined): boolean { return symbol.declarations.some((x: ts.Declaration) => { // terser / uglify property minifiers aren't able to handle decorators - return (isClassMember(x) && !hasDecorators(x) || isConstructorParameter(x)) && isPrivateNonStatic(x); + return (isClassMember(x) && !hasDecorators(x) || isConstructorParameter(x)) && isPrivateNonStatic(x) && !hasModifier(x, ts.SyntaxKind.DeclareKeyword); }); } diff --git a/tests/functional-test-cases.ts b/tests/functional-test-cases.ts index 7a6db9e..937fe00 100644 --- a/tests/functional-test-cases.ts +++ b/tests/functional-test-cases.ts @@ -73,6 +73,44 @@ function checkDiagnosticsErrors(diagnostics: ReadonlyArray): void assert.strictEqual(diagnostics.length, 0, ts.formatDiagnostics(diagnostics, formatDiagnosticsHost).trim()); } +const enum Constants { + NoInputsWereFoundDiagnosticCode = 18003, +} + +const parseConfigHost: ts.ParseConfigHost = { + useCaseSensitiveFileNames: ts.sys.useCaseSensitiveFileNames, + readDirectory: ts.sys.readDirectory, + fileExists: ts.sys.fileExists, + readFile: ts.sys.readFile, +}; + +function getCompilerOptions(configFileName: string): ts.CompilerOptions | null { + if (!fs.existsSync(configFileName)) { + return null; + } + + const configParseResult = ts.readConfigFile(configFileName, ts.sys.readFile); + + checkDiagnosticsErrors(configParseResult.error !== undefined ? [configParseResult.error] : []); + + const compilerOptionsParseResult = ts.parseJsonConfigFileContent( + configParseResult.config, + parseConfigHost, + path.resolve(path.dirname(configFileName)), + undefined, + configFileName + ); + + // we don't want to raise an error if no inputs found in a config file + // because this error is mostly for CLI, but we'll pass an inputs in createProgram + const diagnostics = compilerOptionsParseResult.errors + .filter((d: ts.Diagnostic) => d.code !== Constants.NoInputsWereFoundDiagnosticCode); + + checkDiagnosticsErrors(diagnostics); + + return compilerOptionsParseResult.options; +} + describe('Functional tests', () => { for (const testCase of getTestCases()) { it(testCase.name, () => { @@ -80,7 +118,7 @@ describe('Functional tests', () => { rootNames: [testCase.inputFileName], options: { target: ts.ScriptTarget.ES5, - experimentalDecorators: true, + ...getCompilerOptions(path.join(testCase.inputFileName, '..', 'tsconfig.json')), }, }); diff --git a/tests/test-cases/useDefineForClassFields-and-declare/input.ts b/tests/test-cases/useDefineForClassFields-and-declare/input.ts new file mode 100644 index 0000000..47c4f37 --- /dev/null +++ b/tests/test-cases/useDefineForClassFields-and-declare/input.ts @@ -0,0 +1,9 @@ +class Class { + public declare publicField: number; + protected declare protectedField: number; + private declare privateField: number; + + public method() { + console.log(this.publicField, this.protectedField, this.privateField); + } +} diff --git a/tests/test-cases/useDefineForClassFields-and-declare/output.js b/tests/test-cases/useDefineForClassFields-and-declare/output.js new file mode 100644 index 0000000..4a34ac0 --- /dev/null +++ b/tests/test-cases/useDefineForClassFields-and-declare/output.js @@ -0,0 +1,13 @@ +var Class = /** @class */ (function () { + function Class() { + } + Object.defineProperty(Class.prototype, "method", { + enumerable: false, + configurable: true, + writable: true, + value: function () { + console.log(this.publicField, this.protectedField, this.privateField); + } + }); + return Class; +}()); diff --git a/tests/test-cases/useDefineForClassFields-and-declare/tsconfig.json b/tests/test-cases/useDefineForClassFields-and-declare/tsconfig.json new file mode 100644 index 0000000..bb04b29 --- /dev/null +++ b/tests/test-cases/useDefineForClassFields-and-declare/tsconfig.json @@ -0,0 +1,6 @@ +{ + "compilerOptions": { + "target": "es5", + "useDefineForClassFields": true + } +}