UNPKG

5.44 kBPlain TextView Raw
1import * as ts from 'typescript';
2import {JsonTsOptions} from "./index";
3import needsQuotes = require("needsquotes");
4
5export interface ParsedNode {
6 kind: ts.SyntaxKind
7 _kind: string
8 name?: string
9 value?: any
10 body?: ParsedNode[]
11 interfaceCandidate?: boolean
12}
13
14function walk(sourceFile: ts.SourceFile): ParsedNode[] {
15
16 const stack : Array<ParsedNode> = [];
17 const elementStack : Array<ParsedNode> = [];
18
19 function push(element) {
20 const parent = elementStack[elementStack.length - 1];
21 const siblings = (parent && parent.body) ? parent.body : stack;
22 siblings.push(element);
23 }
24
25 eachProp(sourceFile);
26
27 return stack;
28
29 function addFromArrayElement(incoming) {
30 switch(incoming.kind) {
31 case ts.SyntaxKind.NullKeyword:
32 case ts.SyntaxKind.TrueKeyword:
33 case ts.SyntaxKind.FalseKeyword:
34 case ts.SyntaxKind.NumericLiteral:
35 case ts.SyntaxKind.StringLiteral: {
36 push(literalTypeFromArrayElement(incoming, incoming.kind));
37 break;
38 }
39 case ts.SyntaxKind.PrefixUnaryExpression: {
40 push(literalTypeFromArrayElement(incoming, ts.SyntaxKind.NumericLiteral));
41 break;
42 }
43 case ts.SyntaxKind.ObjectLiteralExpression: {
44 const elem = {
45 kind: ts.SyntaxKind.ObjectLiteralExpression,
46 _kind: `ObjectLiteralExpression`,
47 interfaceCandidate: true,
48 body: [],
49 };
50 push(elem);
51 elementStack.push(elem);
52 eachProp(incoming.properties);
53 elementStack.pop();
54 break;
55 }
56 case ts.SyntaxKind.ArrayLiteralExpression: {
57 const elem = {
58 kind: ts.SyntaxKind.ArrayLiteralExpression,
59 _kind: `ArrayLiteralExpression`,
60 body: [],
61 };
62 push(elem);
63 elementStack.push(elem);
64 eachProp(incoming.elements);
65 elementStack.pop();
66 break;
67 }
68 }
69 }
70
71 function eachProp(properties) {
72 properties.forEach(function (prop) {
73 if (!prop.initializer) {
74 return addFromArrayElement(prop);
75 } else {
76 switch (prop.initializer.kind) {
77 case ts.SyntaxKind.TrueKeyword:
78 case ts.SyntaxKind.FalseKeyword:
79 case ts.SyntaxKind.NullKeyword:
80 case ts.SyntaxKind.StringLiteral:
81 case ts.SyntaxKind.NumericLiteral: {
82 push(literalTypeFromProp(prop, prop.initializer.kind));
83 break;
84 }
85 case ts.SyntaxKind.PrefixUnaryExpression: {
86 push(literalTypeFromProp(prop, ts.SyntaxKind.NumericLiteral));
87 break;
88 }
89 case ts.SyntaxKind.ObjectLiteralExpression: {
90 const quotes = needsQuotes(prop.name.text).needsQuotes;
91 const interfaceCandidate = (quotes === false);
92
93 const elem = {
94 name: prop.name.text,
95 body: [],
96 interfaceCandidate,
97 kind: ts.SyntaxKind.ObjectLiteralExpression,
98 _kind: `ObjectLiteralExpression`
99 };
100 push(elem);
101 elementStack.push(elem);
102 eachProp(prop.initializer.properties);
103 elementStack.pop();
104 break;
105 }
106 case ts.SyntaxKind.ArrayLiteralExpression: {
107 const elem = {
108 name: prop.name.text,
109 body: [],
110 kind: ts.SyntaxKind.ArrayLiteralExpression,
111 _kind: `ArrayLiteralExpression`
112 };
113 push(elem);
114 elementStack.push(elem);
115 eachProp(prop.initializer.elements);
116 elementStack.pop();
117 break;
118 }
119 }
120 }
121 });
122 }
123
124 function literalTypeFromProp(prop, kind) {
125 return {
126 name: prop.name.text,
127 value: prop.initializer.text,
128 kind: kind,
129 }
130 }
131
132 function literalTypeFromArrayElement(element, kind) {
133 return {
134 kind,
135 name: element.text,
136 value: element.text,
137 }
138 }
139}
140
141export function parse(string, options: JsonTsOptions): any[] {
142 const input = `const ROOTOBJ = ${string}`;
143 let sourceFile : ts.SourceFile = ts.createSourceFile('json.ts', input, ts.ScriptTarget.ES2015, /*setParentNodes */ true);
144 // delint it
145 const _json = sourceFile.statements[0] as any;
146 // console.log(sourceFile.statements[0].declarationList.declarations[0].initializer.properties);
147 // elementStack.push({name: 'root', body: []});
148 const stack = walk(_json.declarationList.declarations[0].initializer.properties);
149 return stack;
150}