first commit

This commit is contained in:
2021-02-08 11:43:23 +08:00
parent 7871282709
commit 4d5ad8d9bc
15 changed files with 1757 additions and 0 deletions
+49
View File
@@ -0,0 +1,49 @@
import * as vscode from "vscode";
import sortImports from "import-sort";
import sortStyle from "./sort-style";
// this method is called when your extension is activated
// your extension is activated the very first time the command is executed
export function activate(context: vscode.ExtensionContext) {
const channel = vscode.window.createOutputChannel("vsc-sort-import");
const disposable = vscode.commands.registerCommand(
"vsc-sort-import.sort",
() => {
try {
const document = vscode.window.activeTextEditor?.document;
if (!document) {
return;
}
if (!/^(java|type)script(react)?$/.test(document.languageId)) {
return;
}
const res = sortImports(
document.getText(),
"import-sort-parser-typescript",
sortStyle
);
if (res.changes.length === 0) {
// don't modify document if there is no change
return;
}
vscode.window.activeTextEditor.edit((builder) => {
const all = new vscode.Range(
0,
0,
Number.MAX_SAFE_INTEGER,
Number.MAX_SAFE_INTEGER
);
builder.replace(all, res.code);
});
} catch (e) {
// if failed, print error and keep silent
channel.appendLine(e);
}
}
);
context.subscriptions.push(disposable);
}
// this method is called when your extension is deactivated
export function deactivate() {}
+105
View File
@@ -0,0 +1,105 @@
import {
IComparatorFunction,
ISorterFunction,
IStyleAPI,
IStyleItem,
} from "import-sort-style";
import { IImport } from "import-sort-parser";
export default function (styleApi: IStyleAPI): IStyleItem[] {
const {
and,
always,
dotSegmentCount,
isAbsoluteModule,
isNodeModule,
isRelativeModule,
name,
startsWithAlphanumeric,
unicode,
} = styleApi;
// comparator function which place non-alphanumeric first
const natural: IComparatorFunction = (a: string, b: string) => {
if (a === b) {
return 0;
}
const sa = startsWithAlphanumeric(a),
sb = startsWithAlphanumeric(b);
if (sa === sb) {
return unicode(a, b);
} else {
return sa ? 1 : -1;
}
};
// sort: use member primarily, if member is not avaliable, use module name
const memberOrModule: (c: IComparatorFunction) => ISorterFunction = (
comparator: IComparatorFunction
) => {
return (a: IImport, b: IImport): number => {
const aHasDefaultMember = Boolean(a.defaultMember),
aHasNamespaceMember = Boolean(a.namespaceMember),
aHasNamedMember = Boolean(a.namedMembers[0]?.name),
aHasOnlyDefaultMember =
aHasDefaultMember && !aHasNamespaceMember && !aHasNamedMember,
aHasOnlyNamespaceMember =
aHasNamespaceMember && !aHasDefaultMember && !aHasNamedMember;
const bHasDefaultMember = Boolean(b.defaultMember),
bHasNamespaceMember = Boolean(b.namespaceMember),
bHasNamedMember = Boolean(b.namedMembers[0]?.name),
bHasOnlyDefaultMember =
bHasDefaultMember && !bHasNamespaceMember && !bHasNamedMember,
bHasOnlyNamespaceMember =
bHasNamespaceMember && !bHasDefaultMember && !bHasNamedMember;
if (aHasOnlyNamespaceMember !== bHasOnlyNamespaceMember) {
return aHasOnlyNamespaceMember ? -1 : 1;
} else if (aHasOnlyDefaultMember !== bHasOnlyDefaultMember) {
return aHasOnlyDefaultMember ? -1 : 1;
} else if (aHasNamespaceMember !== bHasNamespaceMember) {
return aHasNamespaceMember ? -1 : 1;
} else if (aHasDefaultMember !== bHasDefaultMember) {
return aHasDefaultMember ? -1 : 1;
} else if (aHasNamedMember !== bHasNamedMember) {
return aHasNamedMember ? -1 : 1;
}
const first =
a.defaultMember ||
a.namespaceMember ||
a.namedMembers[0]?.name ||
a.moduleName;
const second =
b.defaultMember ||
b.namespaceMember ||
b.namedMembers[0]?.name ||
b.moduleName;
return comparator(first, second);
};
};
return [
// built-in module, has member
{
match: isNodeModule,
sort: memberOrModule(natural),
sortNamedMembers: name(natural),
},
// absolute
{
match: isAbsoluteModule,
sort: memberOrModule(natural),
sortNamedMembers: name(natural),
},
// relative
{
match: isRelativeModule,
sort: [dotSegmentCount, memberOrModule(natural)],
sortNamedMembers: name(natural),
},
// fallback
{
match: always,
sort: [dotSegmentCount, memberOrModule(natural)],
sortNamedMembers: name(natural),
},
];
}
+23
View File
@@ -0,0 +1,23 @@
import * as path from 'path';
import { runTests } from 'vscode-test';
async function main() {
try {
// The folder containing the Extension Manifest package.json
// Passed to `--extensionDevelopmentPath`
const extensionDevelopmentPath = path.resolve(__dirname, '../../');
// The path to test runner
// Passed to --extensionTestsPath
const extensionTestsPath = path.resolve(__dirname, './suite/index');
// Download VS Code, unzip it and run the integration test
await runTests({ extensionDevelopmentPath, extensionTestsPath });
} catch (err) {
console.error('Failed to run tests');
process.exit(1);
}
}
main();
+15
View File
@@ -0,0 +1,15 @@
import * as assert from 'assert';
// You can import and use all API from the 'vscode' module
// as well as import your extension to test it
import * as vscode from 'vscode';
// import * as myExtension from '../../extension';
suite('Extension Test Suite', () => {
vscode.window.showInformationMessage('Start all tests.');
test('Sample test', () => {
assert.strictEqual(-1, [1, 2, 3].indexOf(5));
assert.strictEqual(-1, [1, 2, 3].indexOf(0));
});
});
+38
View File
@@ -0,0 +1,38 @@
import * as path from 'path';
import * as Mocha from 'mocha';
import * as glob from 'glob';
export function run(): Promise<void> {
// Create the mocha test
const mocha = new Mocha({
ui: 'tdd',
color: true
});
const testsRoot = path.resolve(__dirname, '..');
return new Promise((c, e) => {
glob('**/**.test.js', { cwd: testsRoot }, (err, files) => {
if (err) {
return e(err);
}
// Add files to the test suite
files.forEach(f => mocha.addFile(path.resolve(testsRoot, f)));
try {
// Run the mocha test
mocha.run(failures => {
if (failures > 0) {
e(new Error(`${failures} tests failed.`));
} else {
c();
}
});
} catch (err) {
console.error(err);
e(err);
}
});
});
}