Skip to content

Commit 57a14a5

Browse files
authored
Merge pull request #53 from buehler/develop
Release
2 parents ec573e6 + 7d35a16 commit 57a14a5

24 files changed

+556
-152
lines changed

.appveyor.yml

+6-2
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,21 @@ version: "{build} - {branch}"
22
skip_tags: true
33
skip_branch_with_pr: true
44

5+
matrix:
6+
fast_finish: true
7+
58
environment:
69
matrix:
10+
- nodejs_version: "9"
711
- nodejs_version: "8"
8-
- nodejs_version: "7"
9-
- nodejs_version: "6"
1012

1113
install:
1214
- ps: Install-Product node $env:nodejs_version
1315
- npm install
1416

1517
test_script:
1618
- npm test
19+
- npm install -g codecov
20+
- codecov
1721

1822
build: off

.travis.yml

+32-23
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,38 @@
1-
sudo: false
21
language: node_js
32

4-
cache:
5-
directories:
6-
- node_modules
3+
stages:
4+
- name: test
5+
if: tag IS blank
6+
- name: deploy
7+
if: branch = master AND type != pull_request
8+
9+
matrix:
10+
fast_finish: true
711

812
notifications:
913
email: false
1014

11-
node_js:
12-
- '8'
13-
- '7'
14-
- '6'
15-
16-
before_script:
17-
- npm prune
18-
19-
after_success:
20-
- npm install coveralls@^2.11.9 && cat ./coverage/lcov.info | coveralls
21-
22-
after_script:
23-
- npm install
24-
- npm run build
25-
- npm run semantic-release
26-
27-
branches:
28-
except:
29-
- /^v\d+\.\d+\.\d+$/
15+
jobs:
16+
include:
17+
- stage: test
18+
node_js: '9'
19+
after_success:
20+
- npm i -g codecov
21+
- codecov
22+
- stage: test
23+
node_js: '8'
24+
after_success:
25+
- npm i -g codecov
26+
- codecov
27+
- stage: deploy
28+
node_js: '9'
29+
script: npm run typedoc
30+
deploy:
31+
provider: pages
32+
skip_cleanup: true
33+
github_token: $GH_TOKEN
34+
local_dir: ./docs
35+
- stage: deploy
36+
node_js: '9'
37+
before_script: npm run build
38+
script: npm run semantic-release

README.md

