Skip to content
Permalink
Browse files

fix(parse): Removed duplicated entries

fix #2
  • Loading branch information...
iamthes committed Nov 21, 2017
1 parent 968c9f8 commit 88116691e1047c6081cfbecd84f2cafb33d35e2d
Showing with 68 additions and 33 deletions.
  1. +2 −2 package.json
  2. +1 −2 src/directory.ts
  3. +13 −0 src/entry.spec.ts
  4. +12 −5 src/entry.ts
  5. +9 −11 src/parse.spec.ts
  6. +31 −13 src/parse.ts
@@ -23,8 +23,8 @@
"lint:w": "concurrently -- \"npm run -s tsclint:w\" \"npm run -s eslint:w\"",
"build": "tsc",
"clean": "rimraf lib",
"prerelease": "npm run clean",
"release": "standard-version",
"prebuild": "npm run clean",
"release": "npm run test && standard-version",
"release:undo": "git reset --hard HEAD~ -- && node -p \"let {execSync: x} = require('child_process'); `${x(`git tag -d ${x(`git for-each-ref refs/tags --sort=-taggerdate --format=%(refname:short) --count=1`)}`)}`\"",
"prepublishOnly": "npm run build",
"setup": "npm i -g commitizen standard-version && commitizen init cz-conventional-changelog --save-dev",
@@ -1,7 +1,7 @@
import { readdir, stat } from 'fs';
import { Entry } from './entry';
import { file as parse } from './file';
import { extname, resolve as resolvePath, parse as parsePath } from 'path';
import { resolve as resolvePath, parse as parsePath } from 'path';
import { fileExtensions } from './file-extensions';

