MCPcopy Index your code
hub / github.com/nodejs/node / getFirstExpression

Function getFirstExpression

lib/internal/errors/error_source.js:70–142  ·  view source on GitHub ↗

* Get the first expression in a code string at the startColumn. * @param {string} code source code line * @param {number} startColumn which column the error is constructed * @returns {string}

(code, startColumn)

Source from the content-addressed store, hash-verified

68 * @returns {string}
69 */
70function getFirstExpression(code, startColumn) {
71 // Lazy load acorn.
72 if (tokenizer === undefined) {
73 const Parser = require('internal/deps/acorn/acorn/dist/acorn').Parser;
74 tokenizer = FunctionPrototypeBind(Parser.tokenizer, Parser);
75 }
76
77 let lastToken;
78 let firstMemberAccessNameToken;
79 let terminatingCol;
80 let parenLvl = 0;
81 // Tokenize the line to locate the expression at the startColumn.
82 // The source line may be an incomplete JavaScript source, so do not parse the source line.
83 for (const token of tokenizer(code, { ecmaVersion: 'latest' })) {
84 // Peek before the startColumn.
85 if (token.start < startColumn) {
86 // There is a semicolon. This is a statement before the startColumn, so reset the memo.
87 if (token.type.label === ';') {
88 firstMemberAccessNameToken = null;
89 continue;
90 }
91 // Try to memo the member access expressions before the startColumn, so that the
92 // returned source code contains more info:
93 // assert.ok(value)
94 // ^ startColumn
95 // The member expression can also be like
96 // assert['ok'](value) or assert?.ok(value)
97 // ^ startColumn ^ startColumn
98 if (memberAccessTokens.includes(token.type.label) && lastToken?.type.label === 'name') {
99 // First member access name token must be a 'name'.
100 firstMemberAccessNameToken ??= lastToken;
101 } else if (!memberAccessTokens.includes(token.type.label) &&
102 !memberNameTokens.includes(token.type.label)) {
103 // Reset the memo if it is not a simple member access.
104 // For example: assert[(() => 'ok')()](value)
105 // ^ startColumn
106 firstMemberAccessNameToken = null;
107 }
108 lastToken = token;
109 continue;
110 }
111 // Now after the startColumn, this must be an expression.
112 if (token.type.label === '(') {
113 parenLvl++;
114 continue;
115 }
116 if (token.type.label === ')') {
117 parenLvl--;
118 if (parenLvl === 0) {
119 // A matched closing parenthesis found after the startColumn,
120 // terminate here. Include the token.
121 // (assert.ok(false), assert.ok(true))
122 // ^ startColumn
123 terminatingCol = token.start + 1;
124 break;
125 }
126 continue;
127 }

Callers 1

getErrorSourceExpressionFunction · 0.85

Calls 2

includesMethod · 0.80
requireFunction · 0.50

Tested by

no test coverage detected

Used in the wild real call sites across dependent graphs

searching dependent graphs…