Skip to content

Commit 2005b68

Browse files
--ignore-not-supported, GenericRecords to object, resolve namespaces
Do not throw exception on non supported features. GenericRecords transforms to object Namespaces content are parsed
1 parent e87d585 commit 2005b68

File tree

7 files changed

+82
-14
lines changed

7 files changed

+82
-14
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
dist/
2+
.idea
23

34
# Logs
45
logs
@@ -58,3 +59,4 @@ typings/
5859

5960
# dotenv environment variables file
6061
.env
62+

lib/index.ts

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ const ignoreNode = "";
2020
export interface ICompilerOptions {
2121
format?: "ts" | "js:esm" | "js:cjs"
2222
ignoreGenerics?: boolean;
23+
ignoreNotSupported?: boolean;
2324
ignoreIndexSignature?: boolean;
2425
inlineImports?: boolean;
2526
}
@@ -37,7 +38,7 @@ export class Compiler {
3738
if (!topNode) {
3839
throw new Error(`Can't process ${filePath}: ${collectDiagnostics(program)}`);
3940
}
40-
options = {format: defaultFormat, ignoreGenerics: false, ignoreIndexSignature: false, inlineImports: false, ...options}
41+
options = {format: defaultFormat, ignoreGenerics: false, ignoreNotSupported: false, ignoreIndexSignature: false, inlineImports: false, ...options}
4142
return new Compiler(checker, options, topNode).compileNode(topNode);
4243
}
4344