+5-4
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,10 @@ a more or less human readable AST out of .js or .ts files.
66
[![Build Status](https://travis-ci.org/buehler/node-typescript-parser.svg)](https://travis-ci.org/buehler/node-typescript-parser)
77
[![Build Status Windows](https://ci.appveyor.com/api/projects/status/j06bqjc4tkdt7sej?svg=true)](https://ci.appveyor.com/project/buehler/node-typescript-parser)
88
[![npm](https://img.shields.io/npm/v/typescript-parser.svg?maxAge=3600)](https://www.npmjs.com/package/typescript-parser)
9-
[![Coverage status](https://img.shields.io/coveralls/buehler/node-typescript-parser.svg?maxAge=3600)](https://coveralls.io/github/buehler/node-typescript-parser)
9+
[![codecov](https://codecov.io/gh/buehler/node-typescript-parser/branch/master/graph/badge.svg)](https://codecov.io/gh/buehler/node-typescript-parser)
1010
[![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release)
1111
[![Greenkeeper badge](https://badges.greenkeeper.io/buehler/node-typescript-parser.svg)](https://greenkeeper.io/)
12+
[![Gitter](https://img.shields.io/gitter/room/node-typescript-parser/Lobby.svg)](https://gitter.im/node-typescript-parser/Lobby)
1213

1314
## How to use
1415

@@ -25,7 +26,7 @@ const parser = new TypescriptParser();
2526
const parsed = await parser.parseSource(/* typescript source code as string */);
2627

2728
// or a filepath
28-
const parsed = await parser.parseSource('/user/myfile.ts', 'workspace root');
29+
const parsed = await parser.parseFile('/user/myfile.ts', 'workspace root');
2930
```
3031

3132
You can also parse multiple files at ones.
@@ -37,10 +38,10 @@ After the parsing is done, you'll get an index with resolved
3738
exports and declarations.
3839

3940
Keep in mind, that the index'll only contain exported declarations.
40-
41+
4142
## Changelog
4243

43-
The changelog is generated by [semantic release](https://github.com/semantic-release/semantic-release) and is located under the
44+
The changelog is generated by [semantic release](https://github.com/semantic-release/semantic-release) and is located under the
4445
[release section](https://github.com/buehler/node-typescript-parser/releases).
4546

4647
## Licence

jest.json

-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
{
22
"collectCoverage": true,
3-
"mapCoverage": true,
43
"transform": {
54
"^.+\\.tsx?$": "<rootDir>/node_modules/ts-jest/preprocessor.js"
65
},

package.json

+15-13
Original file line numberDiff line numberDiff line change
@@ -31,22 +31,24 @@
3131
},
3232
"homepage": "https://github.com/TypeScript-Heroes/node-typescript-parser#readme",
3333
"devDependencies": {
34-
"@types/jest": "^21.1.0",
34+
"@smartive/tslint-config": "^2.0.0",
35+
"@types/jest": "^22.1.4",
36+
"@types/lodash-es": "^4.17.0",
3537
"@types/mock-fs": "^3.6.30",
36-
"@types/node": "^8.0.31",
38+
"@types/node": "^9.4.6",
3739
"del-cli": "^1.1.0",
38-
"jest": "^21.2.0",
39-
"mock-fs": "^4.4.1",
40-
"semantic-release": "^9.0.0",
41-
"ts-jest": "^21.0.0",
42-
"tslint": "^5.5.0",
43-
"tslint-config-airbnb": "^5.2.1",
44-
"tsutils": "^2.9.0",
45-
"typedoc": "^0.8.0"
40+
"jest": "^22.4.2",
41+
"mock-fs": "^4.4.2",
42+
"semantic-release": "^15.0.0",
43+
"ts-jest": "^22.4.0",
44+
"tslint": "^5.9.1",
45+
"tsutils": "^2.22.0",
46+
"typedoc": "^0.10.0"
4647
},
4748
"dependencies": {
48-
"lodash": "^4.17.4",
49-
"tslib": "^1.7.1",
50-
"typescript": "^2.5.3"
49+
"lodash": "^4.17.5",
50+
"lodash-es": "^4.17.5",
51+
"tslib": "^1.9.0",
52+
"typescript": "^2.7.2"
5153
}
5254
}

src/TypescriptParser.ts

+23-15
Original file line numberDiff line numberDiff line change
@@ -151,46 +151,54 @@ export class TypescriptParser {
151151
*
152152
* @memberof TsResourceParser
153153
*/
154-
private parse(resource: Resource, node: Node): void {
155-
for (const child of node.getChildren()) {
156-
switch (child.kind) {
154+
private parse(rootResource: Resource, rootNode: Node): void {
155+
let [resource, ...resourceQueue]: Resource[] = Array(rootNode.getChildren().length).fill(rootResource);
156+
let [node, ...nodeQueue]: Node[] = [...rootNode.getChildren()];
157+
while (node) {
158+
switch (node.kind) {
157159
case SyntaxKind.ImportDeclaration:
158160
case SyntaxKind.ImportEqualsDeclaration:
159-
parseImport(resource, <ImportDeclaration | ImportEqualsDeclaration>child);
161+
parseImport(resource, <ImportDeclaration | ImportEqualsDeclaration>node);
160162
break;
161163
case SyntaxKind.ExportDeclaration:
162164
case SyntaxKind.ExportAssignment:
163-
parseExport(resource, <ExportAssignment | ExportDeclaration>child);
165+
parseExport(resource, <ExportAssignment | ExportDeclaration>node);
164166
break;
165167
case SyntaxKind.EnumDeclaration:
166-
parseEnum(resource, <EnumDeclaration>child);
168+
parseEnum(resource, <EnumDeclaration>node);
167169
break;
168170
case SyntaxKind.TypeAliasDeclaration:
169-
parseTypeAlias(resource, <TypeAliasDeclaration>child);
171+
parseTypeAlias(resource, <TypeAliasDeclaration>node);
170172
break;
171173
case SyntaxKind.FunctionDeclaration:
172-
parseFunction(resource, <FunctionDeclaration>child);
174+
parseFunction(resource, <FunctionDeclaration>node);
175+
[resource, ...resourceQueue] = resourceQueue;
176+
[node, ...nodeQueue] = nodeQueue;
173177
continue;
174178
case SyntaxKind.VariableStatement:
175-
parseVariable(resource, <VariableStatement>child);
179+
parseVariable(resource, <VariableStatement>node);
176180
break;
177181
case SyntaxKind.InterfaceDeclaration:
178-
parseInterface(resource, <InterfaceDeclaration>child);
182+
parseInterface(resource, <InterfaceDeclaration>node);
179183
break;
180184
case SyntaxKind.ClassDeclaration:
181-
parseClass(resource, <ClassDeclaration>child);
185+
parseClass(resource, <ClassDeclaration>node);
186+
[resource, ...resourceQueue] = resourceQueue;
187+
[node, ...nodeQueue] = nodeQueue;
182188
continue;
183189
case SyntaxKind.Identifier:
184-
parseIdentifier(resource, <Identifier>child);
190+
parseIdentifier(resource, <Identifier>node);
185191
break;
186192
case SyntaxKind.ModuleDeclaration:
187-
const newResource = parseModule(resource, <ModuleDeclaration>child);
188-
this.parse(newResource, child);
193+
const newResource = parseModule(resource, <ModuleDeclaration>node);
194+
[resource, ...resourceQueue] = [...Array(node.getChildren().length).fill(newResource), ...resourceQueue];
195+
[node, ...nodeQueue] = [...node.getChildren(), ...nodeQueue];
189196
continue;
190197
default:
191198
break;
192199
}
193-
this.parse(resource, child);
200+
[resource, ...resourceQueue] = [...Array(node.getChildren().length).fill(resource), ...resourceQueue];
201+
[node, ...nodeQueue] = [...node.getChildren(), ...nodeQueue];
194202
}
195203
}
196204
}

src/code-generators/TypescriptGenerationOptions.ts

+22
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
export enum MultiLineImportRule {
2+
strictlyOneImportPerLine = 'strictlyOneImportPerLine',
3+
oneImportPerLineOnlyAfterThreshold = 'oneImportPerLineOnlyAfterThreshold',
4+
multipleImportsPerLine = 'multipleImportsPerLine',
5+
}
6+
17
/**
28
* Typescript generation options type. Contains all information needed to stringify some objects to typescript.
39
*
@@ -29,6 +35,14 @@ export interface TypescriptGenerationOptions {
2935
*/
3036
spaceBraces: boolean;
3137

38+
/**
39+
* The wrapping methodology to be used for imports.
40+
*
41+
* @type {MultiLineImportRule}
42+
* @memberof TypescriptGenerationOptions
43+
*/
44+
wrapMethod: MultiLineImportRule;
45+
3246
/**
3347
* The threshold where an import is written as multiline.
3448
*
@@ -52,4 +66,12 @@ export interface TypescriptGenerationOptions {
5266
* @memberof TypescriptGenerationOptions
5367
*/
5468
tabSize: number;
69+
70+
/**
71+
* Insert spaces instead of tabs (default: true)
72+
*
73+
* @type {boolean}
74+
* @memberof TypescriptGenerationOptions
75+
*/
76+
insertSpaces: boolean;
5577
}

src/code-generators/typescript-generators/namedImport.ts

+54-23
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
11
import { NamedImport } from '../../imports/NamedImport';
22
import { SymbolSpecifier } from '../../SymbolSpecifier';
33
import { stringTemplate } from '../../utilities/StringTemplate';
4-
import { TypescriptGenerationOptions } from '../TypescriptGenerationOptions';
4+
import { MultiLineImportRule, TypescriptGenerationOptions } from '../TypescriptGenerationOptions';
55
import { generateSymbolSpecifier } from './symbolSpecifier';
66

7-
const importTemplate = stringTemplate`import ${0} from ${1}`;
7+
const oneLinerImportTemplate = stringTemplate`import ${0} from ${1}`;
88

9-
const multiLineImport = stringTemplate`import ${3}{
9+
const multiLineImportTemplate = stringTemplate`import ${3}{
1010
${0}${1}
1111
} from ${2}`;
1212

13+
const defaultAliasOnlyMultiLineImportTemplate = stringTemplate`import ${0}
14+
from ${1}`;
15+
1316
/**
1417
* Sort function for symbol specifiers. Does sort after the specifiers name (to lowercase).
1518
*
@@ -23,7 +26,8 @@ function specifierSort(i1: SymbolSpecifier, i2: SymbolSpecifier): number {
2326

2427
if (strA < strB) {
2528
return -1;
26-
} else if (strA > strB) {
29+
}
30+
if (strA > strB) {
2731
return 1;
2832
}
2933
return 0;
@@ -44,34 +48,61 @@ export function generateNamedImport(
4448
stringQuoteStyle,
4549
spaceBraces,
4650
tabSize,
51+
wrapMethod,
4752
multiLineWrapThreshold,
4853
multiLineTrailingComma,
54+
insertSpaces = true,
4955
}: TypescriptGenerationOptions,
5056
): string {
51-
const space = spaceBraces ? ' ' : '';
5257
const lib = `${stringQuoteStyle}${imp.libraryName}${stringQuoteStyle}${eol}`;
53-
54-
const specifiers = imp.specifiers.sort(specifierSort).map(o => generateSymbolSpecifier(o)).join(', ');
55-
let importSpecifiers = `${space}${specifiers}${space}`;
56-
if (importSpecifiers.trim().length === 0) {
57-
importSpecifiers = ' ';
58+
// const specifiers = imp.specifiers.sort(specifierSort).map(o => generateSymbolSpecifier(o)).join(', ');
59+
const oneLinerImportStatement = oneLinerImportTemplate(getImportSpecifiers(imp, spaceBraces), lib);
60+
if (oneLinerImportStatement.length <= multiLineWrapThreshold &&
61+
(wrapMethod !== MultiLineImportRule.strictlyOneImportPerLine ||
62+
imp.specifiers.length <= 1)) {
63+
return oneLinerImportStatement;
5864
}
59-
60-
const importString = importTemplate(
61-
getImportSpecifiers(imp, spaceBraces),
62-
lib,
63-
);
64-
65-
if (importString.length > multiLineWrapThreshold) {
66-
const spacings = Array(tabSize + 1).join(' ');
67-
return multiLineImport(
68-
imp.specifiers.sort(specifierSort).map(o => `${spacings}${generateSymbolSpecifier(o)}`).join(',\n'),
69-
multiLineTrailingComma ? ',' : '',
70-
`${stringQuoteStyle}${imp.libraryName}${stringQuoteStyle}${eol}`,
65+
const defaultAliasOnly: boolean = imp.specifiers.length === 0;
66+
if (defaultAliasOnly) {
67+
return defaultAliasOnlyMultiLineImportTemplate(
7168
imp.defaultAlias ? `${imp.defaultAlias}, ` : '',
69+
`${stringQuoteStyle}${imp.libraryName}${stringQuoteStyle}${eol}`,
7270
);
7371
}
74-
return importString;
72+
73+
const sortedImportSpecifiers: SymbolSpecifier[] = imp.specifiers.sort(specifierSort);
74+
let importSpecifierStrings: string = '';
75+
const indent = insertSpaces ? Array(tabSize + 1).join(' ') : '\t';
76+
if (wrapMethod === MultiLineImportRule.strictlyOneImportPerLine ||
77+
wrapMethod === MultiLineImportRule.oneImportPerLineOnlyAfterThreshold) {
78+
importSpecifierStrings = sortedImportSpecifiers.map(o => `${indent}${generateSymbolSpecifier(o)}`).join(',\n');
79+
} else if (wrapMethod === MultiLineImportRule.multipleImportsPerLine) {
80+
importSpecifierStrings = sortedImportSpecifiers.reduce(
81+
(acc, curr) => {
82+
const symbolSpecifier: string = generateSymbolSpecifier(curr);
83+
// const dist: number = acc.out.length - acc.lastWrapOffset + symbolSpecifier.length;
84+
const importLines = acc.out.split('\n');
85+
const lastImportLine = importLines[importLines.length - 1];
86+
const dist: number = lastImportLine.length + `, `.length + symbolSpecifier.length;
87+
const needsWrap: boolean = dist >= multiLineWrapThreshold;
88+
return {
89+
out: acc.out + (needsWrap ? `,\n${indent}` : (acc.out.length ? `, ` : `${indent}`)) +
90+
symbolSpecifier,
91+
lastWrapOffset: acc.lastWrapOffset + (needsWrap ? dist : 0),
92+
};
93+
},
94+
{
95+
out: '',
96+
lastWrapOffset: 0,
97+
},
98+
).out;
99+
}
100+
return multiLineImportTemplate(
101+
importSpecifierStrings,
102+
multiLineTrailingComma ? ',' : '',
103+
`${stringQuoteStyle}${imp.libraryName}${stringQuoteStyle}${eol}`,
104+
imp.defaultAlias ? `${imp.defaultAlias}, ` : '',
105+
);
75106
}
76107

77108
function getImportSpecifiers(namedImport: NamedImport, spaceBraces: boolean): string {

src/node-parser/class-parser.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,11 @@ import { Resource } from '../resources/Resource';
2020
import {
2121
isArrayBindingPattern,
2222
isConstructorDeclaration,
23+
isGetAccessorDeclaration,
2324
isIdentifier,
2425
isMethodDeclaration,
2526
isObjectBindingPattern,
2627
isPropertyDeclaration,
27-
isGetAccessorDeclaration,
2828
isSetAccessorDeclaration,
2929
} from '../type-guards/TypescriptGuards';
3030
import { parseFunctionParts, parseMethodParams } from './function-parser';

0 commit comments

Comments
 (0)