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

microsoft / botbuilder-js / 3706780471

pending completion
3706780471

push

github

GitHub
chore(deps): bump express (#4390)

9686 of 12680 branches covered (76.39%)

Branch coverage included in aggregate %.

19968 of 22357 relevant lines covered (89.31%)

3197.88 hits per line

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

84.48
/libraries/botbuilder-lg/src/templateExtensions.ts
1
/* eslint-disable security/detect-object-injection */
2
/**
3
 * @module botbuilder-lg
4
 */
5
/**
6
 * Copyright (c) Microsoft Corporation. All rights reserved.
7
 * Licensed under the MIT License.
8
 */
9

10
import * as path from 'path';
1✔
11
import { ParserRuleContext } from 'antlr4ts';
12
import { Position } from './position';
1✔
13
import { Range } from './range';
1✔
14
import { v4 as uuidv4 } from 'uuid';
1✔
15

16
import {
1✔
17
    IfConditionRuleContext,
18
    KeyValueStructureValueContext,
19
    NormalTemplateStringContext,
20
    SwitchCaseRuleContext,
21
} from './generated/LGTemplateParser';
22

23
/**
24
 * Extension methods for LG.
25
 */
26
export class TemplateExtensions {
1✔
27
    /**
28
     * Trim expression. ${abc} => abc,  ${a == {}} => a == {}.
29
     *
30
     * @param expression Input expression string.
31
     * @returns Pure expression string.
32
     */
33
    static trimExpression(expression: string): string {
34
        let result = expression.trim();
2,794✔
35
        if (result.startsWith('$')) {
2,794!
36
            result = result.substr(1);
2,794✔
37
        }
38

39
        result = result.trim();
2,794✔
40

41
        if (result.startsWith('{') && result.endsWith('}')) {
2,794!
42
            result = result.substr(1, result.length - 2);
2,794✔
43
        }
44

45
        return result.trim();
2,794✔
46
    }
47

48
    /**
49
     * Normalize authored path to os path.
50
     * path is from authored content which doesn't know what OS it is running on.
51
     * This method treats / and \ both as seperators regardless of OS, for windows that means / -> \ and for linux/mac \ -> /.
52
     * This allows author to use ../foo.lg or ..\foo.lg as equivelents for importing.
53
     *
54
     * @param ambiguousPath AuthoredPath.
55
     * @returns Path expressed as OS path.
56
     */
57
    static normalizePath(ambiguousPath: string): string {
58
        if (process.platform === 'win32') {
216!
59
            // map linux/mac sep -> windows
60
            return path.normalize(ambiguousPath.replace(/\//g, '\\'));
×
61
        } else {
62
            // map windows sep -> linux/mac
63
            return path.normalize(ambiguousPath.replace(/\\/g, '/'));
216✔
64
        }
65
    }
66

67
    /**
68
     * Get prefix error message from normal template sting context.
69
     *
70
     * @param context Normal template sting context.
71
     * @returns Prefix error message.
72
     */
73
    static getPrefixErrorMessage(context: NormalTemplateStringContext): string {
74
        let errorPrefix = '';
3,976✔
75
        if (context.parent && context.parent.parent && context.parent.parent.parent) {
3,976!
76
            if (context.parent.parent.parent instanceof IfConditionRuleContext) {
3,976✔
77
                const conditionContext = context.parent.parent.parent;
294✔
78
                let tempMsg = '';
294✔
79
                if (conditionContext.ifCondition() && conditionContext.ifCondition().expression().length > 0) {
294✔
80
                    tempMsg = conditionContext.ifCondition().expression(0).text;
172✔
81
                    errorPrefix = "Condition '" + tempMsg + "': ";
172✔
82
                }
83
            } else {
84
                if (context.parent.parent.parent instanceof SwitchCaseRuleContext) {
3,682✔
85
                    const switchCaseContext = context.parent.parent.parent;
58✔
86
                    const state = switchCaseContext.switchCaseStat();
58✔
87
                    if (state && state.DEFAULT()) {
58✔
88
                        errorPrefix = "Case 'Default':";
19✔
89
                    } else if (state && state.SWITCH()) {
39!
90
                        let tempMsg = '';
×
91
                        if (state.expression(0)) {
×
92
                            tempMsg = state.expression(0).text;
×
93
                        }
94
                        errorPrefix = `Switch '${tempMsg} ':`;
×
95
                    } else if (state && state.CASE()) {
39!
96
                        let tempMsg = '';
39✔
97
                        if (state.expression(0)) {
39!
98
                            tempMsg = state.expression(0).text;
39✔
99
                        }
100
                        errorPrefix = `Case '${tempMsg}':`;
39✔
101
                    }
102
                }
103
            }
104
        }
105

106
        return errorPrefix;
3,976✔
107
    }
108

109
    /**
110
     * If a value is pure Expression.
111
     *
112
     * @param ctx Key value structure value context.
113
     * @returns True if the value is pure Expression, false otherwise.
114
     */
115
    static isPureExpression(ctx: KeyValueStructureValueContext): boolean {
116
        if (ctx.expressionInStructure() === undefined || ctx.expressionInStructure().length != 1) {
269✔
117
            return false;
109✔
118
        }
119

120
        return ctx.expressionInStructure(0).text.trim() === ctx.text.trim();
160✔
121
    }
122

123
    /**
124
     * Escape \ from text.
125
     *
126
     * @param exp Input text.
127
     * @returns Escaped text.
128
     */
129
    static evalEscape(exp: string): string {
130
        const validCharactersDict: Record<string, string> = {
37✔
131
            '\\r': '\r',
132
            '\\n': '\n',
133
            '\\t': '\t',
134
            '\\\\': '\\',
135
        };
136

137
        return exp.replace(/\\[^\r\n]?/g, (sub: string): string => {
37✔
138
            if (sub in validCharactersDict) {
33✔
139
                return validCharactersDict[sub];
8✔
140
            } else if (sub === '\\$') {
25✔
141
                return sub.substr(1);
12✔
142
            } else if (sub === '\\`') {
13✔
143
                return sub.substr(1);
2✔
144
            } else {
145
                return sub;
11✔
146
            }
147
        });
148
    }
149

150
    /**
151
     * Generate new guid string.
152
     *
153
     * @returns The new guid string.
154
     */
155
    static newGuid(): string {
156
        return uuidv4();
18✔
157
    }
158

159
    /**
160
     * Read line from text.
161
     *
162
     * @param input Text content.
163
     * @returns Split read line.
164
     */
165
    static readLine(input: string): string[] {
166
        if (!input) {
41!
167
            return [];
×
168
        }
169

170
        return input.replace(/\r\n/g, '\n').split('\n');
41✔
171
    }
172

173
    /**
174
     * Convert antlr parser into Range.
175
     *
176
     * @param context Antlr parse context.
177
     * @param [lineOffset] Line offset.
178
     * @returns Range object.
179
     */
180
    static convertToRange(context: ParserRuleContext, lineOffset?: number): Range {
181
        if (!lineOffset) {
2,144✔
182
            lineOffset = 0;
2,076✔
183
        }
184
        if (!context) {
2,144!
185
            return Range.DefaultRange;
×
186
        }
187

188
        const startPosition = new Position(lineOffset + context.start.line, context.start.charPositionInLine);
2,144✔
189
        const stopPosition = new Position(
2,144✔
190
            lineOffset + context.stop.line,
191
            context.stop.charPositionInLine + context.stop.text.length
192
        );
193

194
        return new Range(startPosition, stopPosition);
2,144✔
195
    }
196
}
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