Skip to content

Commit 10d3b65

Browse files
rpetrichdomoritz
authored andcommitted
Support TypeScript 2.9.x (YousefED#223)
* Support TypeScript 2.9.x * Fix linter violation * Fix type name generation for TypeScript 2.9.x * Rename unique names test filenames to match what new version of TypeScript emits * Make symbol hashes based on the source filename and position in the file instead of symbol ID (so that tests deterministically pass regardless of precise TypeScript version and imports) * Use the getCurrentDirectory method from TypeScript instead of node's process.cwd * Update ts-node
1 parent 11dd5ce commit 10d3b65

File tree

4 files changed

+14
-8
lines changed

4 files changed

+14
-8
lines changed

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@
4848
"dependencies": {
4949
"glob": "~7.1.2",
5050
"json-stable-stringify": "^1.0.1",
51-
"typescript": "~2.8.3",
51+
"typescript": "~2.9.2",
5252
"yargs": "^11.0.0"
5353
},
5454
"devDependencies": {
@@ -62,7 +62,7 @@
6262
"chai": "^4.1.2",
6363
"mocha": "^5.1.1",
6464
"source-map-support": "^0.5.5",
65-
"ts-node": "^6.0.1",
65+
"ts-node": "^7.0.0",
6666
"tslint": "^5.9.1"
6767
},
6868
"scripts": {

typescript-json-schema.ts

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
import * as glob from "glob";
22
import * as stringify from "json-stable-stringify";
33
import * as path from "path";
4+
import { createHash } from "crypto";
45
import * as ts from "typescript";
56
export { Program, CompilerOptions, Symbol } from "typescript";
67

78

89
const vm = require("vm");
910

10-
const REGEX_FILE_NAME = /".*"\./;
11+
const REGEX_FILE_NAME_OR_SPACE = /(\bimport\(".*?"\)|".*?")\.| /g;
1112
const REGEX_TSCONFIG_NAME = /^.*\.json$/;
1213
const REGEX_TJS_JSDOC = /^-([\w]+)\s+(\S|\S[\s\S]*\S)\s*$/g;
1314

@@ -801,7 +802,7 @@ export class JsonSchemaGenerator {
801802
return this.typeNamesById[id];
802803
}
803804

804-
const baseName = this.tc.typeToString(typ, undefined, ts.TypeFormatFlags.UseFullyQualifiedType);
805+
const baseName = this.tc.typeToString(typ, undefined, ts.TypeFormatFlags.NoTruncation | ts.TypeFormatFlags.UseFullyQualifiedType).replace(REGEX_FILE_NAME_OR_SPACE, "");
805806
let name = baseName;
806807
if (this.typeNamesUsed[name]) { // If a type with same name exists
807808
for (let i = 1; true; ++i) { // Try appending "_1", "_2", etc.
@@ -855,13 +856,11 @@ export class JsonSchemaGenerator {
855856
reffedType!.getFlags() & ts.SymbolFlags.Alias ?
856857
this.tc.getAliasedSymbol(reffedType!) :
857858
reffedType!
858-
).replace(REGEX_FILE_NAME, "");
859+
).replace(REGEX_FILE_NAME_OR_SPACE, "");
859860
} else if (asRef) {
860861
fullTypeName = this.getTypeName(typ);
861862
}
862863

863-
fullTypeName = fullTypeName.replace(" ", "");
864-
865864
if (asRef) {
866865
// We don't return the full definition, but we put it into
867866
// reffedDefinitions below.
@@ -1036,6 +1035,10 @@ export function getProgramFromFiles(files: string[], jsonCompilerOptions: any =
10361035
return ts.createProgram(files, options);
10371036
}
10381037

1038+
function generateHashOfNode(node: ts.Node, relativePath: string) {
1039+
return createHash("md5").update(relativePath).update(node.pos.toString()).digest("hex").substring(0, 8);
1040+
}
1041+
10391042
export function buildGenerator(program: ts.Program, args: PartialArgs = {}, onlyIncludeFiles?: string[]): JsonSchemaGenerator|null {
10401043
function isUserFile(file: ts.SourceFile): boolean {
10411044
if (onlyIncludeFiles === undefined) {
@@ -1065,8 +1068,11 @@ export function buildGenerator(program: ts.Program, args: PartialArgs = {}, only
10651068
const allSymbols: { [name: string]: ts.Type } = {};
10661069
const userSymbols: { [name: string]: ts.Symbol } = {};
10671070
const inheritingTypes: { [baseName: string]: string[] } = {};
1071+
const workingDir = program.getCurrentDirectory();
10681072

10691073
program.getSourceFiles().forEach((sourceFile, _sourceFileIdx) => {
1074+
const relativePath = path.relative(workingDir, sourceFile.fileName);
1075+
10701076
function inspect(node: ts.Node, tc: ts.TypeChecker) {
10711077

10721078
if (node.kind === ts.SyntaxKind.ClassDeclaration
@@ -1078,7 +1084,7 @@ export function buildGenerator(program: ts.Program, args: PartialArgs = {}, only
10781084
const nodeType = tc.getTypeAtLocation(node);
10791085
const fullyQualifiedName = tc.getFullyQualifiedName(symbol);
10801086
const typeName = fullyQualifiedName.replace(/".*"\./, "");
1081-
const name = !args.uniqueNames ? typeName : `${typeName}.${(<any>symbol).id}`;
1087+
const name = !args.uniqueNames ? typeName : `${typeName}.${generateHashOfNode(node, relativePath)}`;
10821088

10831089
symbols.push({ name, typeName, fullyQualifiedName, symbol });
10841090
if (!userSymbols[name]) {

0 commit comments

Comments
 (0)