• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

teableio / teable / 8421654220

25 Mar 2024 02:22PM CUT coverage: 79.934% (+53.8%) from 26.087%
8421654220

Pull #495

github

web-flow
Merge 4faeebea5 into 1869c986d
Pull Request #495: chore: add licenses for non-NPM packages

3256 of 3853 branches covered (84.51%)

25152 of 31466 relevant lines covered (79.93%)

1188.29 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

39.22
/apps/nestjs-backend/src/features/automation/engine/json-schema/parser.ts
1
import { get } from 'lodash';
2✔
2

2✔
3
type IPathResolver<T = unknown> = (value: object, path: string | string[]) => T;
2✔
4

2✔
5
function defaultPathResolver(value: object, path: string | string[]) {
×
6
  return get(value, path);
×
7
}
×
8

2✔
9
export class JsonSchemaParser<TSchema extends { [key: string]: unknown }, TResult> {
2✔
10
  private readonly inputSchema: TSchema;
×
11
  private readonly pathResolver: IPathResolver;
×
12

×
13
  constructor(
×
14
    inputSchema: TSchema,
×
15
    options: {
×
16
      pathResolver?: IPathResolver;
×
17
    } = {}
×
18
  ) {
×
19
    this.inputSchema = inputSchema;
×
20
    this.pathResolver = options.pathResolver || defaultPathResolver;
×
21
  }
×
22

×
23
  async parse(): Promise<TResult> {
×
24
    const result: Record<string, unknown> = {};
×
25

×
26
    for (const [key, value] of Object.entries(this.inputSchema)) {
×
27
      if (typeof value === 'string') {
×
28
        result[key] = value;
×
29
      } else if (typeof value === 'object') {
×
30
        if (!value || !('type' in value)) {
×
31
          throw new Error(
×
32
            'Parse object format exceptions,Missing `type` attribute or object is undefined'
×
33
          );
×
34
        }
×
35

×
36
        const valueAs = value as Record<string, unknown>;
×
37
        result[key] = await ParserFactory.get(valueAs.type as IParserType).parse({
×
38
          schema: valueAs,
×
39
          pathResolver: this.pathResolver,
×
40
        });
×
41
      }
×
42
    }
×
43

×
44
    return result as TResult;
×
45
  }
×
46
}
×
47

2✔
48
type IParserType = 'null' | 'const' | 'array' | 'object' | 'template' | 'objectPathValue';
2✔
49

2✔
50
interface IOptions {
2✔
51
  schema: { [key: string]: unknown };
2✔
52
  parentNodeType?: IParserType;
2✔
53
  pathResolver: IPathResolver;
2✔
54
  arraySeparator?: string;
2✔
55
}
2✔
56

2✔
57
interface IParser {
2✔
58
  parse(options: IOptions): Promise<string | string[] | Record<string, unknown> | null | undefined>;
2✔
59
}
2✔
60

2✔
61
class NullParser implements IParser {
68✔
62
  private parserType: IParserType = 'null';
68✔
63

68✔
64
  async parse(_options: IOptions): Promise<null> {
68✔
65
    return null;
×
66
  }
×
67
}
68✔
68

2✔
69
/**
2✔
70
 * const parser:
2✔
71
 * Import:
2✔
72
 * ```
2✔
73
 * {
2✔
74
 *    type: 'const',
2✔
75
 *    value: 'tblwEp45tdvwTxiUl',
2✔
76
 *  }
2✔
77
 * ```
2✔
78
 * Export:
2✔
79
 * 'tblwEp45tdvwTxiUl'
2✔
80
 */
2✔
81
class ConstParser implements IParser {
68✔
82
  private parserType: IParserType = 'const';
68✔
83

68✔
84
  async parse(options: IOptions): Promise<string | undefined> {
68✔
85
    const { schema } = options;
×
86
    return schema.value as string;
×
87
  }
×
88
}
68✔
89

