How to use parseTypeExpression method in Playwright Internal

Best JavaScript code snippet using playwright-internal

Run Playwright Internal automation tests on LambdaTest cloud grid

Perform automation testing on 3000+ real desktop and mobile devices online.

typed.js

Source: typed.js Github

copy
1/*
2 * @fileoverview Type expression parser.
3 * @author Yusuke Suzuki <[email protected]>
4 * @author Dan Tao <[email protected]>
5 * @author Andrew Eisenberg <[email protected]>
6 */
7
8// "typed", the Type Expression Parser for doctrine.
9
10(function () {
11    'use strict';
12
13    var Syntax,
14        Token,
15        source,
16        length,
17        index,
18        previous,
19        token,
20        value,
21        esutils,
22        utility;
23
24    esutils = require('esutils');
25    utility = require('./utility');
26
27    Syntax = {
28        NullableLiteral: 'NullableLiteral',
29        AllLiteral: 'AllLiteral',
30        NullLiteral: 'NullLiteral',
31        UndefinedLiteral: 'UndefinedLiteral',
32        VoidLiteral: 'VoidLiteral',
33        UnionType: 'UnionType',
34        ArrayType: 'ArrayType',
35        RecordType: 'RecordType',
36        FieldType: 'FieldType',
37        FunctionType: 'FunctionType',
38        ParameterType: 'ParameterType',
39        RestType: 'RestType',
40        NonNullableType: 'NonNullableType',
41        OptionalType: 'OptionalType',
42        NullableType: 'NullableType',
43        NameExpression: 'NameExpression',
44        TypeApplication: 'TypeApplication',
45        StringLiteralType: 'StringLiteralType',
46        NumericLiteralType: 'NumericLiteralType',
47        BooleanLiteralType: 'BooleanLiteralType'
48    };
49
50    Token = {
51        ILLEGAL: 0,    // ILLEGAL
52        DOT_LT: 1,     // .<
53        REST: 2,       // ...
54        LT: 3,         // <
55        GT: 4,         // >
56        LPAREN: 5,     // (
57        RPAREN: 6,     // )
58        LBRACE: 7,     // {
59        RBRACE: 8,     // }
60        LBRACK: 9,    // [
61        RBRACK: 10,    // ]
62        COMMA: 11,     // ,
63        COLON: 12,     // :
64        STAR: 13,      // *
65        PIPE: 14,      // |
66        QUESTION: 15,  // ?
67        BANG: 16,      // !
68        EQUAL: 17,     // =
69        NAME: 18,      // name token
70        STRING: 19,    // string
71        NUMBER: 20,    // number
72        EOF: 21
73    };
74
75    function isTypeName(ch) {
76        return '><(){}[],:*|?!='.indexOf(String.fromCharCode(ch)) === -1 && !esutils.code.isWhiteSpace(ch) && !esutils.code.isLineTerminator(ch);
77    }
78
79    function Context(previous, index, token, value) {
80        this._previous = previous;
81        this._index = index;
82        this._token = token;
83        this._value = value;
84    }
85
86    Context.prototype.restore = function () {
87        previous = this._previous;
88        index = this._index;
89        token = this._token;
90        value = this._value;
91    };
92
93    Context.save = function () {
94        return new Context(previous, index, token, value);
95    };
96
97    function advance() {
98        var ch = source.charAt(index);
99        index += 1;
100        return ch;
101    }
102
103    function scanHexEscape(prefix) {
104        var i, len, ch, code = 0;
105
106        len = (prefix === 'u') ? 4 : 2;
107        for (i = 0; i < len; ++i) {
108            if (index < length && esutils.code.isHexDigit(source.charCodeAt(index))) {
109                ch = advance();
110                code = code * 16 + '0123456789abcdef'.indexOf(ch.toLowerCase());
111            } else {
112                return '';
113            }
114        }
115        return String.fromCharCode(code);
116    }
117
118    function scanString() {
119        var str = '', quote, ch, code, unescaped, restore; //TODO review removal octal = false
120        quote = source.charAt(index);
121        ++index;
122
123        while (index < length) {
124            ch = advance();
125
126            if (ch === quote) {
127                quote = '';
128                break;
129            } else if (ch === '\\') {
130                ch = advance();
131                if (!esutils.code.isLineTerminator(ch.charCodeAt(0))) {
132                    switch (ch) {
133                    case 'n':
134                        str += '\n';
135                        break;
136                    case 'r':
137                        str += '\r';
138                        break;
139                    case 't':
140                        str += '\t';
141                        break;
142                    case 'u':
143                    case 'x':
144                        restore = index;
145                        unescaped = scanHexEscape(ch);
146                        if (unescaped) {
147                            str += unescaped;
148                        } else {
149                            index = restore;
150                            str += ch;
151                        }
152                        break;
153                    case 'b':
154                        str += '\b';
155                        break;
156                    case 'f':
157                        str += '\f';
158                        break;
159                    case 'v':
160                        str += '\v';
161                        break;
162
163                    default:
164                        if (esutils.code.isOctalDigit(ch.charCodeAt(0))) {
165                            code = '01234567'.indexOf(ch);
166
167                            // \0 is not octal escape sequence
168                            // Deprecating unused code. TODO review removal
169                            //if (code !== 0) {
170                            //    octal = true;
171                            //}
172
173                            if (index < length && esutils.code.isOctalDigit(source.charCodeAt(index))) {
174                                //TODO Review Removal octal = true;
175                                code = code * 8 + '01234567'.indexOf(advance());
176
177                                // 3 digits are only allowed when string starts
178                                // with 0, 1, 2, 3
179                                if ('0123'.indexOf(ch) >= 0 &&
180                                        index < length &&
181                                        esutils.code.isOctalDigit(source.charCodeAt(index))) {
182                                    code = code * 8 + '01234567'.indexOf(advance());
183                                }
184                            }
185                            str += String.fromCharCode(code);
186                        } else {
187                            str += ch;
188                        }
189                        break;
190                    }
191                } else {
192                    if (ch ===  '\r' && source.charCodeAt(index) === 0x0A  /* '\n' */) {
193                        ++index;
194                    }
195                }
196            } else if (esutils.code.isLineTerminator(ch.charCodeAt(0))) {
197                break;
198            } else {
199                str += ch;
200            }
201        }
202
203        if (quote !== '') {
204            utility.throwError('unexpected quote');
205        }
206
207        value = str;
208        return Token.STRING;
209    }
210
211    function scanNumber() {
212        var number, ch;
213
214        number = '';
215        ch = source.charCodeAt(index);
216
217        if (ch !== 0x2E  /* '.' */) {
218            number = advance();
219            ch = source.charCodeAt(index);
220
221            if (number === '0') {
222                if (ch === 0x78  /* 'x' */ || ch === 0x58  /* 'X' */) {
223                    number += advance();
224                    while (index < length) {
225                        ch = source.charCodeAt(index);
226                        if (!esutils.code.isHexDigit(ch)) {
227                            break;
228                        }
229                        number += advance();
230                    }
231
232                    if (number.length <= 2) {
233                        // only 0x
234                        utility.throwError('unexpected token');
235                    }
236
237                    if (index < length) {
238                        ch = source.charCodeAt(index);
239                        if (esutils.code.isIdentifierStartES5(ch)) {
240                            utility.throwError('unexpected token');
241                        }
242                    }
243                    value = parseInt(number, 16);
244                    return Token.NUMBER;
245                }
246
247                if (esutils.code.isOctalDigit(ch)) {
248                    number += advance();
249                    while (index < length) {
250                        ch = source.charCodeAt(index);
251                        if (!esutils.code.isOctalDigit(ch)) {
252                            break;
253                        }
254                        number += advance();
255                    }
256
257                    if (index < length) {
258                        ch = source.charCodeAt(index);
259                        if (esutils.code.isIdentifierStartES5(ch) || esutils.code.isDecimalDigit(ch)) {
260                            utility.throwError('unexpected token');
261                        }
262                    }
263                    value = parseInt(number, 8);
264                    return Token.NUMBER;
265                }
266
267                if (esutils.code.isDecimalDigit(ch)) {
268                    utility.throwError('unexpected token');
269                }
270            }
271
272            while (index < length) {
273                ch = source.charCodeAt(index);
274                if (!esutils.code.isDecimalDigit(ch)) {
275                    break;
276                }
277                number += advance();
278            }
279        }
280
281        if (ch === 0x2E  /* '.' */) {
282            number += advance();
283            while (index < length) {
284                ch = source.charCodeAt(index);
285                if (!esutils.code.isDecimalDigit(ch)) {
286                    break;
287                }
288                number += advance();
289            }
290        }
291
292        if (ch === 0x65  /* 'e' */ || ch === 0x45  /* 'E' */) {
293            number += advance();
294
295            ch = source.charCodeAt(index);
296            if (ch === 0x2B  /* '+' */ || ch === 0x2D  /* '-' */) {
297                number += advance();
298            }
299
300            ch = source.charCodeAt(index);
301            if (esutils.code.isDecimalDigit(ch)) {
302                number += advance();
303                while (index < length) {
304                    ch = source.charCodeAt(index);
305                    if (!esutils.code.isDecimalDigit(ch)) {
306                        break;
307                    }
308                    number += advance();
309                }
310            } else {
311                utility.throwError('unexpected token');
312            }
313        }
314
315        if (index < length) {
316            ch = source.charCodeAt(index);
317            if (esutils.code.isIdentifierStartES5(ch)) {
318                utility.throwError('unexpected token');
319            }
320        }
321
322        value = parseFloat(number);
323        return Token.NUMBER;
324    }
325
326
327    function scanTypeName() {
328        var ch, ch2;
329
330        value = advance();
331        while (index < length && isTypeName(source.charCodeAt(index))) {
332            ch = source.charCodeAt(index);
333            if (ch === 0x2E  /* '.' */) {
334                if ((index + 1) >= length) {
335                    return Token.ILLEGAL;
336                }
337                ch2 = source.charCodeAt(index + 1);
338                if (ch2 === 0x3C  /* '<' */) {
339                    break;
340                }
341            }
342            value += advance();
343        }
344        return Token.NAME;
345    }
346
347    function next() {
348        var ch;
349
350        previous = index;
351
352        while (index < length && esutils.code.isWhiteSpace(source.charCodeAt(index))) {
353            advance();
354        }
355        if (index >= length) {
356            token = Token.EOF;
357            return token;
358        }
359
360        ch = source.charCodeAt(index);
361        switch (ch) {
362        case 0x27:  /* ''' */
363        case 0x22:  /* '"' */
364            token = scanString();
365            return token;
366
367        case 0x3A:  /* ':' */
368            advance();
369            token = Token.COLON;
370            return token;
371
372        case 0x2C:  /* ',' */
373            advance();
374            token = Token.COMMA;
375            return token;
376
377        case 0x28:  /* '(' */
378            advance();
379            token = Token.LPAREN;
380            return token;
381
382        case 0x29:  /* ')' */
383            advance();
384            token = Token.RPAREN;
385            return token;
386
387        case 0x5B:  /* '[' */
388            advance();
389            token = Token.LBRACK;
390            return token;
391
392        case 0x5D:  /* ']' */
393            advance();
394            token = Token.RBRACK;
395            return token;
396
397        case 0x7B:  /* '{' */
398            advance();
399            token = Token.LBRACE;
400            return token;
401
402        case 0x7D:  /* '}' */
403            advance();
404            token = Token.RBRACE;
405            return token;
406
407        case 0x2E:  /* '.' */
408            if (index + 1 < length) {
409                ch = source.charCodeAt(index + 1);
410                if (ch === 0x3C  /* '<' */) {
411                    advance();  // '.'
412                    advance();  // '<'
413                    token = Token.DOT_LT;
414                    return token;
415                }
416
417                if (ch === 0x2E  /* '.' */ && index + 2 < length && source.charCodeAt(index + 2) === 0x2E  /* '.' */) {
418                    advance();  // '.'
419                    advance();  // '.'
420                    advance();  // '.'
421                    token = Token.REST;
422                    return token;
423                }
424
425                if (esutils.code.isDecimalDigit(ch)) {
426                    token = scanNumber();
427                    return token;
428                }
429            }
430            token = Token.ILLEGAL;
431            return token;
432
433        case 0x3C:  /* '<' */
434            advance();
435            token = Token.LT;
436            return token;
437
438        case 0x3E:  /* '>' */
439            advance();
440            token = Token.GT;
441            return token;
442
443        case 0x2A:  /* '*' */
444            advance();
445            token = Token.STAR;
446            return token;
447
448        case 0x7C:  /* '|' */
449            advance();
450            token = Token.PIPE;
451            return token;
452
453        case 0x3F:  /* '?' */
454            advance();
455            token = Token.QUESTION;
456            return token;
457
458        case 0x21:  /* '!' */
459            advance();
460            token = Token.BANG;
461            return token;
462
463        case 0x3D:  /* '=' */
464            advance();
465            token = Token.EQUAL;
466            return token;
467
468        case 0x2D: /* '-' */
469            token = scanNumber();
470            return token;
471
472        default:
473            if (esutils.code.isDecimalDigit(ch)) {
474                token = scanNumber();
475                return token;
476            }
477
478            // type string permits following case,
479            //
480            // namespace.module.MyClass
481            //
482            // this reduced 1 token TK_NAME
483            utility.assert(isTypeName(ch));
484            token = scanTypeName();
485            return token;
486        }
487    }
488
489    function consume(target, text) {
490        utility.assert(token === target, text || 'consumed token not matched');
491        next();
492    }
493
494    function expect(target, message) {
495        if (token !== target) {
496            utility.throwError(message || 'unexpected token');
497        }
498        next();
499    }
500
501    // UnionType := '(' TypeUnionList ')'
502    //
503    // TypeUnionList :=
504    //     <<empty>>
505    //   | NonemptyTypeUnionList
506    //
507    // NonemptyTypeUnionList :=
508    //     TypeExpression
509    //   | TypeExpression '|' NonemptyTypeUnionList
510    function parseUnionType() {
511        var elements;
512        consume(Token.LPAREN, 'UnionType should start with (');
513        elements = [];
514        if (token !== Token.RPAREN) {
515            while (true) {
516                elements.push(parseTypeExpression());
517                if (token === Token.RPAREN) {
518                    break;
519                }
520                expect(Token.PIPE);
521            }
522        }
523        consume(Token.RPAREN, 'UnionType should end with )');
524        return {
525            type: Syntax.UnionType,
526            elements: elements
527        };
528    }
529
530    // ArrayType := '[' ElementTypeList ']'
531    //
532    // ElementTypeList :=
533    //     <<empty>>
534    //  | TypeExpression
535    //  | '...' TypeExpression
536    //  | TypeExpression ',' ElementTypeList
537    function parseArrayType() {
538        var elements;
539        consume(Token.LBRACK, 'ArrayType should start with [');
540        elements = [];
541        while (token !== Token.RBRACK) {
542            if (token === Token.REST) {
543                consume(Token.REST);
544                elements.push({
545                    type: Syntax.RestType,
546                    expression: parseTypeExpression()
547                });
548                break;
549            } else {
550                elements.push(parseTypeExpression());
551            }
552            if (token !== Token.RBRACK) {
553                expect(Token.COMMA);
554            }
555        }
556        expect(Token.RBRACK);
557        return {
558            type: Syntax.ArrayType,
559            elements: elements
560        };
561    }
562
563    function parseFieldName() {
564        var v = value;
565        if (token === Token.NAME || token === Token.STRING) {
566            next();
567            return v;
568        }
569
570        if (token === Token.NUMBER) {
571            consume(Token.NUMBER);
572            return String(v);
573        }
574
575        utility.throwError('unexpected token');
576    }
577
578    // FieldType :=
579    //     FieldName
580    //   | FieldName ':' TypeExpression
581    //
582    // FieldName :=
583    //     NameExpression
584    //   | StringLiteral
585    //   | NumberLiteral
586    //   | ReservedIdentifier
587    function parseFieldType() {
588        var key;
589
590        key = parseFieldName();
591        if (token === Token.COLON) {
592            consume(Token.COLON);
593            return {
594                type: Syntax.FieldType,
595                key: key,
596                value: parseTypeExpression()
597            };
598        }
599        return {
600            type: Syntax.FieldType,
601            key: key,
602            value: null
603        };
604    }
605
606    // RecordType := '{' FieldTypeList '}'
607    //
608    // FieldTypeList :=
609    //     <<empty>>
610    //   | FieldType
611    //   | FieldType ',' FieldTypeList
612    function parseRecordType() {
613        var fields;
614
615        consume(Token.LBRACE, 'RecordType should start with {');
616        fields = [];
617        if (token === Token.COMMA) {
618            consume(Token.COMMA);
619        } else {
620            while (token !== Token.RBRACE) {
621                fields.push(parseFieldType());
622                if (token !== Token.RBRACE) {
623                    expect(Token.COMMA);
624                }
625            }
626        }
627        expect(Token.RBRACE);
628        return {
629            type: Syntax.RecordType,
630            fields: fields
631        };
632    }
633
634    // NameExpression :=
635    //    Identifier
636    //  | TagIdentifier ':' Identifier
637    //
638    // Tag identifier is one of "module", "external" or "event"
639    // Identifier is the same as Token.NAME, including any dots, something like
640    // namespace.module.MyClass
641    function parseNameExpression() {
642        var name = value;
643        expect(Token.NAME);
644
645        if (token === Token.COLON && (
646                name === 'module' ||
647                name === 'external' ||
648                name === 'event')) {
649            consume(Token.COLON);
650            name += ':' + value;
651            expect(Token.NAME);
652        }
653
654        return {
655            type: Syntax.NameExpression,
656            name: name
657        };
658    }
659
660    // TypeExpressionList :=
661    //     TopLevelTypeExpression
662    //   | TopLevelTypeExpression ',' TypeExpressionList
663    function parseTypeExpressionList() {
664        var elements = [];
665
666        elements.push(parseTop());
667        while (token === Token.COMMA) {
668            consume(Token.COMMA);
669            elements.push(parseTop());
670        }
671        return elements;
672    }
673
674    // TypeName :=
675    //     NameExpression
676    //   | NameExpression TypeApplication
677    //
678    // TypeApplication :=
679    //     '.<' TypeExpressionList '>'
680    //   | '<' TypeExpressionList '>'   // this is extension of doctrine
681    function parseTypeName() {
682        var expr, applications;
683
684        expr = parseNameExpression();
685        if (token === Token.DOT_LT || token === Token.LT) {
686            next();
687            applications = parseTypeExpressionList();
688            expect(Token.GT);
689            return {
690                type: Syntax.TypeApplication,
691                expression: expr,
692                applications: applications
693            };
694        }
695        return expr;
696    }
697
698    // ResultType :=
699    //     <<empty>>
700    //   | ':' void
701    //   | ':' TypeExpression
702    //
703    // BNF is above
704    // but, we remove <<empty>> pattern, so token is always TypeToken::COLON
705    function parseResultType() {
706        consume(Token.COLON, 'ResultType should start with :');
707        if (token === Token.NAME && value === 'void') {
708            consume(Token.NAME);
709            return {
710                type: Syntax.VoidLiteral
711            };
712        }
713        return parseTypeExpression();
714    }
715
716    // ParametersType :=
717    //     RestParameterType
718    //   | NonRestParametersType
719    //   | NonRestParametersType ',' RestParameterType
720    //
721    // RestParameterType :=
722    //     '...'
723    //     '...' Identifier
724    //
725    // NonRestParametersType :=
726    //     ParameterType ',' NonRestParametersType
727    //   | ParameterType
728    //   | OptionalParametersType
729    //
730    // OptionalParametersType :=
731    //     OptionalParameterType
732    //   | OptionalParameterType, OptionalParametersType
733    //
734    // OptionalParameterType := ParameterType=
735    //
736    // ParameterType := TypeExpression | Identifier ':' TypeExpression
737    //
738    // Identifier is "new" or "this"
739    function parseParametersType() {
740        var params = [], optionalSequence = false, expr, rest = false;
741
742        while (token !== Token.RPAREN) {
743            if (token === Token.REST) {
744                // RestParameterType
745                consume(Token.REST);
746                rest = true;
747            }
748
749            expr = parseTypeExpression();
750            if (expr.type === Syntax.NameExpression && token === Token.COLON) {
751                // Identifier ':' TypeExpression
752                consume(Token.COLON);
753                expr = {
754                    type: Syntax.ParameterType,
755                    name: expr.name,
756                    expression: parseTypeExpression()
757                };
758            }
759            if (token === Token.EQUAL) {
760                consume(Token.EQUAL);
761                expr = {
762                    type: Syntax.OptionalType,
763                    expression: expr
764                };
765                optionalSequence = true;
766            } else {
767                if (optionalSequence) {
768                    utility.throwError('unexpected token');
769                }
770            }
771            if (rest) {
772                expr = {
773                    type: Syntax.RestType,
774                    expression: expr
775                };
776            }
777            params.push(expr);
778            if (token !== Token.RPAREN) {
779                expect(Token.COMMA);
780            }
781        }
782        return params;
783    }
784
785    // FunctionType := 'function' FunctionSignatureType
786    //
787    // FunctionSignatureType :=
788    //   | TypeParameters '(' ')' ResultType
789    //   | TypeParameters '(' ParametersType ')' ResultType
790    //   | TypeParameters '(' 'this' ':' TypeName ')' ResultType
791    //   | TypeParameters '(' 'this' ':' TypeName ',' ParametersType ')' ResultType
792    function parseFunctionType() {
793        var isNew, thisBinding, params, result, fnType;
794        utility.assert(token === Token.NAME && value === 'function', 'FunctionType should start with \'function\'');
795        consume(Token.NAME);
796
797        // Google Closure Compiler is not implementing TypeParameters.
798        // So we do not. if we don't get '(', we see it as error.
799        expect(Token.LPAREN);
800
801        isNew = false;
802        params = [];
803        thisBinding = null;
804        if (token !== Token.RPAREN) {
805            // ParametersType or 'this'
806            if (token === Token.NAME &&
807                    (value === 'this' || value === 'new')) {
808                // 'this' or 'new'
809                // 'new' is Closure Compiler extension
810                isNew = value === 'new';
811                consume(Token.NAME);
812                expect(Token.COLON);
813                thisBinding = parseTypeName();
814                if (token === Token.COMMA) {
815                    consume(Token.COMMA);
816                    params = parseParametersType();
817                }
818            } else {
819                params = parseParametersType();
820            }
821        }
822
823        expect(Token.RPAREN);
824
825        result = null;
826        if (token === Token.COLON) {
827            result = parseResultType();
828        }
829
830        fnType = {
831            type: Syntax.FunctionType,
832            params: params,
833            result: result
834        };
835        if (thisBinding) {
836            // avoid adding null 'new' and 'this' properties
837            fnType['this'] = thisBinding;
838            if (isNew) {
839                fnType['new'] = true;
840            }
841        }
842        return fnType;
843    }
844
845    // BasicTypeExpression :=
846    //     '*'
847    //   | 'null'
848    //   | 'undefined'
849    //   | TypeName
850    //   | FunctionType
851    //   | UnionType
852    //   | RecordType
853    //   | ArrayType
854    function parseBasicTypeExpression() {
855        var context;
856        switch (token) {
857        case Token.STAR:
858            consume(Token.STAR);
859            return {
860                type: Syntax.AllLiteral
861            };
862
863        case Token.LPAREN:
864            return parseUnionType();
865
866        case Token.LBRACK:
867            return parseArrayType();
868
869        case Token.LBRACE:
870            return parseRecordType();
871
872        case Token.NAME:
873            if (value === 'null') {
874                consume(Token.NAME);
875                return {
876                    type: Syntax.NullLiteral
877                };
878            }
879
880            if (value === 'undefined') {
881                consume(Token.NAME);
882                return {
883                    type: Syntax.UndefinedLiteral
884                };
885            }
886
887            if (value === 'true' || value === 'false') {
888                consume(Token.NAME);
889                return {
890                    type: Syntax.BooleanLiteralType,
891                    value: value === 'true'
892                };
893            }
894
895            context = Context.save();
896            if (value === 'function') {
897                try {
898                    return parseFunctionType();
899                } catch (e) {
900                    context.restore();
901                }
902            }
903
904            return parseTypeName();
905
906        case Token.STRING:
907            next();
908            return {
909                type: Syntax.StringLiteralType,
910                value: value
911            };
912
913        case Token.NUMBER:
914            next();
915            return {
916                type: Syntax.NumericLiteralType,
917                value: value
918            };
919
920        default:
921            utility.throwError('unexpected token');
922        }
923    }
924
925    // TypeExpression :=
926    //     BasicTypeExpression
927    //   | '?' BasicTypeExpression
928    //   | '!' BasicTypeExpression
929    //   | BasicTypeExpression '?'
930    //   | BasicTypeExpression '!'
931    //   | '?'
932    //   | BasicTypeExpression '[]'
933    function parseTypeExpression() {
934        var expr;
935
936        if (token === Token.QUESTION) {
937            consume(Token.QUESTION);
938            if (token === Token.COMMA || token === Token.EQUAL || token === Token.RBRACE ||
939                    token === Token.RPAREN || token === Token.PIPE || token === Token.EOF ||
940                    token === Token.RBRACK || token === Token.GT) {
941                return {
942                    type: Syntax.NullableLiteral
943                };
944            }
945            return {
946                type: Syntax.NullableType,
947                expression: parseBasicTypeExpression(),
948                prefix: true
949            };
950        }
951
952        if (token === Token.BANG) {
953            consume(Token.BANG);
954            return {
955                type: Syntax.NonNullableType,
956                expression: parseBasicTypeExpression(),
957                prefix: true
958            };
959        }
960
961        expr = parseBasicTypeExpression();
962        if (token === Token.BANG) {
963            consume(Token.BANG);
964            return {
965                type: Syntax.NonNullableType,
966                expression: expr,
967                prefix: false
968            };
969        }
970
971        if (token === Token.QUESTION) {
972            consume(Token.QUESTION);
973            return {
974                type: Syntax.NullableType,
975                expression: expr,
976                prefix: false
977            };
978        }
979
980        if (token === Token.LBRACK) {
981            consume(Token.LBRACK);
982            expect(Token.RBRACK, 'expected an array-style type declaration (' + value + '[])');
983            return {
984                type: Syntax.TypeApplication,
985                expression: {
986                    type: Syntax.NameExpression,
987                    name: 'Array'
988                },
989                applications: [expr]
990            };
991        }
992
993        return expr;
994    }
995
996    // TopLevelTypeExpression :=
997    //      TypeExpression
998    //    | TypeUnionList
999    //
1000    // This rule is Google Closure Compiler extension, not ES4
1001    // like,
1002    //   { number | string }
1003    // If strict to ES4, we should write it as
1004    //   { (number|string) }
1005    function parseTop() {
1006        var expr, elements;
1007
1008        expr = parseTypeExpression();
1009        if (token !== Token.PIPE) {
1010            return expr;
1011        }
1012
1013        elements = [expr];
1014        consume(Token.PIPE);
1015        while (true) {
1016            elements.push(parseTypeExpression());
1017            if (token !== Token.PIPE) {
1018                break;
1019            }
1020            consume(Token.PIPE);
1021        }
1022
1023        return {
1024            type: Syntax.UnionType,
1025            elements: elements
1026        };
1027    }
1028
1029    function parseTopParamType() {
1030        var expr;
1031
1032        if (token === Token.REST) {
1033            consume(Token.REST);
1034            return {
1035                type: Syntax.RestType,
1036                expression: parseTop()
1037            };
1038        }
1039
1040        expr = parseTop();
1041        if (token === Token.EQUAL) {
1042            consume(Token.EQUAL);
1043            return {
1044                type: Syntax.OptionalType,
1045                expression: expr
1046            };
1047        }
1048
1049        return expr;
1050    }
1051
1052    function parseType(src, opt) {
1053        var expr;
1054
1055        source = src;
1056        length = source.length;
1057        index = 0;
1058        previous = 0;
1059
1060        next();
1061        expr = parseTop();
1062
1063        if (opt && opt.midstream) {
1064            return {
1065                expression: expr,
1066                index: previous
1067            };
1068        }
1069
1070        if (token !== Token.EOF) {
1071            utility.throwError('not reach to EOF');
1072        }
1073
1074        return expr;
1075    }
1076
1077    function parseParamType(src, opt) {
1078        var expr;
1079
1080        source = src;
1081        length = source.length;
1082        index = 0;
1083        previous = 0;
1084
1085        next();
1086        expr = parseTopParamType();
1087
1088        if (opt && opt.midstream) {
1089            return {
1090                expression: expr,
1091                index: previous
1092            };
1093        }
1094
1095        if (token !== Token.EOF) {
1096            utility.throwError('not reach to EOF');
1097        }
1098
1099        return expr;
1100    }
1101
1102    function stringifyImpl(node, compact, topLevel) {
1103        var result, i, iz;
1104
1105        switch (node.type) {
1106        case Syntax.NullableLiteral:
1107            result = '?';
1108            break;
1109
1110        case Syntax.AllLiteral:
1111            result = '*';
1112            break;
1113
1114        case Syntax.NullLiteral:
1115            result = 'null';
1116            break;
1117
1118        case Syntax.UndefinedLiteral:
1119            result = 'undefined';
1120            break;
1121
1122        case Syntax.VoidLiteral:
1123            result = 'void';
1124            break;
1125
1126        case Syntax.UnionType:
1127            if (!topLevel) {
1128                result = '(';
1129            } else {
1130                result = '';
1131            }
1132
1133            for (i = 0, iz = node.elements.length; i < iz; ++i) {
1134                result += stringifyImpl(node.elements[i], compact);
1135                if ((i + 1) !== iz) {
1136                    result += '|';
1137                }
1138            }
1139
1140            if (!topLevel) {
1141                result += ')';
1142            }
1143            break;
1144
1145        case Syntax.ArrayType:
1146            result = '[';
1147            for (i = 0, iz = node.elements.length; i < iz; ++i) {
1148                result += stringifyImpl(node.elements[i], compact);
1149                if ((i + 1) !== iz) {
1150                    result += compact ? ',' : ', ';
1151                }
1152            }
1153            result += ']';
1154            break;
1155
1156        case Syntax.RecordType:
1157            result = '{';
1158            for (i = 0, iz = node.fields.length; i < iz; ++i) {
1159                result += stringifyImpl(node.fields[i], compact);
1160                if ((i + 1) !== iz) {
1161                    result += compact ? ',' : ', ';
1162                }
1163            }
1164            result += '}';
1165            break;
1166
1167        case Syntax.FieldType:
1168            if (node.value) {
1169                result = node.key + (compact ? ':' : ': ') + stringifyImpl(node.value, compact);
1170            } else {
1171                result = node.key;
1172            }
1173            break;
1174
1175        case Syntax.FunctionType:
1176            result = compact ? 'function(' : 'function (';
1177
1178            if (node['this']) {
1179                if (node['new']) {
1180                    result += (compact ? 'new:' : 'new: ');
1181                } else {
1182                    result += (compact ? 'this:' : 'this: ');
1183                }
1184
1185                result += stringifyImpl(node['this'], compact);
1186
1187                if (node.params.length !== 0) {
1188                    result += compact ? ',' : ', ';
1189                }
1190            }
1191
1192            for (i = 0, iz = node.params.length; i < iz; ++i) {
1193                result += stringifyImpl(node.params[i], compact);
1194                if ((i + 1) !== iz) {
1195                    result += compact ? ',' : ', ';
1196                }
1197            }
1198
1199            result += ')';
1200
1201            if (node.result) {
1202                result += (compact ? ':' : ': ') + stringifyImpl(node.result, compact);
1203            }
1204            break;
1205
1206        case Syntax.ParameterType:
1207            result = node.name + (compact ? ':' : ': ') + stringifyImpl(node.expression, compact);
1208            break;
1209
1210        case Syntax.RestType:
1211            result = '...';
1212            if (node.expression) {
1213                result += stringifyImpl(node.expression, compact);
1214            }
1215            break;
1216
1217        case Syntax.NonNullableType:
1218            if (node.prefix) {
1219                result = '!' + stringifyImpl(node.expression, compact);
1220            } else {
1221                result = stringifyImpl(node.expression, compact) + '!';
1222            }
1223            break;
1224
1225        case Syntax.OptionalType:
1226            result = stringifyImpl(node.expression, compact) + '=';
1227            break;
1228
1229        case Syntax.NullableType:
1230            if (node.prefix) {
1231                result = '?' + stringifyImpl(node.expression, compact);
1232            } else {
1233                result = stringifyImpl(node.expression, compact) + '?';
1234            }
1235            break;
1236
1237        case Syntax.NameExpression:
1238            result = node.name;
1239            break;
1240
1241        case Syntax.TypeApplication:
1242            result = stringifyImpl(node.expression, compact) + '.<';
1243            for (i = 0, iz = node.applications.length; i < iz; ++i) {
1244                result += stringifyImpl(node.applications[i], compact);
1245                if ((i + 1) !== iz) {
1246                    result += compact ? ',' : ', ';
1247                }
1248            }
1249            result += '>';
1250            break;
1251
1252        case Syntax.StringLiteralType:
1253            result = '"' + node.value + '"';
1254            break;
1255
1256        case Syntax.NumericLiteralType:
1257            result = String(node.value);
1258            break;
1259
1260        case Syntax.BooleanLiteralType:
1261            result = String(node.value);
1262            break;
1263
1264        default:
1265            utility.throwError('Unknown type ' + node.type);
1266        }
1267
1268        return result;
1269    }
1270
1271    function stringify(node, options) {
1272        if (options == null) {
1273            options = {};
1274        }
1275        return stringifyImpl(node, options.compact, options.topLevel);
1276    }
1277
1278    exports.parseType = parseType;
1279    exports.parseParamType = parseParamType;
1280    exports.stringify = stringify;
1281    exports.Syntax = Syntax;
1282}());
1283/* vim: set sw=4 ts=4 et tw=80 : */
1284
Full Screen

Accelerate Your Automation Test Cycles With LambdaTest

Leverage LambdaTest’s cloud-based platform to execute your automation tests in parallel and trim down your test execution time significantly. Your first 100 automation testing minutes are on us.

Try LambdaTest

Run JavaScript Tests on LambdaTest Cloud Grid

Execute automation tests with Playwright Internal on a cloud-based Grid of 3000+ real browsers and operating systems for both web and mobile applications.

Test now for Free
LambdaTestX

We use cookies to give you the best experience. Cookies help to provide a more personalized experience and relevant advertising for you, and web analytics for us. Learn More in our Cookies policy, Privacy & Terms of service

Allow Cookie
Sarah

I hope you find the best code examples for your project.

If you want to accelerate automated browser testing, try LambdaTest. Your first 100 automation testing minutes are FREE.

Sarah Elson (Product & Growth Lead)