@@ -80,6 +81,12 @@ export class Compiler {
8081
case ts.SyntaxKind.ExportDeclaration:
8182
case ts.SyntaxKind.ImportDeclaration:
8283
return this._compileImportDeclaration(node as ts.ImportDeclaration);
84+
case ts.SyntaxKind.ModuleDeclaration:
85+
const body: ts.ModuleBody = node["body"];
86+
if ("statements" in body) {
87+
return body.statements.map(this.compileNode, this).filter(s => s).join("\n\n");
88+
}
89+
//return this._compileNamespaceDeclaration(node as ts.NamespaceDeclaration);
8390
case ts.SyntaxKind.SourceFile: return this._compileSourceFile(node as ts.SourceFile);
8491
case ts.SyntaxKind.AnyKeyword: return '"any"';
8592
case ts.SyntaxKind.NumberKeyword: return '"number"';
@@ -97,6 +104,12 @@ export class Compiler {
97104
}
98105
// Skip top-level statements that we haven't handled.
99106
if (ts.isSourceFile(node.parent!)) { return ""; }
107+
108+
if (this.options.ignoreNotSupported) {
109+
console.log(`Node ${ts.SyntaxKind[node.kind]} not supported by ts-interface-builder: ` +
110+
node.getText());
111+
return node.getText();
112+
}
100113
throw new Error(`Node ${ts.SyntaxKind[node.kind]} not supported by ts-interface-builder: ` +
101114
node.getText());
102115
}
@@ -139,6 +152,8 @@ export class Compiler {
139152
return this.compileNode(node.typeArguments[0]);
140153
} else if (node.typeName.getText() === "Array") {
141154
return `t.array(${this.compileNode(node.typeArguments[0])})`;
155+
} else if (node.typeName.getText() === "Record") {
156+
return '"object"';
142157
} else if (this.options.ignoreGenerics) {
143158
return '"any"';
144159
} else {
@@ -180,8 +195,15 @@ export class Compiler {
180195
}
181196
private _compileEnumDeclaration(node: ts.EnumDeclaration): string {
182197
const name = this.getName(node.name);
183-
const members: string[] = node.members.map(m =>
184-
` "${this.getName(m.name)}": ${getTextOfConstantValue(this.checker.getConstantValue(m))},\n`);
198+
let counter = 0;
199+
const members: string[] = node.members.map(m => {
200+
let value = getTextOfConstantValue(this.checker.getConstantValue(m));
201+
if (value === "undefined") {
202+
value = counter.toString(10);
203+
++counter;
204+
}
205+
return ` "${this.getName(m.name)}": ${value},\n`
206+
});
185207
this.exportedNames.push(name);
186208
return this._formatExport(name, `t.enumtype({\n${members.join("")}})`);
187209
}
@@ -214,6 +236,13 @@ export class Compiler {
214236
private _compileParenthesizedTypeNode(node: ts.ParenthesizedTypeNode): string {
215237
return this.compileNode(node.type);
216238
}
239+
// private _compileNamespaceDeclaration(node: ts.NamespaceDeclaration): string {
240+
// if ("statements" in node.body) {
241+
// const name = this.getName(node.name);
242+
// const prefix = node.modifiers.map(n => n.getText()).filter(s => s).join(" ");
243+
// return `${prefix} ${name} {\n${this._compileSourceFileStatements(node.body.statements)}\n}\n`;
244+
// }
245+
// }
217246
private _compileImportDeclaration(node: ts.ImportDeclaration): string {
218247
if (this.options.inlineImports) {
219248
const importedSym = this.checker.getSymbolAtLocation(node.moduleSpecifier);
@@ -226,26 +255,27 @@ export class Compiler {
226255
}
227256
return '';
228257
}
229-
private _compileSourceFileStatements(node: ts.SourceFile): string {
230-
return node.statements.map(this.compileNode, this).filter((s) => s).join("\n\n");
258+
private _compileSourceFileStatements(statements: ts.NodeArray<ts.Statement>): string {
259+
260+
return statements.map(this.compileNode, this).filter((s) => s).join("\n\n");
231261
}
232262
private _compileSourceFile(node: ts.SourceFile): string {
233263
// for imported source files, skip the wrapper
234264
if (node !== this.topNode) {
235-
return this._compileSourceFileStatements(node);
265+
return this._compileSourceFileStatements(node.statements);
236266
}
237267
// wrap the top node with a default export
238268
if (this.options.format === "js:cjs") {
239269
return `const t = require("ts-interface-checker");\n\n` +
240270
"module.exports = {\n" +
241-
this._compileSourceFileStatements(node) + "\n" +
271+
this._compileSourceFileStatements(node.statements) + "\n" +
242272
"};\n"
243273
}
244274
const prefix = `import * as t from "ts-interface-checker";\n` +
245275
(this.options.format === "ts" ? "// tslint:disable:object-literal-key-quotes\n" : "") +
246276
"\n";
247277
return prefix +
248-
this._compileSourceFileStatements(node) + "\n\n" +
278+
this._compileSourceFileStatements(node.statements) + "\n\n" +
249279
"const exportedTypeSuite" + (this.options.format === "ts" ? ": t.ITypeSuite" : "") + " = {\n" +
250280
this.exportedNames.map((n) => ` ${n},\n`).join("") +
251281
"};\n" +
@@ -302,6 +332,7 @@ export function main() {
302332
.option("--format <format>", `Format to use for output; options are 'ts' (default), 'js:esm', 'js:cjs'`)
303333
.option("-g, --ignore-generics", `Ignores generics`)
304334
.option("-i, --ignore-index-signature", `Ignores index signature`)
335+
.option("--ignore-not-supported", `Skip all not supported code`)
305336
.option("--inline-imports", `Traverses the full import tree and inlines all types into output`)
306337
.option("-s, --suffix <suffix>", `Suffix to append to generated files (default ${defaultSuffix})`, defaultSuffix)
307338
.option("-o, --outDir <path>", `Directory for output files; same as source file if omitted`)
@@ -317,6 +348,7 @@ export function main() {
317348
const options: ICompilerOptions = {
318349
format: commander.format || defaultFormat,
319350
ignoreGenerics: commander.ignoreGenerics,
351+
ignoreNotSupported: commander.ignoreNotSupported,
320352
ignoreIndexSignature: commander.ignoreIndexSignature,
321353
inlineImports: commander.inlineImports,
322354
};

lib/macro.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,8 @@ const macroHandler: MacroHandler = (params) => {
4848

4949
// Begin mutations
5050

51-
programPath.scope.rename(tsInterfaceCheckerIdentifier);
52-
programPath.scope.rename(onceIdentifier);
51+
programPath?.scope.rename(tsInterfaceCheckerIdentifier);
52+
programPath?.scope.rename(onceIdentifier);
5353
toReplace.forEach(({ callPath, id }) => {
5454
scopeRenameRecursive(callPath.scope, id);
5555
});
@@ -127,7 +127,7 @@ const macroHandler: MacroHandler = (params) => {
127127
}
128128

129129
function prependProgramStatement(statement: types.Statement) {
130-
(programPath.get("body.0") as NodePath).insertBefore(statement);
130+
(programPath?.get("body.0") as NodePath).insertBefore(statement);
131131
}
132132
};
133133

test/fixtures/namespaces-ti.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import * as t from "ts-interface-checker";
2+
// tslint:disable:object-literal-key-quotes
3+
4+
export const SomeInterface = t.iface([], {
5+
"foo": "number",
6+
});
7+
8+
export const SomeEnum = t.enumtype({
9+
"Foo": 0,
10+
"Boo": 1,
11+
});
12+
13+
export const SomeAlias = t.name("number");
14+
15+
const exportedTypeSuite: t.ITypeSuite = {
16+
SomeInterface,
17+
SomeEnum,
18+
SomeAlias,
19+
};
20+
export default exportedTypeSuite;

test/fixtures/namespaces.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
export declare namespace TestNameSpace {
2+
export interface SomeInterface {
3+
foo: number
4+
}
5+
export enum SomeEnum { Foo, Boo }
6+
7+
export type SomeAlias = number;
8+
}

test/test_index.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,13 @@ describe("ts-interface-builder", () => {
1111
const expected = await readFile(join(fixtures, "sample-ti.ts"), {encoding: "utf8"});
1212
assert.deepEqual(output, expected);
1313
});
14-
14+
15+
it("should compile namespace to runtime code", async () => {
16+
const output = await Compiler.compile(join(fixtures, "namespaces.ts"), {ignoreNotSupported: true});
17+
const expected = await readFile(join(fixtures, "namespaces-ti.ts"), {encoding: "utf8"});
18+
assert.deepEqual(output, expected);
19+
});
20+
1521
it("should strip out promises", async () => {
1622
const output = await Compiler.compile(join(fixtures, "promises.ts"));
1723
const expected = await readFile(join(fixtures, "promises-ti.ts"), {encoding: "utf8"});

tsconfig.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"compilerOptions": {
3-
"target": "es6",
4-
"strict": true,
3+
"target": "es2018",
4+
"strict": false,
55
"noUnusedLocals": true,
66
"module": "commonjs",
77
"baseUrl": ".",

0 commit comments

Comments
 (0)