2✔
90
class ArrayParser implements IParser {
68✔
91
  private parserType: IParserType = 'array';
68✔
92

68✔
93
  async parse(options: IOptions): Promise<string | string[] | undefined> {
68✔
94
    const { schema, parentNodeType, arraySeparator } = options;
×
95

×
96
    const result: string[] = [];
×
97
    for (const element of schema.elements as []) {
×
98
      const value = await ParserFactory.get(element['type']).parse({
×
99
        ...options,
×
100
        schema: element,
×
101
        parentNodeType: this.parserType,
×
102
      });
×
103
      result.push(value as string);
×
104
    }
×
105

×
106
    if (!parentNodeType || parentNodeType === 'object') {
×
107
      return result;
×
108
    }
×
109

×
110
    return result.join(arraySeparator || '');
×
111
  }
×
112
}
68✔
113

2✔
114
class ObjectParser implements IParser {
68✔
115
  private parserType: IParserType = 'object';
68✔
116

68✔
117
  async parse(options: IOptions): Promise<Record<string, unknown> | undefined> {
68✔
118
    const { schema } = options;
×
119

×
120
    const result: Record<string, unknown> = {};
×
121

×
122
    for (const prop of schema.properties as []) {
×
123
      const [key, value] = await Promise.all([
×
124
        ParserFactory.get(prop['key']['type']).parse({
×
125
          ...options,
×
126
          schema: prop['key'],
×
127
          parentNodeType: this.parserType,
×
128
        }),
×
129
        ParserFactory.get(prop['value']['type']).parse({
×
130
          ...options,
×
131
          schema: prop['value'],
×
132
          parentNodeType: this.parserType,
×
133
        }),
×
134
      ]);
×
135

×
136
      result[key as string] = value;
×
137
    }
×
138

×
139
    return result;
×
140
  }
×
141
}
68✔
142

2✔
143
class TemplateParser implements IParser {
68✔
144
  private parserType: IParserType = 'template';
68✔
145

68✔
146
  async parse(options: IOptions): Promise<string | string[] | undefined> {
68✔
147
    const { schema } = options;
×
148

×
149
    const result: string[] = [];
×
150

×
151
    for (const element of schema.elements as []) {
×
152
      const value = await ParserFactory.get(element['type']).parse({
×
153
        ...options,
×
154
        schema: element,
×
155
        parentNodeType: this.parserType,
×
156
      });
×
157
      result.push(value as string);
×
158
    }
×
159

×
160
    return result.join('');
×
161
  }
×
162
}
68✔
163

2✔
164
class ObjectPathValueParser implements IParser {
68✔
165
  private parserType: IParserType = 'objectPathValue';
68✔
166

68✔
167
  async parse(options: IOptions): Promise<string | Record<string, unknown> | undefined> {
68✔
168
    const { schema, pathResolver } = options;
×
169

×
170
    const { nodeId, nodeType } = schema.object as Record<string, string>;
×
171
    const pathAs = schema.path as Record<string, unknown>;
×
172

×
173
    const path = (await ParserFactory.get(pathAs.type as IParserType).parse({
×
174
      ...options,
×
175
      schema: pathAs,
×
176
      arraySeparator: '.',
×
177
      parentNodeType: this.parserType,
×
178
    })) as string;
×
179

×
180
    return pathResolver(schema, [`${nodeType}.${nodeId}`, path]) as
×
181
      | string
×
182
      | Record<string, unknown>
×
183
      | undefined;
×
184
  }
×
185
}
68✔
186

2✔
187
class ParserFactory {
2✔
188
  private static _parsers: { [type: string]: IParser } = {
2✔
189
    null: new NullParser(),
68✔
190
    const: new ConstParser(),
68✔
191
    array: new ArrayParser(),
68✔
192
    object: new ObjectParser(),
68✔
193
    template: new TemplateParser(),
68✔
194
    objectPathValue: new ObjectPathValueParser(),
68✔
195
  };
68✔
196

2✔
197
  static get(type: IParserType): IParser {
2✔
198
    const service: IParser = this._parsers[type];
×
199
    if (!service) {
×
200
      throw new Error('Unknown parser type: ' + type);
×
201
    }
×
202
    return service;
×
203
  }
×
204
}
2✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc