Skip to content
This repository has been archived by the owner on Oct 10, 2018. It is now read-only.

fix(organize-imports): Don't remove exported elements and react called functions #413

Merged
merged 3 commits into from
Mar 5, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
"EXT_DEBUG": "true",
"LOCAL_TEST": "true",
"COVERAGE": "true",
"CHAI_JEST_SNAPSHOT_UPDATE_ALL": "true"
"CHAI_JEST_SNAPSHOT_UPDATE_ALL": ""
},
"stopOnEntry": false,
"sourceMaps": true,
Expand All @@ -75,7 +75,7 @@
"EXT_DEBUG": "true",
"LOCAL_TEST": "true",
"COVERAGE": "true",
"CHAI_JEST_SNAPSHOT_UPDATE_ALL": "true"
"CHAI_JEST_SNAPSHOT_UPDATE_ALL": ""
},
"stopOnEntry": false,
"sourceMaps": true,
Expand Down
16 changes: 8 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -87,13 +87,13 @@
]
},
"devDependencies": {
"@smartive/tslint-config": "^2.0.0",
"@smartive/tslint-config": "^2.1.0",
"@types/chai": "^4.1.2",
"@types/istanbul": "^0.4.29",
"@types/mocha": "^2.2.48",
"@types/node": "^9.4.0",
"@types/node": "^9.4.6",
"@types/reflect-metadata": "0.1.0",
"@types/sinon": "^4.1.3",
"@types/sinon": "^4.3.0",
"@types/sinon-chai": "^2.7.29",
"chai": "^4.1.2",
"chai-jest-snapshot": "^2.0.0",
Expand All @@ -103,19 +103,19 @@
"remap-istanbul": "^0.10.1",
"semantic-release": "^12.4.1",
"semantic-release-vsce": "^2.0.0",
"sinon": "^4.2.2",
"sinon": "^4.4.2",
"sinon-chai": "^2.14.0",
"tslint": "^5.9.1",
"tsutils": "^2.21.0",
"tsutils": "^2.22.2",
"vscode": "^1.1.10"
},
"dependencies": {
"fs-extra": "^5.0.0",
"inversify": "^4.10.0",
"inversify": "^4.11.1",
"reflect-metadata": "^0.1.12",
"tslib": "^1.9.0",
"typescript": "~2.7.1",
"typescript-parser": "^2.2.2",
"typescript": "~2.7.2",
"typescript-parser": "^2.3.0",
"winston": "^3.0.0-rc1"
},
"activationEvents": [
Expand Down
4 changes: 3 additions & 1 deletion src/configuration/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { inject, injectable } from 'inversify';
import { TypescriptGenerationOptions } from 'typescript-parser';
import { MultiLineImportRule, TypescriptGenerationOptions } from 'typescript-parser';
import { Event, EventEmitter, ExtensionContext, Uri, window, workspace } from 'vscode';

import iocSymbols from '../ioc-symbols';
Expand Down Expand Up @@ -50,13 +50,15 @@ export default class Configuration {
public typescriptGeneratorOptions(resource: Uri): TypescriptGenerationOptions {
return {
eol: this.imports.insertSemicolons(resource) ? ';' : '',
insertSpaces: true,
multiLineTrailingComma: this.imports.multiLineTrailingComma(resource),
multiLineWrapThreshold: this.imports.multiLineWrapThreshold(resource),
spaceBraces: this.imports.insertSpaceBeforeAndAfterImportBraces(resource),
stringQuoteStyle: this.imports.stringQuoteStyle(resource),
tabSize: window.activeTextEditor && window.activeTextEditor.options.tabSize ?
(window.activeTextEditor.options.tabSize as any) * 1 :
workspace.getConfiguration('editor', resource).get('tabSize', 4),
wrapMethod: MultiLineImportRule.oneImportPerLineOnlyAfterThreshold,
};
}
}
5 changes: 4 additions & 1 deletion src/imports/import-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,10 @@ export default class ImportManager {
const defaultSpec = actImport.defaultAlias;
const libraryAlreadyImported = keep.find(d => d.libraryName === actImport.libraryName);
if (actImport.specifiers.length ||
(!!defaultSpec && this._parsedDocument.nonLocalUsages.indexOf(defaultSpec) >= 0)) {
(!!defaultSpec && [
...this._parsedDocument.nonLocalUsages,
...this._parsedDocument.usages,
].indexOf(defaultSpec) >= 0)) {
if (libraryAlreadyImported) {
if (actImport.defaultAlias) {
(<NamedImport>libraryAlreadyImported).defaultAlias = actImport.defaultAlias;
Expand Down
2 changes: 1 addition & 1 deletion src/imports/import-organizer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ export class ImportOrganizer implements Activatable {
* @private
* @returns {Promise<boolean>}
*
* @memberof ImportResolveExtension
* @memberof ImportOrganizer
*/
private async organizeImports(): Promise<void> {
if (!window.activeTextEditor) {
Expand Down
Empty file.
Empty file.
74 changes: 74 additions & 0 deletions test/tests/imports/__snapshots__/import-organizer.test.ts.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`ImportOrganizer import-organizer-file.ts should not remove default exported default imports 1`] = `
"import Barbaz from './foo';

export default Barbaz;
"
`;

exports[`ImportOrganizer import-organizer-file.ts should not remove default exported default imports 2`] = `
"import Barbaz from './foo';

export default Barbaz;
"
`;

exports[`ImportOrganizer import-organizer-file.ts should not remove directly exported default imports 1`] = `
"import Barbaz from './foo';

export { Barbaz }
"
`;

exports[`ImportOrganizer import-organizer-file.ts should not remove directly exported default imports 2`] = `
"import Barbaz from './foo';

export { Barbaz }
"
`;

exports[`ImportOrganizer import-organizer-file.ts should not remove directly exported imports 1`] = `
"import * as Foobar from './lol';
import * as Barbaz from './foo';

export { Foobar, Barbaz }
"
`;

exports[`ImportOrganizer import-organizer-file.ts should not remove directly exported imports 2`] = `
"import * as Barbaz from './foo';
import * as Foobar from './lol';

export { Foobar, Barbaz }
"
`;

exports[`ImportOrganizer import-organizer-file.tsx should not remove function that is used in tsx 1`] = `
"import { f } from './somewhere';
import * as React from 'react';

export class Comp extends React.Component {
render() {
return (
<div>{f()}</div>
);
}
}
"
`;

exports[`ImportOrganizer import-organizer-file.tsx should not remove function that is used in tsx 2`] = `
"import * as React from 'react';

import { f } from './somewhere';

export class Comp extends React.Component {
render() {
return (
<div>{f()}</div>
);
}
}
"
`;
143 changes: 143 additions & 0 deletions test/tests/imports/import-organizer.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
import { join } from 'path';
import { Position, Range, TextDocument, Uri, window, workspace } from 'vscode';

import { ImportOrganizer } from '../../../src/imports';
import ioc from '../../../src/ioc';
import iocSymbols from '../../../src/ioc-symbols';
import { expect } from '../setup';

describe('ImportOrganizer', () => {

describe('import-organizer-file.ts', () => {

const rootPath = workspace.workspaceFolders![0].uri.fsPath;
const file = Uri.file(join(rootPath, 'imports', 'import-organizer-file.ts'));
let document: TextDocument;
let extension: any;

before(async () => {
document = await workspace.openTextDocument(file);
await window.showTextDocument(document);

extension = new ImportOrganizer(
ioc.get(iocSymbols.extensionContext),
ioc.get(iocSymbols.logger),
ioc.get(iocSymbols.configuration),
ioc.get(iocSymbols.importManager),
);
});

afterEach(async () => {
await window.activeTextEditor!.edit((builder) => {
builder.delete(new Range(
new Position(0, 0),
document.lineAt(document.lineCount - 1).rangeIncludingLineBreak.end,
));
});
});

it('should not remove directly exported imports', async () => {
await window.activeTextEditor!.edit((builder) => {
builder.insert(
new Position(0, 0),
`import * as Foobar from './lol';
import * as Barbaz from './foo';

export { Foobar, Barbaz }
`,
);
});

expect(window.activeTextEditor!.document.getText()).to.matchSnapshot();
await extension.organizeImports();
expect(window.activeTextEditor!.document.getText()).to.matchSnapshot();
});

it('should not remove directly exported default imports', async () => {
await window.activeTextEditor!.edit((builder) => {
builder.insert(
new Position(0, 0),
`import Barbaz from './foo';

export { Barbaz }
`,
);
});

expect(window.activeTextEditor!.document.getText()).to.matchSnapshot();
await extension.organizeImports();
expect(window.activeTextEditor!.document.getText()).to.matchSnapshot();
});

it('should not remove default exported default imports', async () => {
await window.activeTextEditor!.edit((builder) => {
builder.insert(
new Position(0, 0),
`import Barbaz from './foo';

export default Barbaz;
`,
);
});

expect(window.activeTextEditor!.document.getText()).to.matchSnapshot();
await extension.organizeImports();
expect(window.activeTextEditor!.document.getText()).to.matchSnapshot();
});

});

describe('import-organizer-file.tsx', () => {

const rootPath = workspace.workspaceFolders![0].uri.fsPath;
const file = Uri.file(join(rootPath, 'imports', 'import-organizer-file.tsx'));
let document: TextDocument;
let extension: any;

before(async () => {
document = await workspace.openTextDocument(file);
await window.showTextDocument(document);

extension = new ImportOrganizer(
ioc.get(iocSymbols.extensionContext),
ioc.get(iocSymbols.logger),
ioc.get(iocSymbols.configuration),
ioc.get(iocSymbols.importManager),
);
});

afterEach(async () => {
await window.activeTextEditor!.edit((builder) => {
builder.delete(new Range(
new Position(0, 0),
document.lineAt(document.lineCount - 1).rangeIncludingLineBreak.end,
));
});
});

it('should not remove function that is used in tsx', async () => {
await window.activeTextEditor!.edit((builder) => {
builder.insert(
new Position(0, 0),
`import { f } from './somewhere';
import * as React from 'react';

export class Comp extends React.Component {
render() {
return (
<div>{f()}</div>
);
}
}
`,
);
});

expect(window.activeTextEditor!.document.getText()).to.matchSnapshot();
await extension.organizeImports();
expect(window.activeTextEditor!.document.getText()).to.matchSnapshot();
});

});

});
Loading