const objectValues = require('object-values');
@@ -26,7 +26,6 @@ export function directory(path: string, options: DirectoryOptions = {}): Promise
});
}).then((items: string[]) => {
const directories: string[] = [];
const files: string[] = [];
let count = items.length;
if (count === 0) {
return Promise.resolve([]);
@@ -0,0 +1,13 @@
import { equal, deepEqual } from 'assert';
import { Entry } from './entry';

it('id function', () => {
const entry = new Entry({ name: 'abc', module: 'mod' });
equal(entry.id(), 'abc/mod');
});

it('serialization should not contain private properties', () => {
const entry = new Entry({ name: 'abc', module: 'mod' });
const unserialized = JSON.parse(JSON.stringify(entry));
deepEqual(Object.keys(unserialized), ['name', 'isDefault', 'module']);
});
@@ -9,6 +9,9 @@ type EntryConstructor = {
};

export class Entry {

private static count = 1;

/**
* Export name.
*/
@@ -29,8 +32,8 @@ export class Entry {
* Flag indicates export default.
*/
isDefault: boolean;
cjs: boolean;
ts: boolean;
cjs?: boolean;
ts?: boolean;

constructor({ name, filepath, specifier, module, isDefault, cjs, ts }: EntryConstructor) {
this.name = name;
@@ -42,7 +45,11 @@ export class Entry {
this.ts = ts;
}

// hash() {
// return `${this.name}/${this.module ? this.module : this.filepath}`;
// }
private get counter() {
return Entry.count++;
}

id() {
return `${this.name || this.counter}${this.isDefault ? '*' : '' }/${this.module ? this.module : this.filepath}`;
}
}
@@ -136,14 +136,12 @@ it('not too deep parse', async () => {
assert.equal(result[0].name, 'deep');
});

// it('duplicates must be removed', async () => {
// const source = `declare module "child_process" {
// export function spawnSync(command: string): SpawnSyncReturns<Buffer>;
// export function spawnSync(command: string, options?: SpawnSyncOptionsWithStringEncoding): SpawnSyncReturns<string>;
// }`;
// debugger
// const result = await parse(source);
// assert.equal(result.length, 1);
// assert.equal(result[0].name, 'spawnSync');
// assert.equal(result[0].module, 'child_process');
// });
it('duplicates must be removed', async () => {
const source = `
export function spawnSync(command: string): SpawnSyncReturns<Buffer>;
export function spawnSync(command: string, options?: SpawnSyncOptionsWithStringEncoding): SpawnSyncReturns<string>;
`;
const result = await parse(source);
assert.equal(result.length, 1);
assert.equal(result[0].name, 'spawnSync');
});
@@ -12,11 +12,25 @@ function hasDefaultKeyword(node?: ts.Node) {
return Boolean(node && node.modifiers && node.modifiers.find(m => m.kind === ts.SyntaxKind.DefaultKeyword));
}

class EntrySet {

readonly result: Entry[] = [];
private set = new Set<string>();

push(entry: Entry) {
const id = entry.id();
if (!this.set.has(id)) {
this.set.add(id);
this.result.push(entry);
}
}
}

export function parse(sourceText: string, options: ParseOptions = {}): Entry[] {
const sourceFile = ts.createSourceFile('dummy.ts', sourceText, ts.ScriptTarget.ES2015, true);
let { module, filepath } = options;
let moduleEnd: number;
let result: Entry[] = [];
const entrySet = new EntrySet();
walk(sourceFile);
function walk(statement: ts.Node) {
const node = statement;
@@ -44,41 +58,45 @@ export function parse(sourceText: string, options: ParseOptions = {}): Entry[] {
const specifier: string = get('moduleSpecifier.text', node);
const isDefault = hasDefaultKeyword(node);
names.forEach(name => {
result.push(new Entry({ name, module, filepath, specifier, isDefault }));
const entry = new Entry({ name, module, filepath, specifier, isDefault });
entrySet.push(entry);
});
} break;
case ts.SyntaxKind.ExportKeyword: {
const declarations = get('declarationList.declarations', node.parent) || [];
declarations.forEach(d => {
const name: string = get('name.text', d);
const name: string = d && d.name && d.name.text;
if (name) {
result.push(new Entry({ name, module, filepath }));
const entry = new Entry({ name, module, filepath });
entrySet.push(entry);
}
const names = get('name.elements', d) || [];
names.forEach(d => {
const name: string = get('name.text', d);
result.push(new Entry({ name, module, filepath }));
const name: string = d && d.name && d.name.text;
const entry = new Entry({ name, module, filepath });
entrySet.push(entry);
});
});
const name: string = get('name.text', node.parent);
if (name) {
const isDefault = hasDefaultKeyword(node.parent);
result.push(new Entry({ name, module, filepath, isDefault }));
const entry = new Entry({ name, module, filepath, isDefault });
entrySet.push(entry);
}
} break;
case ts.SyntaxKind.ExportAssignment: {
result.push(new Entry({ module, cjs: true, ts: true }));
entrySet.result.push(new Entry({ module, cjs: true, ts: true }));
} break;
}
if (node.kind === ts.SyntaxKind.SourceFile
|| node.kind === ts.SyntaxKind.ModuleDeclaration
|| get('parent.kind', node) === ts.SyntaxKind.SourceFile
|| get('parent.kind', node) === ts.SyntaxKind.ModuleDeclaration
|| get('parent.parent.kind', node) === ts.SyntaxKind.SourceFile
|| get('parent.parent.kind', node) === ts.SyntaxKind.ModuleDeclaration
|| (node.parent && node.parent.kind === ts.SyntaxKind.SourceFile)
|| (node.parent && node.parent.kind === ts.SyntaxKind.ModuleDeclaration)
|| (node.parent && node.parent.parent && node.parent.parent.kind === ts.SyntaxKind.SourceFile)
|| (node.parent && node.parent.parent && node.parent.parent.kind === ts.SyntaxKind.ModuleDeclaration)
) {
ts.forEachChild(node, walk);
}
}
return result;
return entrySet.result;
}

0 comments on commit 8811669

Please sign in to comment.
You can’t perform that action at this time.