+
+ `
+
+ const queries = [
+ `
+ <$$
+ $$={()=>{}}
+ />
+ `,
+ `
+ <$$
+ $$={[]}
+ />
+ `,
+ `
+ <$$
+ $$={{}}
+ />
+ `,
+ ]
+
+ const { matches, errors } = searchInStrings({
+ mode: 'include',
+ files: [{ content: fileContent, path: '' }],
+ queryCodes: queries,
+ })
+
+ expect(errors).toHaveLength(0)
+ expect(matches.length).toBe(3)
+ })
+})
diff --git a/packages/core/__tests__/JavaScriptWithJSX/other/astUtils.test.ts b/packages/core/__tests__/JavaScriptWithJSX/other/astUtils.test.ts
new file mode 100644
index 0000000..76ecc39
--- /dev/null
+++ b/packages/core/__tests__/JavaScriptWithJSX/other/astUtils.test.ts
@@ -0,0 +1,150 @@
+import { compareCode } from '../../utils'
+import { createWildcardUtils } from '../../../src/wildcardUtilsFactory'
+import { PoorNodeType } from '../../../src/types'
+import { sortByLeastIdentifierStrength } from '../../../src/astUtils'
+
+describe('AST utils', () => {
+ it('should compare code as equal', () => {
+ const code1 = `
+ import * as React from 'react';
+ import { Paragraph, Button, Portal, Dialog, Colors } from 'react-native-paper';
+
+ const DialogWithCustomColors = ({
+ visible,
+ close,
+ }) => (
+
+
+ Alert
+
+
+ This is a dialog with custom colors
+
+
+
+ OK
+
+
+
+ );
+
+ export default DialogWithCustomColors;
+ `
+
+ const code2 = `
+ import * as React from 'react';
+ import {
+ Paragraph,
+ Button,
+ Portal,
+ Dialog,
+ Colors
+ } from 'react-native-paper';
+
+ const DialogWithCustomColors = ({
+ visible,
+ close,
+ }) => (
+
+
+ Alert
+
+ This is a dialog with custom colors
+
+
+
+ OK
+
+
+
+
+ );
+
+ export default DialogWithCustomColors;
+ `
+ expect(compareCode(code1, code2)).toBeTruthy()
+ })
+
+ it('should compare code as unequal', () => {
+ const code1 = `
+ import * as React from 'react';
+ import { Paragraph, Button, Portal, Dialog, Colors } from 'react-native-paper';
+
+ const DialogWithCustomColors = ({
+ visible,
+ close,
+ }) => (
+
+
+ Alert
+
+
+ This is a dialog with custom colors
+
+
+
+
+ OK
+
+
+
+
+ );
+
+ export default DialogWithCustomColors;
+ `
+
+ const code2 =
+ // no Colors import
+
+ `
+ import * as React from 'react';
+ import {
+ Paragraph,
+ Button,
+ Portal,
+ Dialog
+ } from 'react-native-paper';
+
+ const DialogWithCustomColors = ({
+ visible,
+ close,
+ }) => (
+
+
+ Alert
+
+
+ This is a dialog with custom colors
+
+
+
+
+ OK
+
+
+
+
+ );
+
+ export default DialogWithCustomColors;
+ `
+ expect(compareCode(code1, code2)).toBe(false)
+ })
+})
diff --git a/packages/core/__tests__/JavaScriptWithJSX/other/parseQuery.test.ts b/packages/core/__tests__/JavaScriptWithJSX/other/parseQuery.test.ts
new file mode 100644
index 0000000..4b2fb94
--- /dev/null
+++ b/packages/core/__tests__/JavaScriptWithJSX/other/parseQuery.test.ts
@@ -0,0 +1,55 @@
+import { getUniqueTokens, extractQueryNode } from '../../../src/parseQuery'
+import { getParserSettings } from '../../utils'
+
+describe('parse query', () => {
+ const parserSettings = getParserSettings()
+
+ it('should get unique tokens', () => {
+ const queryCode = `
+ require('some$$wildcard$$string')
+ const a = 'b'
+ const alpha = 'beta'
+ (
)
+ 123;
+ pre$$_ref1_post
+ $$_ref1_content$$_ref2
+ asd$$_invalidRef_$$
+ asd$$_invalidRef$$
+ {
+ {
+ () => {
+ 0x0;
+ return 'test'
+ }
+ }
+ }
+ f('some$$_ref1_tttt$$_ref2')
+ `
+ const { queryNode } = extractQueryNode(
+ parserSettings.parseCode(queryCode),
+ parserSettings,
+ )
+
+ const uniqueTokens = [...getUniqueTokens(queryNode, false, parserSettings)]
+
+ expect(uniqueTokens).toMatchObject([
+ 'require',
+ 'some',
+ 'wildcard',
+ 'string',
+ 'alpha',
+ 'beta',
+ 'SomeJSX',
+ '123',
+ 'pre',
+ 'post',
+ 'content',
+ 'asd',
+ '_invalidRef_',
+ '_invalidRef',
+ 'test',
+ // 'some', // only 'tttt' is new
+ 'tttt',
+ ])
+ })
+})
diff --git a/packages/core/__tests__/Lua/matchCodePatterns/basic.test.ts b/packages/core/__tests__/Lua/matchCodePatterns/basic.test.ts
new file mode 100644
index 0000000..962f442
--- /dev/null
+++ b/packages/core/__tests__/Lua/matchCodePatterns/basic.test.ts
@@ -0,0 +1,203 @@
+import { searchInStrings } from '../../../src/searchInStrings'
+import { getParserSettings, compareCode } from '../../utils'
+
+describe('Basic queries', () => {
+ beforeAll(async () => {
+ await getParserSettings().init?.()
+ })
+
+ it('Should exact match identifier', async () => {
+ const fileContent = `
+ print
+ `
+ const queries = [fileContent]
+
+ const { matches, errors } = searchInStrings({
+ mode: 'exact',
+ caseInsensitive: true,
+ queryCodes: queries,
+ files: [
+ {
+ path: 'mock',
+ content: fileContent,
+ },
+ ],
+ })
+
+ expect(errors).toHaveLength(0)
+ expect(matches.length).toBe(1)
+ })
+
+ it('Should exact match function definition', () => {
+ const fileContent = `
+ function fact (n)
+ if n == 0 then
+ return 1
+ else
+ return n * fact(n-1)
+ end
+ end
+ `
+ const queries = [fileContent]
+
+ const { matches, errors } = searchInStrings({
+ mode: 'exact',
+ caseInsensitive: true,
+ queryCodes: queries,
+ files: [
+ {
+ path: 'mock',
+ content: fileContent,
+ },
+ ],
+ })
+
+ expect(errors).toHaveLength(0)
+ expect(matches.length).toBe(1)
+ })
+
+ it('Should partial match function definition', () => {
+ const fileContent = `
+ function fact (n)
+ if n == 0 then
+ return 1
+ else
+ return n * fact(n-1)
+ end
+ end
+ `
+ const queries = [
+ `
+ function fact (n)
+ if n == 0 then
+ return 1
+ end
+ end
+ `,
+ ]
+
+ const { matches, errors } = searchInStrings({
+ mode: 'include',
+ caseInsensitive: true,
+ queryCodes: queries,
+ files: [
+ {
+ path: 'mock',
+ content: fileContent,
+ },
+ ],
+ })
+
+ expect(errors).toHaveLength(0)
+ expect(matches.length).toBe(1)
+ })
+
+ it('Should match multiline', () => {
+ const fileContent = `
+ function setupWS(mode, transmit, setChannel)
+ local deviceType = mode == "TX" and "transmitter" or "receiver"
+ local url = "ws://" .. loraServerAddress .. "/" .. deviceType
+ local headers = {["Authorization"] = "Basic ZnJvZzpoYWt1bmFtYXRhdGE0MzM="}
+ local ws = wsModule(url, headers)
+ local transmitEvent = "SEND_" .. (mode == "TX" and "TRANSMITTER" or "RECEIVER")
+ local transmissionParamsEvent = "TRANSMISSION_PARAMS_" .. (mode == "TX" and "TRANSMITTER" or "RECEIVER")
+
+ ws.on(
+ transmitEvent,
+ function(data)
+ transmit(data.loraPktData)
+ ws.send(transmitEvent .. "_ACK", true)
+ end
+ )
+
+ ws.on(
+ transmissionParamsEvent,
+ function(data)
+ data.spreadingFactor = "SF" .. data.spreadingFactor
+ local saveResult = config.saveConfig(data)
+ setChannel(config.computeFrequency(data.frequency), data.spreadingFactor, data.errorCorrection)
+ ws.send(transmissionParamsEvent .. "_ACK", saveResult)
+ end
+ )
+
+ return function(data)
+ local event = mode == "TX" and "TRANSMITTER_DATA" or "RECEIVER_DATA"
+ ws.send(event, data)
+ end
+ end
+ `
+
+ const queries = [
+ `
+ local transmitEvent = "SEND_" .. (mode == "TX" and "TRANSMITTER" or "RECEIVER")
+ local transmissionParamsEvent = "TRANSMISSION_PARAMS_" .. (mode == "TX" and "TRANSMITTER" or "RECEIVER")
+
+ ws.on(
+ transmissionParamsEvent,
+ function(data)
+ data.spreadingFactor = "SF" .. data.spreadingFactor
+ local saveResult = config.saveConfig(data)
+ setChannel(config.computeFrequency(data.frequency), data.spreadingFactor, data.errorCorrection)
+ ws.send(transmissionParamsEvent .. "_ACK", saveResult)
+ end
+ )
+ `,
+ ]
+
+ const { matches, errors } = searchInStrings({
+ mode: 'include',
+ caseInsensitive: true,
+ queryCodes: queries,
+ files: [
+ {
+ path: 'mock',
+ content: fileContent,
+ },
+ ],
+ })
+
+ expect(errors).toHaveLength(0)
+ expect(matches.length).toBe(1)
+
+ const match = matches[0]
+
+ expect(match.loc).toMatchObject({
+ start: { line: 7, column: 6 },
+ end: { line: 26, column: 7 },
+ })
+ })
+
+ it('Should match tuple', () => {
+ const fileContent = `
+ local var = 1,"text"
+ `
+
+ const queries = [
+ `
+ 1,"text"
+ `,
+ ]
+
+ const { matches, errors } = searchInStrings({
+ mode: 'include',
+ caseInsensitive: true,
+ queryCodes: queries,
+ files: [
+ {
+ path: 'mock',
+ content: fileContent,
+ },
+ ],
+ })
+
+ expect(errors).toHaveLength(0)
+ expect(matches.length).toBe(1)
+
+ const match = matches[0]
+
+ expect(match.loc).toStrictEqual({
+ start: { line: 2, column: 18, index: 19 },
+ end: { line: 2, column: 26, index: 27 },
+ })
+ })
+})
diff --git a/packages/core/__tests__/Lua/matchCodePatterns/binaryExpression.test.ts b/packages/core/__tests__/Lua/matchCodePatterns/binaryExpression.test.ts
new file mode 100644
index 0000000..b3a91f4
--- /dev/null
+++ b/packages/core/__tests__/Lua/matchCodePatterns/binaryExpression.test.ts
@@ -0,0 +1,37 @@
+import { searchInStrings } from '../../../src/searchInStrings'
+import { getParserSettings, compareCode } from '../../utils'
+
+describe('Binary Expression', () => {
+ beforeAll(async () => {
+ await getParserSettings().init?.()
+ })
+
+ it('Should binary expression based on operator (which is not defined by tree-sitter)', async () => {
+ const fileContent = `
+ local var = a ^ b
+ local var = a * b
+ local var = a and b
+ `
+ const queries = [
+ `
+ local var = a*b
+ `,
+ ]
+
+ const { matches, errors } = searchInStrings({
+ mode: 'exact',
+ caseInsensitive: true,
+ queryCodes: queries,
+ files: [
+ {
+ path: 'mock',
+ content: fileContent,
+ },
+ ],
+ })
+
+ expect(errors).toHaveLength(0)
+ expect(matches.length).toBe(1)
+ expect(matches[0].code).toBe('local var = a * b')
+ })
+})
diff --git a/packages/core/__tests__/Lua/matchCodePatterns/functions.test.ts b/packages/core/__tests__/Lua/matchCodePatterns/functions.test.ts
new file mode 100644
index 0000000..53ed420
--- /dev/null
+++ b/packages/core/__tests__/Lua/matchCodePatterns/functions.test.ts
@@ -0,0 +1,39 @@
+import { searchInStrings } from '../../../src/searchInStrings'
+import { getParserSettings, compareCode } from '../../utils'
+
+describe('Functions', () => {
+ beforeAll(async () => {
+ await getParserSettings().init?.()
+ })
+
+ it('Should match anonymous function passed as parameter by query with function declaration without name', async () => {
+ const fileContent = `
+ passCallback(function (a)
+ return a
+ end
+ )
+ `
+ const queries = [
+ `
+ function (a)
+ return a
+ end
+ `,
+ ]
+
+ const { matches, errors } = searchInStrings({
+ mode: 'exact',
+ caseInsensitive: true,
+ queryCodes: queries,
+ files: [
+ {
+ path: 'mock',
+ content: fileContent,
+ },
+ ],
+ })
+
+ expect(errors).toHaveLength(0)
+ expect(matches.length).toBe(1)
+ })
+})
diff --git a/packages/core/__tests__/Lua/matchCodePatterns/ifstatement.test.ts b/packages/core/__tests__/Lua/matchCodePatterns/ifstatement.test.ts
new file mode 100644
index 0000000..13e72ef
--- /dev/null
+++ b/packages/core/__tests__/Lua/matchCodePatterns/ifstatement.test.ts
@@ -0,0 +1,34 @@
+import { searchInStrings } from '../../../src/searchInStrings'
+import { getParserSettings, compareCode } from '../../utils'
+
+describe('If statement', () => {
+ beforeAll(async () => {
+ await getParserSettings().init?.()
+ })
+
+ it('Should match any if statement ', async () => {
+ const fileContent = `
+ if (a) then b() else c() end
+ `
+ const queries = [
+ `
+ if () then else end
+ `,
+ ]
+
+ const { matches, errors } = searchInStrings({
+ mode: 'include',
+ caseInsensitive: true,
+ queryCodes: queries,
+ files: [
+ {
+ path: 'mock',
+ content: fileContent,
+ },
+ ],
+ })
+
+ expect(errors).toHaveLength(0)
+ expect(matches.length).toBe(1)
+ })
+})
diff --git a/packages/core/__tests__/Lua/matchCodePatterns/literals.test.ts b/packages/core/__tests__/Lua/matchCodePatterns/literals.test.ts
new file mode 100644
index 0000000..8088de4
--- /dev/null
+++ b/packages/core/__tests__/Lua/matchCodePatterns/literals.test.ts
@@ -0,0 +1,149 @@
+import { searchInStrings } from '../../../src/searchInStrings'
+import { getParserSettings } from '../../utils'
+
+describe('Literals', () => {
+ beforeAll(async () => {
+ await getParserSettings().init?.()
+ })
+
+ it('Should match string literal', () => {
+ const fileContent = `
+ ws.on(
+ transmitEvent,
+ function(data)
+ transmit(data.loraPktData)
+ ws.send(transmitEvent .. "_ACK", true)
+ end
+ )
+ `
+
+ const queries = [
+ `
+ '_ACK'
+ `,
+ ]
+
+ const { matches, errors } = searchInStrings({
+ mode: 'include',
+ caseInsensitive: true,
+ queryCodes: queries,
+ files: [
+ {
+ path: 'mock',
+ content: fileContent,
+ },
+ ],
+ })
+
+ expect(errors).toHaveLength(0)
+ expect(matches.length).toBe(1)
+ })
+
+ it('Should exact match template string literal', () => {
+ const fileContent = `
+ f"project:{self.project_id}:rules"
+ `
+
+ const queries = [
+ `
+ f"project:{self.project_id}:rules"
+ `,
+ ]
+
+ const { matches, errors } = searchInStrings({
+ mode: 'include',
+ caseInsensitive: true,
+ queryCodes: queries,
+ files: [
+ {
+ path: 'mock',
+ content: fileContent,
+ },
+ ],
+ })
+
+ expect(errors).toHaveLength(0)
+ expect(matches.length).toBe(1)
+ })
+
+ it('Should match Integer literal', () => {
+ const fileContent = `
+ val = 123
+ `
+
+ const queries = [
+ `
+ 123
+ `,
+ ]
+
+ const { matches, errors } = searchInStrings({
+ mode: 'include',
+ caseInsensitive: true,
+ queryCodes: queries,
+ files: [
+ {
+ path: 'mock',
+ content: fileContent,
+ },
+ ],
+ })
+
+ expect(errors).toHaveLength(0)
+ expect(matches.length).toBe(1)
+ })
+
+ it('Should match Float literal', () => {
+ const fileContent = `
+ val = 123.123
+ `
+
+ const queries = [
+ `
+ 123.123
+ `,
+ ]
+
+ const { matches, errors } = searchInStrings({
+ mode: 'include',
+ caseInsensitive: true,
+ queryCodes: queries,
+ files: [
+ {
+ path: 'mock',
+ content: fileContent,
+ },
+ ],
+ })
+
+ expect(errors).toHaveLength(0)
+ expect(matches.length).toBe(1)
+ })
+
+ it('Should match Hex literal', () => {
+ const fileContent = `
+ val = 0xFF
+ `
+
+ const queries = [
+ `
+ 0xFF
+ `,
+ ]
+
+ const { matches, errors } = searchInStrings({
+ mode: 'include',
+ caseInsensitive: true,
+ queryCodes: queries,
+ files: [
+ {
+ path: 'mock',
+ content: fileContent,
+ },
+ ],
+ })
+
+ expect(errors).toHaveLength(0)
+ expect(matches.length).toBe(1)
+ })
+})
diff --git a/packages/core/__tests__/Lua/matchCodePatterns/table.test.ts b/packages/core/__tests__/Lua/matchCodePatterns/table.test.ts
new file mode 100644
index 0000000..9326f9b
--- /dev/null
+++ b/packages/core/__tests__/Lua/matchCodePatterns/table.test.ts
@@ -0,0 +1,112 @@
+import { searchInStrings } from '../../../src/searchInStrings'
+import { getParserSettings, compareCode } from '../../utils'
+
+describe('Tables', () => {
+ beforeAll(async () => {
+ await getParserSettings().init?.()
+ })
+
+ it('Should match table with keys exact', async () => {
+ const fileContent = `
+ local header = {
+ operationType = sdLib.operationTypeNumbers.repeater_telemetry,
+ transactionNumber = "0"
+ }
+ `
+
+ const queries = [
+ `
+ {
+ operationType = sdLib.operationTypeNumbers.repeater_telemetry,
+ transactionNumber = "0"
+ }
+ `,
+ ]
+
+ const { matches, errors } = searchInStrings({
+ mode: 'exact',
+ caseInsensitive: true,
+ queryCodes: queries,
+ files: [
+ {
+ path: 'mock',
+ content: fileContent,
+ },
+ ],
+ })
+
+ expect(errors).toHaveLength(0)
+ expect(matches.length).toBe(1)
+
+ expect(matches[0].loc).toMatchObject({
+ start: {
+ line: 2,
+ column: 21,
+ },
+ end: { line: 5, column: 7 },
+ })
+ })
+
+ it('Should match table with keys partial', async () => {
+ const fileContent = `
+ local header = {
+ operationType = sdLib.operationTypeNumbers.repeater_telemetry,
+ transactionNumber = "0"
+ }
+ `
+
+ const queries = [
+ `
+ {
+ transactionNumber = "0"
+ }
+ `,
+ ]
+
+ const { matches, errors } = searchInStrings({
+ mode: 'include',
+ caseInsensitive: true,
+ queryCodes: queries,
+ files: [
+ {
+ path: 'mock',
+ content: fileContent,
+ },
+ ],
+ })
+
+ expect(errors).toHaveLength(0)
+ expect(matches.length).toBe(1)
+ })
+
+ it('Should match table with values exact', async () => {
+ const fileContent = `
+ local header = {
+ "text", 123, {nested = 'table'}
+ }
+ `
+
+ const queries = [
+ `
+ {
+ "text", 123, {nested = "table"}
+ }
+ `,
+ ]
+
+ const { matches, errors } = searchInStrings({
+ mode: 'exact',
+ caseInsensitive: true,
+ queryCodes: queries,
+ files: [
+ {
+ path: 'mock',
+ content: fileContent,
+ },
+ ],
+ })
+
+ expect(errors).toHaveLength(0)
+ expect(matches.length).toBe(1)
+ })
+})
diff --git a/packages/core/__tests__/Lua/matchCodePatterns/wildcards.test.ts b/packages/core/__tests__/Lua/matchCodePatterns/wildcards.test.ts
new file mode 100644
index 0000000..715b32d
--- /dev/null
+++ b/packages/core/__tests__/Lua/matchCodePatterns/wildcards.test.ts
@@ -0,0 +1,154 @@
+import { searchInStrings } from '../../../src/searchInStrings'
+import { getParserSettings } from '../../utils'
+
+describe('Wildcards', () => {
+ beforeAll(async () => {
+ await getParserSettings().init?.()
+ })
+
+ it('Should match string wildcard', () => {
+ const fileContent = `
+ ws.on(
+ transmitEvent,
+ function(data)
+ transmit(data.loraPktData)
+ ws.send(transmitEvent .. "_ACK", true)
+ end
+ )
+ `
+
+ const queries = [
+ `
+ "_$$K"
+ `,
+ ]
+
+ const { matches, errors } = searchInStrings({
+ mode: 'include',
+ caseInsensitive: true,
+ queryCodes: queries,
+ files: [
+ {
+ path: 'mock',
+ content: fileContent,
+ },
+ ],
+ })
+
+ expect(errors).toHaveLength(0)
+ expect(matches.length).toBe(1)
+ })
+
+ it('Should match node wildcard', () => {
+ const fileContent = `
+ scopes = function(data)
+ data.spreadingFactor = "SF" .. data.spreadingFactor
+ local saveResult = config.saveConfig(data)
+ setChannel(config.computeFrequency(data.frequency), data.spreadingFactor, data.errorCorrection)
+ ws.send(transmissionParamsEvent .. "_ACK", saveResult)
+ end
+ `
+
+ const queries = [
+ `
+ scopes = $$$
+ `,
+ ]
+
+ const { matches, errors } = searchInStrings({
+ mode: 'include',
+ caseInsensitive: true,
+ queryCodes: queries,
+ files: [
+ {
+ path: 'mock',
+ content: fileContent,
+ },
+ ],
+ })
+
+ expect(errors).toHaveLength(0)
+ expect(matches.length).toBe(1)
+ })
+
+ it('Should match identifier wildcard', () => {
+ const fileContent = `
+ scopes = ws.send(transmissionParamsEvent .. "_ACK", saveResult)
+ `
+
+ const queries = [
+ `
+ scopes = ws.$$()
+ `,
+ ]
+
+ const { matches, errors } = searchInStrings({
+ mode: 'include',
+ caseInsensitive: true,
+ queryCodes: queries,
+ files: [
+ {
+ path: 'mock',
+ content: fileContent,
+ },
+ ],
+ })
+
+ expect(errors).toHaveLength(0)
+ expect(matches.length).toBe(1)
+ })
+
+ it('Should match integer wildcard', () => {
+ const fileContent = `
+ val = 123
+ `
+
+ const queries = [
+ `
+ 0x0
+ `,
+ ]
+
+ const { matches, errors } = searchInStrings({
+ mode: 'include',
+ caseInsensitive: true,
+ queryCodes: queries,
+ files: [
+ {
+ path: 'mock',
+ content: fileContent,
+ },
+ ],
+ })
+
+ expect(errors).toHaveLength(0)
+ expect(matches.length).toBe(1)
+ })
+
+ it('Should match float wildcard', () => {
+ const fileContent = `
+ val = 123.123
+ `
+
+ const queries = [
+ `
+ 0x0
+ `,
+ ]
+
+ const { matches, errors } = searchInStrings({
+ mode: 'include',
+ caseInsensitive: true,
+ queryCodes: queries,
+ files: [
+ {
+ path: 'mock',
+ content: fileContent,
+ },
+ ],
+ })
+
+ expect(errors).toHaveLength(0)
+ expect(matches.length).toBe(1)
+ })
+})
diff --git a/packages/core/__tests__/Lua/other/searchWithContext.test.ts b/packages/core/__tests__/Lua/other/searchWithContext.test.ts
new file mode 100644
index 0000000..698cffd
--- /dev/null
+++ b/packages/core/__tests__/Lua/other/searchWithContext.test.ts
@@ -0,0 +1,64 @@
+import { searchInStrings } from '../../../src/searchInStrings'
+import { compareCode, getParserSettings } from '../../utils'
+
+describe('Search with context', () => {
+ beforeAll(async () => {
+ await getParserSettings().init?.()
+ })
+
+ it('Should partial match function definition using wildcard and alias', () => {
+ const fileContent = `
+ function fact (n)
+ if n == 0 then
+ print()
+ return 1
+ else
+ print()
+ return n * fact(n-1)
+ end
+ end
+
+ `
+ const queries = [
+ `
+ function fact (n)
+ if n == 0 then
+ $$_refPrint()
+ return 1
+ else
+ $$_refPrint()
+ return n * fact(n-1)
+ end
+ end
+ `,
+ ]
+
+ const { matches, errors } = searchInStrings({
+ mode: 'include',
+ caseInsensitive: true,
+ queryCodes: queries,
+ files: [
+ {
+ path: 'mock',
+ content: fileContent,
+ },
+ ],
+ })
+
+ expect(errors).toHaveLength(0)
+ expect(matches.length).toBe(1)
+
+ const match = matches[0]
+
+ expect(match.aliases.identifierAliasesMap['refPrint'].aliasValue).toBe(
+ 'print',
+ )
+
+ expect(compareCode(fileContent, match.code)).toBe(true)
+
+ expect(match.loc).toStrictEqual({
+ start: { line: 2, column: 6, index: 7 },
+ end: { line: 10, column: 9, index: 168 },
+ })
+ })
+})
diff --git a/packages/core/__tests__/Python/matchCodePatterns/basic.test.ts b/packages/core/__tests__/Python/matchCodePatterns/basic.test.ts
new file mode 100644
index 0000000..2d8dce2
--- /dev/null
+++ b/packages/core/__tests__/Python/matchCodePatterns/basic.test.ts
@@ -0,0 +1,203 @@
+import { searchInStrings } from '../../../src/searchInStrings'
+import { getParserSettings, compareCode } from '../../utils'
+
+describe('Basic queries', () => {
+ beforeAll(async () => {
+ await getParserSettings().init?.()
+ })
+
+ it('Should exact match identifier', async () => {
+ const fileContent = `
+ print;
+ `
+ const queries = [fileContent]
+
+ const { matches, errors } = searchInStrings({
+ mode: 'exact',
+ caseInsensitive: true,
+ queryCodes: queries,
+ files: [
+ {
+ path: 'mock',
+ content: fileContent,
+ },
+ ],
+ })
+
+ expect(errors).toHaveLength(0)
+ expect(matches.length).toBe(1)
+ })
+
+ it('Should exact match function definition', () => {
+ const fileContent = `
+ def fib(n):
+ a, b = 0, 1
+ while a < n:
+ print(a, end=' ')
+ a, b = b, a+b
+ print()
+ `
+ const queries = [fileContent]
+
+ const { matches, errors } = searchInStrings({
+ mode: 'exact',
+ caseInsensitive: true,
+ queryCodes: queries,
+ files: [
+ {
+ path: 'mock',
+ content: fileContent,
+ },
+ ],
+ })
+
+ expect(errors).toHaveLength(0)
+ expect(matches.length).toBe(1)
+ })
+
+ it('Should partial match function definition', () => {
+ const fileContent = `
+ def fib(n):
+ a, b = 0, 1
+ while a < n:
+ print(a, end=' ')
+ a, b = b, a+b
+ print()
+ `
+ const queries = [
+ `
+ def fib(n):
+ print()
+ `,
+ ]
+
+ const { matches, errors } = searchInStrings({
+ mode: 'include',
+ caseInsensitive: true,
+ queryCodes: queries,
+ files: [
+ {
+ path: 'mock',
+ content: fileContent,
+ },
+ ],
+ })
+
+ expect(errors).toHaveLength(0)
+ expect(matches.length).toBe(1)
+ })
+
+ it('Should match function with return type by query without return type in include mode', () => {
+ const fileContent = `
+ def accepts() -> str:
+ a
+ `
+ const queries = [
+ `
+ def accepts():
+ a
+ `,
+ ]
+
+ const { matches, errors } = searchInStrings({
+ mode: 'include',
+ caseInsensitive: true,
+ queryCodes: queries,
+ files: [
+ {
+ path: 'mock',
+ content: fileContent,
+ },
+ ],
+ })
+
+ expect(errors).toHaveLength(0)
+ expect(matches.length).toBe(1)
+
+ const match = matches[0]
+
+ expect(match.loc).toStrictEqual({
+ start: { line: 2, column: 6, index: 7 },
+ end: { line: 3, column: 9, index: 38 },
+ })
+ })
+
+ it('Should match multiline', () => {
+ const fileContent = `
+ def from_dsn(cls, dsn):
+ urlparts = urlparse(dsn)
+
+ public_key = urlparts.username
+ project_id = urlparts.path.rsplit("/", 1)[-1]
+
+ try:
+ return ProjectKey.objects.get(public_key=public_key, project=project_id)
+ except ValueError:
+ raise ProjectKey.DoesNotExist("ProjectKey matching query does not exist.")
+ `
+
+ const queries = [
+ `
+ public_key = urlparts.username
+ project_id = urlparts.path.rsplit("/", 1)[-1]
+ `,
+ ]
+
+ const { matches, errors } = searchInStrings({
+ mode: 'include',
+ caseInsensitive: true,
+ queryCodes: queries,
+ files: [
+ {
+ path: 'mock',
+ content: fileContent,
+ },
+ ],
+ })
+
+ expect(errors).toHaveLength(0)
+ expect(matches.length).toBe(1)
+
+ const match = matches[0]
+
+ expect(match.loc).toStrictEqual({
+ start: { line: 5, column: 8, index: 73 },
+ end: { line: 6, column: 53, index: 157 },
+ })
+ })
+
+ it('Should match function named params with different formatting', () => {
+ const fileContent = `
+ ProjectKey.objects.get(public_key = public_key, project= project_id)
+ `
+
+ const queries = [
+ `
+ ProjectKey.objects.get(public_key=public_key, project = project_id)
+
+ `,
+ ]
+
+ const { matches, errors } = searchInStrings({
+ mode: 'include',
+ caseInsensitive: true,
+ queryCodes: queries,
+ files: [
+ {
+ path: 'mock',
+ content: fileContent,
+ },
+ ],
+ })
+
+ expect(errors).toHaveLength(0)
+ expect(matches.length).toBe(1)
+
+ const match = matches[0]
+
+ expect(match.loc).toStrictEqual({
+ start: { line: 2, column: 6, index: 7 },
+ end: { line: 2, column: 76, index: 77 },
+ })
+ })
+})
diff --git a/packages/core/__tests__/Python/matchCodePatterns/literals.test.ts b/packages/core/__tests__/Python/matchCodePatterns/literals.test.ts
new file mode 100644
index 0000000..bc59a4e
--- /dev/null
+++ b/packages/core/__tests__/Python/matchCodePatterns/literals.test.ts
@@ -0,0 +1,174 @@
+import { searchInStrings } from '../../../src/searchInStrings'
+import { getParserSettings } from '../../utils'
+
+describe('Literals', () => {
+ beforeAll(async () => {
+ await getParserSettings().init?.()
+ })
+
+ it('Should match string literal', () => {
+ const fileContent = `
+ scopes = BitField(
+ flags=(
+ ("project:read", "project:read")
+ )
+ )
+ `
+
+ const queries = [
+ `
+ "project:read"
+ `,
+ ]
+
+ const { matches, errors } = searchInStrings({
+ mode: 'include',
+ caseInsensitive: true,
+ queryCodes: queries,
+ files: [
+ {
+ path: 'mock',
+ content: fileContent,
+ },
+ ],
+ })
+
+ expect(errors).toHaveLength(0)
+ expect(matches.length).toBe(2)
+ })
+
+ it('Should exact match template string literal', () => {
+ const fileContent = `
+ f"project:{self.project_id}:rules"
+ `
+
+ const queries = [
+ `
+ f"project:{self.project_id}:rules"
+ `,
+ ]
+
+ const { matches, errors } = searchInStrings({
+ mode: 'include',
+ caseInsensitive: true,
+ queryCodes: queries,
+ files: [
+ {
+ path: 'mock',
+ content: fileContent,
+ },
+ ],
+ })
+
+ expect(errors).toHaveLength(0)
+ expect(matches.length).toBe(1)
+ })
+
+ it('Should partial match template string literal', () => {
+ const fileContent = `
+ f"project:{self.project_id}:rules{value}"
+ `
+
+ const queries = [
+ `
+ f"project:{value}:rules"
+ `,
+ ]
+
+ const { matches, errors } = searchInStrings({
+ mode: 'include',
+ caseInsensitive: true,
+ queryCodes: queries,
+ files: [
+ {
+ path: 'mock',
+ content: fileContent,
+ },
+ ],
+ })
+
+ expect(errors).toHaveLength(0)
+ expect(matches.length).toBe(1)
+ })
+
+ it('Should match Integer literal', () => {
+ const fileContent = `
+ val = 123
+ `
+
+ const queries = [
+ `
+ 123
+ `,
+ ]
+
+ const { matches, errors } = searchInStrings({
+ mode: 'include',
+ caseInsensitive: true,
+ queryCodes: queries,
+ files: [
+ {
+ path: 'mock',
+ content: fileContent,
+ },
+ ],
+ })
+
+ expect(errors).toHaveLength(0)
+ expect(matches.length).toBe(1)
+ })
+
+ it('Should match Float literal', () => {
+ const fileContent = `
+ val = 123.123
+ `
+
+ const queries = [
+ `
+ 123.123
+ `,
+ ]
+
+ const { matches, errors } = searchInStrings({
+ mode: 'include',
+ caseInsensitive: true,
+ queryCodes: queries,
+ files: [
+ {
+ path: 'mock',
+ content: fileContent,
+ },
+ ],
+ })
+
+ expect(errors).toHaveLength(0)
+ expect(matches.length).toBe(1)
+ })
+
+ it('Should match Hex literal', () => {
+ const fileContent = `
+ val = 0xFF
+ `
+
+ const queries = [
+ `
+ 0xFF
+ `,
+ ]
+
+ const { matches, errors } = searchInStrings({
+ mode: 'include',
+ caseInsensitive: true,
+ queryCodes: queries,
+ files: [
+ {
+ path: 'mock',
+ content: fileContent,
+ },
+ ],
+ })
+
+ expect(errors).toHaveLength(0)
+ expect(matches.length).toBe(1)
+ })
+})
diff --git a/packages/core/__tests__/Python/matchCodePatterns/wildcards.test.ts b/packages/core/__tests__/Python/matchCodePatterns/wildcards.test.ts
new file mode 100644
index 0000000..8387101
--- /dev/null
+++ b/packages/core/__tests__/Python/matchCodePatterns/wildcards.test.ts
@@ -0,0 +1,155 @@
+import { searchInStrings } from '../../../src/searchInStrings'
+import { getParserSettings } from '../../utils'
+
+describe('Wildcards', () => {
+ beforeAll(async () => {
+ await getParserSettings().init?.()
+ })
+
+ it('Should match string wildcard', () => {
+ const fileContent = `
+ scopes = BitField(
+ flags=(
+ ("project:read", "project:read")
+ )
+ )
+ `
+
+ const queries = [
+ `
+ "pro$$t:read"
+ `,
+ ]
+
+ const { matches, errors } = searchInStrings({
+ mode: 'include',
+ caseInsensitive: true,
+ queryCodes: queries,
+ files: [
+ {
+ path: 'mock',
+ content: fileContent,
+ },
+ ],
+ })
+
+ expect(errors).toHaveLength(0)
+ expect(matches.length).toBe(2)
+ })
+
+ it('Should match node wildcard', () => {
+ const fileContent = `
+ scopes = BitField(
+ flags=(
+ ("project:read", "project:read")
+ )
+ )
+ `
+
+ const queries = [
+ `
+ scopes = $$$
+ `,
+ ]
+
+ const { matches, errors } = searchInStrings({
+ mode: 'include',
+ caseInsensitive: true,
+ queryCodes: queries,
+ files: [
+ {
+ path: 'mock',
+ content: fileContent,
+ },
+ ],
+ })
+
+ expect(errors).toHaveLength(0)
+ expect(matches.length).toBe(1)
+ })
+
+ it('Should match identifier wildcard', () => {
+ const fileContent = `
+ scopes = BitField(
+ flags=(
+ ("project:read", "project:read")
+ )
+ )
+ `
+
+ const queries = [
+ `
+ scopes = $$()
+ `,
+ ]
+
+ const { matches, errors } = searchInStrings({
+ mode: 'include',
+ caseInsensitive: true,
+ queryCodes: queries,
+ files: [
+ {
+ path: 'mock',
+ content: fileContent,
+ },
+ ],
+ })
+
+ expect(errors).toHaveLength(0)
+ expect(matches.length).toBe(1)
+ })
+
+ it('Should match integer wildcard', () => {
+ const fileContent = `
+ val = 123
+ `
+
+ const queries = [
+ `
+ 0x0
+ `,
+ ]
+
+ const { matches, errors } = searchInStrings({
+ mode: 'include',
+ caseInsensitive: true,
+ queryCodes: queries,
+ files: [
+ {
+ path: 'mock',
+ content: fileContent,
+ },
+ ],
+ })
+
+ expect(errors).toHaveLength(0)
+ expect(matches.length).toBe(1)
+ })
+
+ it('Should match float wildcard', () => {
+ const fileContent = `
+ val = 123.123
+ `
+
+ const queries = [
+ `
+ 0x0
+ `,
+ ]
+
+ const { matches, errors } = searchInStrings({
+ mode: 'include',
+ caseInsensitive: true,
+ queryCodes: queries,
+ files: [
+ {
+ path: 'mock',
+ content: fileContent,
+ },
+ ],
+ })
+
+ expect(errors).toHaveLength(0)
+ expect(matches.length).toBe(1)
+ })
+})
diff --git a/packages/core/__tests__/Python/other/searchWithContext.test.ts b/packages/core/__tests__/Python/other/searchWithContext.test.ts
new file mode 100644
index 0000000..75c9050
--- /dev/null
+++ b/packages/core/__tests__/Python/other/searchWithContext.test.ts
@@ -0,0 +1,55 @@
+import { searchInStrings } from '../../../src/searchInStrings'
+import { compareCode, getParserSettings } from '../../utils'
+
+describe('Search with context', () => {
+ beforeAll(async () => {
+ await getParserSettings().init?.()
+ })
+
+ it('Should partial match function definition using wildcard and alias', () => {
+ const fileContent = `
+ def fib(n):
+ a, b = 0, 1
+ print()
+ while a < n:
+ print(a, end=' ')
+ a, b = b, a+b
+ print()
+ `
+ const queries = [
+ `
+ def fib(n):
+ $$_refPrint()
+ $$_refPrint()
+ `,
+ ]
+
+ const { matches, errors } = searchInStrings({
+ mode: 'include',
+ caseInsensitive: true,
+ queryCodes: queries,
+ files: [
+ {
+ path: 'mock',
+ content: fileContent,
+ },
+ ],
+ })
+
+ expect(errors).toHaveLength(0)
+ expect(matches.length).toBe(1)
+
+ const match = matches[0]
+
+ expect(match.aliases.identifierAliasesMap['refPrint'].aliasValue).toBe(
+ 'print',
+ )
+
+ expect(compareCode(fileContent, match.code)).toBe(true)
+
+ expect(match.loc).toStrictEqual({
+ start: { line: 2, column: 6, index: 7 },
+ end: { line: 8, column: 15, index: 147 },
+ })
+ })
+})
diff --git a/packages/core/__tests__/search/textSearch.test.ts b/packages/core/__tests__/TextSearch/textSearch.test.ts
similarity index 95%
rename from packages/core/__tests__/search/textSearch.test.ts
rename to packages/core/__tests__/TextSearch/textSearch.test.ts
index 5a994ac..1aef5db 100644
--- a/packages/core/__tests__/search/textSearch.test.ts
+++ b/packages/core/__tests__/TextSearch/textSearch.test.ts
@@ -1,15 +1,16 @@
-import { getFilesList } from '/getFilesList'
+import { getFilesList } from '../../src/getFilesList'
import path from 'path'
-import { searchInFileSystem } from '/searchInFs'
+import { searchInFileSystem } from '../../src/searchInFs'
import dedent from 'dedent'
-import searchInStrings from '/searchInStrings'
+import searchInStrings from '../../src/searchInStrings'
+import { fixturesPath, fixturesOtherPath } from '../utils'
describe('Text search mode', () => {
let filesList = [] as string[]
beforeAll(async () => {
filesList = await getFilesList({
- searchRoot: path.resolve(__dirname, '__fixtures__'),
+ searchRoot: fixturesPath,
omitGitIgnore: true,
})
})
@@ -273,9 +274,7 @@ describe('Text search mode', () => {
`,
],
- filePaths: [
- path.resolve(__dirname, '__fixturesOther__', 'textSearch.ts'),
- ],
+ filePaths: [fixturesOtherPath + '/textSearch.ts'],
mode: 'text',
caseInsensitive: true,
})
diff --git a/packages/core/__tests__/TypeScript/matchCodePatterns/assignmentPattern.test.ts b/packages/core/__tests__/TypeScript/matchCodePatterns/assignmentPattern.test.ts
new file mode 100644
index 0000000..2a51bb1
--- /dev/null
+++ b/packages/core/__tests__/TypeScript/matchCodePatterns/assignmentPattern.test.ts
@@ -0,0 +1,65 @@
+import { searchInStrings } from '../../../src/searchInStrings'
+
+describe('AssignmentPattern improvements in include mode', () => {
+ it('should match assignment pattern in function arguments type annotation', () => {
+ const fileContent = `
+ function some(param: [] | null = null) {
+
+ }
+ `
+
+ const queries = [
+ `
+ function some(param: [] | null) {
+
+ }
+ `,
+ ]
+
+ const { matches, errors } = searchInStrings({
+ mode: 'include',
+ caseInsensitive: true,
+ queryCodes: queries,
+ files: [
+ {
+ path: 'mock',
+ content: fileContent,
+ },
+ ],
+ })
+
+ expect(errors).toHaveLength(0)
+ expect(matches.length).toBe(1)
+ })
+
+ it('should not match assignment pattern in function arguments with wildcard but without types', () => {
+ const fileContent = `
+ function some(param = null) {
+
+ }
+ `
+
+ const queries = [
+ `
+ function some($$: [] | null = null) {
+
+ }
+ `,
+ ]
+
+ const { matches, errors } = searchInStrings({
+ mode: 'include',
+ caseInsensitive: true,
+ queryCodes: queries,
+ files: [
+ {
+ path: 'mock',
+ content: fileContent,
+ },
+ ],
+ })
+
+ expect(errors).toHaveLength(0)
+ expect(matches.length).toBe(0)
+ })
+})
diff --git a/packages/core/__tests__/TypeScript/matchCodePatterns/functionsAndTypes.test.ts b/packages/core/__tests__/TypeScript/matchCodePatterns/functionsAndTypes.test.ts
new file mode 100644
index 0000000..f2f6fb9
--- /dev/null
+++ b/packages/core/__tests__/TypeScript/matchCodePatterns/functionsAndTypes.test.ts
@@ -0,0 +1,242 @@
+import { searchInStrings } from '../../../src/searchInStrings'
+import { compareCode } from '../../utils'
+
+describe('functions', () => {
+ const fileContent = `
+ const onScroll = ({
+ nativeEvent
+ }: NativeSyntheticEvent
) => {
+ const currentScrollPosition = Math.floor(nativeEvent?.contentOffset?.y) ?? 0;
+
+ if (!isIOS) {
+ return velocity.setValue(currentScrollPosition);
+ }
+
+ setExtended(currentScrollPosition <= 0);
+ };
+ `
+
+ it('should match exact function with body', () => {
+ const queries = [
+ `
+ const onScroll = ({
+ nativeEvent
+ }: NativeSyntheticEvent) => {
+ const currentScrollPosition = Math.floor(nativeEvent?.contentOffset?.y) ?? 0;
+
+ if (!isIOS) {
+ return velocity.setValue(currentScrollPosition);
+ }
+
+ setExtended(currentScrollPosition <= 0);
+ };
+ `,
+ ]
+
+ const { matches, errors } = searchInStrings({
+ mode: 'exact',
+ files: [{ content: fileContent, path: '' }],
+ queryCodes: queries,
+ })
+
+ expect(errors).toHaveLength(0)
+ expect(matches.length).toBe(1)
+
+ expect(compareCode(matches[0].code, queries[0])).toBeTruthy()
+ })
+
+ it('should match function with body statements in order with exact statements', () => {
+ const queries = [
+ `
+ const onScroll = ({
+ nativeEvent
+ }: NativeSyntheticEvent) => {
+ const currentScrollPosition = Math.floor(nativeEvent?.contentOffset?.y) ?? 0;
+
+
+ if (!isIOS) {
+ return velocity.setValue(currentScrollPosition);
+ }
+
+ setExtended(currentScrollPosition <= 0);
+
+ };
+ `,
+ ]
+
+ const { matches, errors } = searchInStrings({
+ mode: 'include-with-order',
+ files: [{ content: fileContent, path: '' }],
+ queryCodes: queries,
+ })
+ expect(errors).toHaveLength(0)
+ expect(matches.length).toBe(1)
+ })
+
+ it('should match function with body statements in order but without all statements', () => {
+ const queries = [
+ `
+ const onScroll = ({
+ nativeEvent
+ }: NativeSyntheticEvent) => {
+ const currentScrollPosition = Math.floor(nativeEvent?.contentOffset?.y) ?? 0;
+
+
+ if (!isIOS) {
+ return velocity.setValue(currentScrollPosition);
+ }
+
+ };
+ `,
+ ]
+
+ const { matches, errors } = searchInStrings({
+ mode: 'include-with-order',
+ files: [{ content: fileContent, path: '' }],
+ queryCodes: queries,
+ })
+
+ expect(errors).toHaveLength(0)
+ expect(matches.length).toBe(1)
+ })
+
+ it('should not match function with body statements in different order', () => {
+ const queries = [
+ `
+ const onScroll = ({
+ nativeEvent
+ }: NativeSyntheticEvent) => {
+ const currentScrollPosition = Math.floor(nativeEvent?.contentOffset?.y) ?? 0;
+
+ setExtended(currentScrollPosition <= 0);
+
+ if (!isIOS) {
+ return velocity.setValue(currentScrollPosition);
+ }
+
+ };
+ `,
+ ]
+
+ const { matches, errors } = searchInStrings({
+ mode: 'include-with-order',
+ files: [{ content: fileContent, path: '' }],
+ queryCodes: queries,
+ })
+
+ expect(errors).toHaveLength(0)
+ expect(matches.length).toBe(0)
+ })
+
+ it('should not match function with body statements in different order without all statements', () => {
+ const queries = [
+ `
+ const onScroll = ({
+ nativeEvent
+ }: NativeSyntheticEvent) => {
+
+ if (!isIOS) {
+ return velocity.setValue(currentScrollPosition);
+ }
+
+ const currentScrollPosition = Math.floor(nativeEvent?.contentOffset?.y) ?? 0;
+
+ };
+ `,
+ ]
+
+ const { matches, errors } = searchInStrings({
+ mode: 'include-with-order',
+ files: [{ content: fileContent, path: '' }],
+ queryCodes: queries,
+ })
+
+ expect(errors).toHaveLength(0)
+ expect(matches.length).toBe(0)
+ })
+
+ it('should match function with body statements in different order', () => {
+ const queries = [
+ `
+ const onScroll = ({
+ nativeEvent
+ }: NativeSyntheticEvent) => {
+ const currentScrollPosition = Math.floor(nativeEvent?.contentOffset?.y) ?? 0;
+
+ setExtended(currentScrollPosition <= 0);
+
+ if (!isIOS) {
+ return velocity.setValue(currentScrollPosition);
+ }
+
+ };
+ `,
+ ]
+
+ const { matches, errors } = searchInStrings({
+ mode: 'include',
+ files: [{ content: fileContent, path: '' }],
+ queryCodes: queries,
+ })
+
+ expect(errors).toHaveLength(0)
+ expect(matches.length).toBe(1)
+ })
+
+ it('should match function with body statements in different order without all statements', () => {
+ const queries = [
+ `
+ const onScroll = ({
+ nativeEvent
+ }: NativeSyntheticEvent) => {
+
+ if (!isIOS) {
+ return velocity.setValue(currentScrollPosition);
+ }
+
+ const currentScrollPosition = Math.floor(nativeEvent?.contentOffset?.y) ?? 0;
+
+ };
+ `,
+ ]
+
+ const { matches, errors } = searchInStrings({
+ mode: 'include',
+ files: [{ content: fileContent, path: '' }],
+ queryCodes: queries,
+ })
+
+ expect(errors).toHaveLength(0)
+ expect(matches.length).toBe(1)
+ })
+
+ it('should match inline types in function params', () => {
+ const fileContent = `
+ const onScroll = ({
+ onClick
+ }: { onClick : () => string }) => {
+ const currentScrollPosition = Math.floor(nativeEvent?.contentOffset?.y) ?? 0;
+
+ setExtended(currentScrollPosition <= 0);
+ };
+ `
+ const queries = [
+ `
+ const $$ = ({
+ $$,
+ }: {
+ $$: () => $$$;
+ }) => {}
+ `,
+ ]
+
+ const { matches, errors } = searchInStrings({
+ mode: 'include',
+ files: [{ content: fileContent, path: '' }],
+ queryCodes: queries,
+ })
+
+ expect(errors).toHaveLength(0)
+ expect(matches.length).toBe(1)
+ })
+})
diff --git a/packages/core/__tests__/TypeScript/matchCodePatterns/other.test.ts b/packages/core/__tests__/TypeScript/matchCodePatterns/other.test.ts
new file mode 100644
index 0000000..684c694
--- /dev/null
+++ b/packages/core/__tests__/TypeScript/matchCodePatterns/other.test.ts
@@ -0,0 +1,77 @@
+import { useTraverseApproachTestOnly } from '../../../src/testOnlyConfig'
+import { searchInFileSystem } from '../../../src/searchInFs'
+
+import { searchInStrings } from '../../../src/searchInStrings'
+
+describe('other', () => {
+ it('should match cast to any', () => {
+ const fileContent = `
+ const val = 5 as any
+ const val2 = (fn() as any) as MyType
+ `
+
+ const queries = [
+ `
+ ($$$ as any)
+ `,
+ ]
+
+ const { matches, errors } = searchInStrings({
+ mode: 'exact',
+ files: [{ content: fileContent, path: '' }],
+
+ queryCodes: queries,
+ })
+
+ expect(errors).toHaveLength(0)
+ expect(matches.length).toBe(2)
+ })
+
+ it('should match anything', () => {
+ const fileContent = `
+ const a:Object = {
+ val : 5
+ }
+ `
+
+ const queries = [
+ `
+ $$$
+ `,
+ ]
+
+ const { matches, errors } = searchInStrings({
+ mode: 'include',
+ files: [{ content: fileContent, path: '' }],
+ queryCodes: queries,
+ })
+
+ // In traversal we only project query to identifier nodes
+ const expectedMatchesCount = global.testSettings?.isTraversal ? 3 : 10
+
+ expect(errors).toHaveLength(0)
+ expect(matches.length).toBe(expectedMatchesCount)
+ })
+
+ it('should not include the same result twice', () => {
+ const fileContent = `type MyType = ScrollViewProps & BoxProps`
+
+ const queries = [
+ `
+ type $$ = ScrollViewProps & $$$
+ `,
+ `
+ type $$ = $$$ & ScrollViewProps
+ `,
+ ]
+
+ const { matches, errors } = searchInStrings({
+ mode: 'include',
+ files: [{ content: fileContent, path: '' }],
+ queryCodes: queries,
+ })
+
+ expect(errors).toHaveLength(0)
+ expect(matches.length).toBe(1)
+ })
+})
diff --git a/packages/core/__tests__/search/types.test.ts b/packages/core/__tests__/TypeScript/matchCodePatterns/types.test.ts
similarity index 91%
rename from packages/core/__tests__/search/types.test.ts
rename to packages/core/__tests__/TypeScript/matchCodePatterns/types.test.ts
index e6b1bc5..6e68973 100644
--- a/packages/core/__tests__/search/types.test.ts
+++ b/packages/core/__tests__/TypeScript/matchCodePatterns/types.test.ts
@@ -1,14 +1,14 @@
-import { searchInFileSystem } from '/searchInFs'
-import path from 'path'
-import { getFilesList } from '/getFilesList'
-import { searchInStrings } from '../../src/searchInStrings'
+import { searchInFileSystem } from '../../../src/searchInFs'
+import { fixturesPath } from '../../utils'
+import { getFilesList } from '../../../src/getFilesList'
+import { searchInStrings } from '../../../src/searchInStrings'
describe('Types', () => {
let filesList = [] as string[]
beforeAll(async () => {
filesList = await getFilesList({
- searchRoot: path.resolve(__dirname, '__fixtures__'),
+ searchRoot: fixturesPath,
omitGitIgnore: true,
})
})
@@ -61,7 +61,7 @@ describe('Types', () => {
queryCodes: queries,
})
- expect(errors.length).toBe(0)
+ expect(errors).toHaveLength(0)
expect(matches.length).toBe(1)
})
@@ -78,7 +78,7 @@ describe('Types', () => {
queryCodes: queries,
})
- expect(errors.length).toBe(0)
+ expect(errors).toHaveLength(0)
expect(matches.length).toBe(1)
})
@@ -95,7 +95,7 @@ describe('Types', () => {
queryCodes: queries,
})
- expect(errors.length).toBe(0)
+ expect(errors).toHaveLength(0)
expect(matches.length).toBe(1)
})
@@ -112,7 +112,7 @@ describe('Types', () => {
queryCodes: queries,
})
- expect(errors.length).toBe(0)
+ expect(errors).toHaveLength(0)
expect(matches.length).toBe(3)
})
@@ -131,7 +131,7 @@ describe('Types', () => {
queryCodes: queries,
})
- expect(errors.length).toBe(0)
+ expect(errors).toHaveLength(0)
expect(matches.length).toBe(5)
})
@@ -150,7 +150,7 @@ describe('Types', () => {
queryCodes: queries,
})
- expect(errors.length).toBe(0)
+ expect(errors).toHaveLength(0)
expect(matches.length).toBe(2)
})
@@ -169,7 +169,7 @@ describe('Types', () => {
queryCodes: queries,
})
- expect(errors.length).toBe(0)
+ expect(errors).toHaveLength(0)
expect(matches.length).toBe(2)
})
@@ -188,7 +188,7 @@ describe('Types', () => {
queryCodes: queries,
})
- expect(errors.length).toBe(0)
+ expect(errors).toHaveLength(0)
expect(matches.length).toBe(2)
})
@@ -207,7 +207,7 @@ describe('Types', () => {
queryCodes: queries,
})
- expect(errors.length).toBe(0)
+ expect(errors).toHaveLength(0)
expect(matches.length).toBe(2)
})
@@ -224,7 +224,7 @@ describe('Types', () => {
queryCodes: queries,
})
- expect(errors.length).toBe(0)
+ expect(errors).toHaveLength(0)
expect(matches.length).toBe(1)
})
@@ -241,7 +241,7 @@ describe('Types', () => {
queryCodes: queries,
})
- expect(errors.length).toBe(0)
+ expect(errors).toHaveLength(0)
expect(matches.length).toBe(1)
})
@@ -258,7 +258,7 @@ describe('Types', () => {
queryCodes: queries,
})
- expect(errors.length).toBe(0)
+ expect(errors).toHaveLength(0)
expect(matches.length).toBe(1)
})
@@ -275,7 +275,7 @@ describe('Types', () => {
queryCodes: queries,
})
- expect(errors.length).toBe(0)
+ expect(errors).toHaveLength(0)
expect(matches.length).toBe(1)
})
@@ -292,7 +292,7 @@ describe('Types', () => {
queryCodes: queries,
})
- expect(errors.length).toBe(0)
+ expect(errors).toHaveLength(0)
expect(matches.length).toBe(1)
})
@@ -309,7 +309,7 @@ describe('Types', () => {
queryCodes: queries,
})
- expect(errors.length).toBe(0)
+ expect(errors).toHaveLength(0)
expect(matches.length).toBe(1)
})
@@ -440,7 +440,7 @@ describe('Types', () => {
queryCodes: queries,
})
- expect(errors.length).toBe(0)
+ expect(errors).toHaveLength(0)
expect(matches.length).toBe(2)
})
@@ -458,7 +458,7 @@ describe('Types', () => {
queryCodes: queries,
})
- expect(errors.length).toBe(0)
+ expect(errors).toHaveLength(0)
expect(matches.length).toBe(1)
})
@@ -476,7 +476,7 @@ describe('Types', () => {
queryCodes: queries,
})
- expect(errors.length).toBe(0)
+ expect(errors).toHaveLength(0)
expect(matches.length).toBe(1)
})
@@ -495,7 +495,7 @@ describe('Types', () => {
queryCodes: queries,
})
- expect(errors.length).toBe(0)
+ expect(errors).toHaveLength(0)
expect(matches.length).toBe(2)
})
@@ -514,7 +514,7 @@ describe('Types', () => {
queryCodes: queries,
})
- expect(errors.length).toBe(0)
+ expect(errors).toHaveLength(0)
expect(matches.length).toBe(1)
})
@@ -533,7 +533,7 @@ describe('Types', () => {
queryCodes: queries,
})
- expect(errors.length).toBe(0)
+ expect(errors).toHaveLength(0)
expect(matches.length).toBe(1)
})
@@ -553,7 +553,7 @@ describe('Types', () => {
queryCodes: queries,
})
- expect(errors.length).toBe(0)
+ expect(errors).toHaveLength(0)
expect(matches.length).toBe(1)
})
@@ -573,7 +573,7 @@ describe('Types', () => {
queryCodes: queries,
})
- expect(errors.length).toBe(0)
+ expect(errors).toHaveLength(0)
expect(matches.length).toBe(0)
})
@@ -602,7 +602,7 @@ describe('Types', () => {
],
})
- expect(errors.length).toBe(0)
+ expect(errors).toHaveLength(0)
expect(matches.length).toBe(3)
})
@@ -631,7 +631,7 @@ describe('Types', () => {
],
})
- expect(errors.length).toBe(0)
+ expect(errors).toHaveLength(0)
expect(matches.length).toBe(3)
})
})
diff --git a/packages/core/__tests__/astUtils.test.ts b/packages/core/__tests__/TypeScript/other/astUtils.test.ts
similarity index 74%
rename from packages/core/__tests__/astUtils.test.ts
rename to packages/core/__tests__/TypeScript/other/astUtils.test.ts
index 991ac47..2ee0848 100644
--- a/packages/core/__tests__/astUtils.test.ts
+++ b/packages/core/__tests__/TypeScript/other/astUtils.test.ts
@@ -1,5 +1,4 @@
-import { compareCode } from './utils'
-import { createWildcardUtils } from '/wildcardUtilsFactory'
+import { compareCode } from '../../utils'
describe('AST utils', () => {
it('should compare code as equal', () => {
@@ -38,12 +37,12 @@ describe('AST utils', () => {
const code2 = `
import * as React from 'react';
- import {
+ import {
Paragraph,
- Button,
- Portal,
- Dialog,
- Colors
+ Button,
+ Portal,
+ Dialog,
+ Colors
} from 'react-native-paper';
const DialogWithCustomColors = ({
@@ -118,11 +117,11 @@ describe('AST utils', () => {
`
import * as React from 'react';
- import {
- Paragraph,
- Button,
- Portal,
- Dialog
+ import {
+ Paragraph,
+ Button,
+ Portal,
+ Dialog
} from 'react-native-paper';
const DialogWithCustomColors = ({
@@ -157,43 +156,4 @@ describe('AST utils', () => {
`
expect(compareCode(code1, code2)).toBe(false)
})
-
- it('should remove identifier ref from wildcard', () => {
- const identifierTypes: string[] = [] // not needed for this test
- const numericWildcard = '0x0'
- const wildcardChar = '$'
- const wildcardUtils = createWildcardUtils(
- identifierTypes,
- numericWildcard,
- wildcardChar,
- )
-
- expect(wildcardUtils.removeIdentifierRefFromWildcard('$$$_ref1')).toBe(
- '$$$',
- )
-
- expect(wildcardUtils.removeIdentifierRefFromWildcard('$$_ref1')).toBe('$$')
-
- expect(wildcardUtils.removeIdentifierRefFromWildcard('$$something')).toBe(
- '$$something',
- )
-
- expect(wildcardUtils.removeIdentifierRefFromWildcard('$$_something')).toBe(
- '$$',
- )
-
- expect(wildcardUtils.removeIdentifierRefFromWildcard('asd$$_ref')).toBe(
- 'asd$$_ref',
- )
-
- // should not remove if ref is another wildcard
- expect(wildcardUtils.removeIdentifierRefFromWildcard('$$$_$$')).toBe(
- '$$$_$$',
- )
-
- // should not remove if ref is in the middle of string
- expect(wildcardUtils.removeIdentifierRefFromWildcard('$$$_notRef_$$')).toBe(
- '$$$_notRef_$$',
- )
- })
})
diff --git a/packages/core/__tests__/parseQuery.test.ts b/packages/core/__tests__/TypeScript/other/parseQuery.test.ts
similarity index 65%
rename from packages/core/__tests__/parseQuery.test.ts
rename to packages/core/__tests__/TypeScript/other/parseQuery.test.ts
index 43ae79b..71de0b2 100644
--- a/packages/core/__tests__/parseQuery.test.ts
+++ b/packages/core/__tests__/TypeScript/other/parseQuery.test.ts
@@ -1,5 +1,5 @@
-import { getUniqueTokens, extractQueryNode } from '../src/parseQuery'
-import { getParserSettings } from './utils'
+import { getUniqueTokens, extractQueryNode } from '../../../src/parseQuery'
+import { getParserSettings } from '../../utils'
describe('parse query', () => {
const parserSettings = getParserSettings()
@@ -11,6 +11,10 @@ describe('parse query', () => {
const alpha = 'beta'
type MyType = boolean
123;
+ pre$$_ref1_post
+ $$_ref1_content$$_ref2
+ asd$$_invalidRef_$$
+ asd$$_invalidRef$$
{
{
() => {
@@ -19,6 +23,7 @@ describe('parse query', () => {
}
}
}
+ f('some$$_ref1_tttt$$_ref2')
`
const { queryNode } = extractQueryNode(
parserSettings.parseCode(queryCode),
@@ -36,7 +41,15 @@ describe('parse query', () => {
'beta',
'MyType',
'123',
+ 'pre',
+ 'post',
+ 'content',
+ 'asd',
+ '_invalidRef_',
+ '_invalidRef',
'test',
+ // 'some', // only 'tttt' is new
+ 'tttt',
])
})
})
diff --git a/packages/core/__tests__/searchMultiThread.test.ts b/packages/core/__tests__/TypeScript/other/searchMultiThread.test.ts
similarity index 88%
rename from packages/core/__tests__/searchMultiThread.test.ts
rename to packages/core/__tests__/TypeScript/other/searchMultiThread.test.ts
index 57ae995..c6fbb9b 100644
--- a/packages/core/__tests__/searchMultiThread.test.ts
+++ b/packages/core/__tests__/TypeScript/other/searchMultiThread.test.ts
@@ -1,9 +1,9 @@
-import { searchMultiThread as searchMultiThread } from '/searchMultiThread'
-import { searchInFileSystem } from '/searchInFs'
+import { searchMultiThread as searchMultiThread } from '../../../src/searchMultiThread'
+import { searchInFileSystem } from '../../../src/searchInFs'
-import { compareCode } from './utils'
+import { compareCode, fixturesPath } from '../../utils'
import path from 'path'
-import { getFilesList } from '/getFilesList'
+import { getFilesList } from '../../../src/getFilesList'
jest.mock('worker_threads', () => {
const actual = jest.requireActual('worker_threads')
@@ -22,7 +22,7 @@ jest.mock('worker_threads', () => {
it('should search using multiple threads and give the same matches count as single thread search', async () => {
const filesList = await getFilesList({
- searchRoot: path.resolve(__dirname, 'search', '__fixtures__'),
+ searchRoot: fixturesPath,
omitGitIgnore: true,
})
const query = `
@@ -80,7 +80,7 @@ it('should search using multiple threads and give the same matches count as sing
it('Should report each match separately for structural search', async () => {
const filesList = await getFilesList({
- searchRoot: path.resolve(__dirname, 'search', '__fixtures__'),
+ searchRoot: fixturesPath,
omitGitIgnore: true,
})
@@ -107,7 +107,7 @@ it('Should report each match separately for structural search', async () => {
it('Should report each match separately for text search', async () => {
const filesList = await getFilesList({
- searchRoot: path.resolve(__dirname, 'search', '__fixtures__'),
+ searchRoot: fixturesPath,
omitGitIgnore: true,
})
diff --git a/packages/core/__tests__/search/JSX.test.ts b/packages/core/__tests__/TypeScript/searchSmoke/JSX.test.ts
similarity index 51%
rename from packages/core/__tests__/search/JSX.test.ts
rename to packages/core/__tests__/TypeScript/searchSmoke/JSX.test.ts
index cd42bf5..ae0fb14 100644
--- a/packages/core/__tests__/search/JSX.test.ts
+++ b/packages/core/__tests__/TypeScript/searchSmoke/JSX.test.ts
@@ -1,51 +1,19 @@
-import { compareCode } from '../utils'
-import { searchInFileSystem } from '/searchInFs'
+import { compareCode } from '../../utils'
+import { searchInFileSystem } from '../../../src/searchInFs'
-import path from 'path'
-import { searchInStrings } from '../../src/searchInStrings'
-import { getFilesList } from '/getFilesList'
+import { fixturesPath } from '../../utils'
+import { getFilesList } from '../../../src/getFilesList'
describe('JSX', () => {
let filesList = [] as string[]
beforeAll(async () => {
filesList = await getFilesList({
- searchRoot: path.resolve(__dirname, '__fixtures__'),
+ searchRoot: fixturesPath,
omitGitIgnore: true,
})
})
- const testFileContent = `
- <>
-
-
-
- Press to
- Download
-
-
-
-
-
- Press to
- Download
-
-
-
- Click
-
-
- >
- `
-
- const mockedFilesList = [
- {
- path: 'mock',
- content: testFileContent,
- },
- ]
-
it('Should find all self-closing JSX', () => {
const query = `<$$ />`
const { matches, errors } = searchInFileSystem({
@@ -111,26 +79,10 @@ describe('JSX', () => {
filePaths: filesList,
queryCodes: [query],
})
- expect(errors.length).toBe(0)
+ expect(errors).toHaveLength(0)
expect(matches.length).toBe(1)
})
- it('Should find JSX by text content regardless formatting', () => {
- const query = `
-
- Press to
- Download
-
- `
- const { matches, errors } = searchInStrings({
- mode: 'include',
- files: mockedFilesList,
- queryCodes: [query],
- })
- expect(errors.length).toBe(0)
- expect(matches.length).toBe(2)
- })
-
it('Should find JSX by text content with wildcard case insensitive', () => {
const query = `r$$L `
const { matches, errors } = searchInFileSystem({
@@ -139,7 +91,7 @@ describe('JSX', () => {
queryCodes: [query],
caseInsensitive: true,
})
- expect(errors.length).toBe(0)
+ expect(errors).toHaveLength(0)
expect(matches.length).toBe(1)
})
@@ -151,7 +103,7 @@ describe('JSX', () => {
caseInsensitive: true,
queryCodes: [query],
})
- expect(errors.length).toBe(0)
+ expect(errors).toHaveLength(0)
expect(matches.length).toBe(1)
})
@@ -228,7 +180,7 @@ describe('JSX', () => {
queryCodes: [query1, query2],
})
- expect(errors.length).toBe(0)
+ expect(errors).toHaveLength(0)
expect(matches.length).toBe(2)
})
@@ -350,275 +302,4 @@ describe('JSX', () => {
expect(errors).toHaveLength(0)
expect(matches.length).toBe(78)
})
-
- it('Should ignore all empty JSXText in search', () => {
- const queries = [
- `
- <$$>
- $$
- $$>;
- `,
- ]
-
- const { matches, errors } = searchInStrings({
- mode: 'include',
- files: mockedFilesList,
- queryCodes: queries,
- })
-
- expect(errors.length).toBe(0)
- expect(matches.length).toBe(3)
-
- expect(
- compareCode(
- matches[0].code,
- `
- Press to
- Download
-
- `,
- ),
- ).toBeTruthy()
- })
-
- it('Should match code with nested JSX when using wildcard on text content', () => {
- const queries = [
- `
-
- c$$$
- ;
- `,
- ]
-
- const { matches, errors } = searchInStrings({
- mode: 'include',
- caseInsensitive: true,
- files: mockedFilesList,
- queryCodes: queries,
- })
-
- expect(errors.length).toBe(0)
- expect(matches.length).toBe(1)
-
- expect(
- compareCode(
- matches[0].code,
- `
- Click
-
-
- `,
- ),
- ).toBeTruthy()
- })
-
- describe('Self and not self closing JSX tags in include mode', () => {
- it('Self-closing JSX tag in query should match also not self-closing tags', () => {
- const fileContent = `
- asd ;
- bbc ;
-
- ;
-
-
- `
-
- const queries = [
- `
-
- `,
- ]
-
- const { matches, errors } = searchInStrings({
- mode: 'include',
- caseInsensitive: true,
- queryCodes: queries,
- files: [
- {
- path: 'mock',
- content: fileContent,
- },
- ],
- })
-
- expect(errors.length).toBe(0)
- expect(matches.length).toBe(4)
- })
-
- it('Not self-closing JSX tag in query should match also self-closing tags', () => {
- const fileContent = `
- asd ;
- bbc ;
-
- ;
-
-
- `
-
- const queries = [
- `
-
- `,
- ]
-
- const { matches, errors } = searchInStrings({
- mode: 'include',
- caseInsensitive: true,
- queryCodes: queries,
- files: [
- {
- path: 'mock',
- content: fileContent,
- },
- ],
- })
-
- expect(errors.length).toBe(0)
- expect(matches.length).toBe(4)
- })
-
- it('Not self-closing JSX tag with children in query should not match self-closing tags', () => {
- const fileContent = `
- ;
-
-
- `
-
- const queries = [
- `
- asd
- `,
- ]
-
- const { matches, errors } = searchInStrings({
- mode: 'include',
- caseInsensitive: true,
- queryCodes: queries,
- files: [
- {
- path: 'mock',
- content: fileContent,
- },
- ],
- })
-
- expect(errors.length).toBe(0)
- expect(matches.length).toBe(0)
- })
-
- it('Self-closing JSX tag with prop in query should match also not self-closing tag with prop', () => {
- const fileContent = `
- asd ;
- bbc ;
-
- ;
-
-
- `
-
- const queries = [
- `
-
- `,
- ]
-
- const { matches, errors } = searchInStrings({
- mode: 'include',
- caseInsensitive: true,
- queryCodes: queries,
- files: [
- {
- path: 'mock',
- content: fileContent,
- },
- ],
- })
-
- expect(errors.length).toBe(0)
- expect(matches.length).toBe(2)
- })
- })
-
- describe('JSXIdentifiers like Identifiers', () => {
- it('Should match JSXIdentifier when looking for Identifier', () => {
- const fileContent = `
- asd ;
- `
-
- const queries = [
- `
- Comp;
- `,
- ]
-
- const { matches, errors } = searchInStrings({
- mode: 'include',
- caseInsensitive: true,
- queryCodes: queries,
- files: [
- {
- path: 'mock',
- content: fileContent,
- },
- ],
- })
-
- expect(errors.length).toBe(0)
- expect(matches.length).toBe(2)
- })
-
- it('Should match JSXIdentifier when looking for Identifier wildcard', () => {
- const fileContent = `
- asd ;
- `
-
- const queries = [
- `
- Co$$;
- `,
- ]
-
- const { matches, errors } = searchInStrings({
- mode: 'include',
- caseInsensitive: true,
- queryCodes: queries,
- files: [
- {
- path: 'mock',
- content: fileContent,
- },
- ],
- })
-
- expect(errors.length).toBe(0)
- expect(matches.length).toBe(2)
- })
- })
-
- it('Should not match too much values using wildcards in JSXText', () => {
- const fileContent = `
- Edit Client - Dweet
- `
-
- const queries = [
- `
- $$| Dweet |$$ ;
- `,
- ]
-
- const { matches, errors } = searchInStrings({
- mode: 'include',
- caseInsensitive: true,
- queryCodes: queries,
- files: [
- {
- path: 'mock',
- content: fileContent,
- },
- ],
- })
-
- expect(errors.length).toBe(0)
- expect(matches.length).toBe(0)
- })
})
diff --git a/packages/core/__tests__/TypeScript/searchSmoke/blocks.test.ts b/packages/core/__tests__/TypeScript/searchSmoke/blocks.test.ts
new file mode 100644
index 0000000..f99c32c
--- /dev/null
+++ b/packages/core/__tests__/TypeScript/searchSmoke/blocks.test.ts
@@ -0,0 +1,79 @@
+import { searchInFileSystem } from '../../../src/searchInFs'
+import { compareCode } from '../../utils'
+
+import { fixturesPath } from '../../utils'
+import { getFilesList } from '../../../src/getFilesList'
+
+describe('blocks', () => {
+ let filesList = [] as string[]
+
+ beforeAll(async () => {
+ filesList = await getFilesList({
+ searchRoot: fixturesPath,
+ omitGitIgnore: true,
+ })
+ })
+
+ it('should match exact whole block', () => {
+ const queries = [
+ `
+ () => {
+ toggleRTL();
+ I18nManager.forceRTL(!isRTL);
+ Updates.reloadAsync();
+ }
+ `,
+ ]
+
+ const { matches, errors } = searchInFileSystem({
+ mode: 'exact',
+ filePaths: filesList,
+ queryCodes: queries,
+ })
+
+ expect(errors).toHaveLength(0)
+ expect(matches.length).toBe(1)
+
+ expect(compareCode(matches[0].code, queries[0])).toBeTruthy()
+ })
+
+ it('should match block using query without all statements and different order', () => {
+ const queries = [
+ `
+ () => {
+ Updates.reloadAsync();
+ toggleRTL();
+ }
+ `,
+ ]
+
+ const { matches, errors } = searchInFileSystem({
+ mode: 'include',
+ filePaths: filesList,
+ queryCodes: queries,
+ })
+
+ expect(errors).toHaveLength(0)
+ expect(matches.length).toBe(1)
+ })
+
+ it('should match block using query without all statements, but with order', () => {
+ const queries = [
+ `
+ () => {
+ toggleRTL();
+ Updates.reloadAsync();
+ }
+ `,
+ ]
+
+ const { matches, errors } = searchInFileSystem({
+ mode: 'include-with-order',
+ filePaths: filesList,
+ queryCodes: queries,
+ })
+
+ expect(errors).toHaveLength(0)
+ expect(matches.length).toBe(1)
+ })
+})
diff --git a/packages/core/__tests__/search/codePatterns.test.ts b/packages/core/__tests__/TypeScript/searchSmoke/codePatterns.test.ts
similarity index 89%
rename from packages/core/__tests__/search/codePatterns.test.ts
rename to packages/core/__tests__/TypeScript/searchSmoke/codePatterns.test.ts
index e0d07fa..fef8953 100644
--- a/packages/core/__tests__/search/codePatterns.test.ts
+++ b/packages/core/__tests__/TypeScript/searchSmoke/codePatterns.test.ts
@@ -1,15 +1,15 @@
-import { searchInFileSystem } from '/searchInFs'
-import { compareCode } from '../utils'
+import { searchInFileSystem } from '../../../src/searchInFs'
+import { compareCode } from '../../utils'
-import path from 'path'
-import { getFilesList } from '/getFilesList'
+import { fixturesPath } from '../../utils'
+import { getFilesList } from '../../../src/getFilesList'
describe('code patterns', () => {
let filesList = [] as string[]
beforeAll(async () => {
filesList = await getFilesList({
- searchRoot: path.resolve(__dirname, '__fixtures__'),
+ searchRoot: fixturesPath,
omitGitIgnore: true,
})
})
@@ -41,7 +41,7 @@ describe('code patterns', () => {
};
`
- expect(errors.length).toBe(0)
+ expect(errors).toHaveLength(0)
expect(matches.length).toBe(10)
expect(compareCode(matches[0].code, firstResult)).toBeTruthy()
})
@@ -67,7 +67,7 @@ describe('code patterns', () => {
queryCodes: queries,
})
- expect(errors.length).toBe(0)
+ expect(errors).toHaveLength(0)
expect(matches.length).toBe(1)
})
@@ -166,7 +166,7 @@ describe('code patterns', () => {
filePaths: filesList,
queryCodes: queries,
})
- expect(errors.length).toBe(0)
+ expect(errors).toHaveLength(0)
expect(matches.length).toBe(1)
})
@@ -183,7 +183,7 @@ describe('code patterns', () => {
queryCodes: queries,
})
- expect(errors.length).toBe(0)
+ expect(errors).toHaveLength(0)
expect(matches.length).toBe(2)
})
@@ -197,7 +197,7 @@ describe('code patterns', () => {
queryCodes: [query],
})
- expect(errors.length).toBe(0)
+ expect(errors).toHaveLength(0)
expect(matches.length).toBe(3)
expect(matches[2].code).toBe("console.log('Pressed')")
@@ -216,7 +216,7 @@ describe('code patterns', () => {
queryCodes: queries,
})
- expect(errors.length).toBe(0)
+ expect(errors).toHaveLength(0)
expect(matches.length).toBe(6)
})
@@ -233,7 +233,7 @@ describe('code patterns', () => {
queryCodes: queries,
})
- expect(errors.length).toBe(0)
+ expect(errors).toHaveLength(0)
expect(matches.length).toBe(0)
})
})
diff --git a/packages/core/__tests__/search/functions.test.ts b/packages/core/__tests__/TypeScript/searchSmoke/functions.test.ts
similarity index 74%
rename from packages/core/__tests__/search/functions.test.ts
rename to packages/core/__tests__/TypeScript/searchSmoke/functions.test.ts
index 6b1bb08..3b31977 100644
--- a/packages/core/__tests__/search/functions.test.ts
+++ b/packages/core/__tests__/TypeScript/searchSmoke/functions.test.ts
@@ -1,8 +1,8 @@
-import { searchInFileSystem } from '/searchInFs'
-import { compareCode } from '../utils'
-import { searchInStrings } from '/searchInStrings'
-import path from 'path'
-import { getFilesList } from '/getFilesList'
+import { searchInFileSystem } from '../../../src/searchInFs'
+import { compareCode, parserType } from '../../utils'
+import { searchInStrings } from '../../../src/searchInStrings'
+import { fixturesPath } from '../../utils'
+import { getFilesList } from '../../../src/getFilesList'
import fs from 'fs'
describe('functions', () => {
@@ -10,24 +10,11 @@ describe('functions', () => {
beforeAll(async () => {
filesList = await getFilesList({
- searchRoot: path.resolve(__dirname, '__fixtures__'),
+ searchRoot: fixturesPath,
omitGitIgnore: true,
})
})
- const testFileContent = `
- (a,b,c) => {};
- (a,d) => {};
- (a, { b}) => {};
- `
-
- const mockedFilesList = [
- {
- path: 'mock',
- content: testFileContent,
- },
- ]
-
it('should match inline types in function params', () => {
const queries = [
`
@@ -52,7 +39,7 @@ describe('functions', () => {
queryCodes: queries,
})
- expect(errors.length).toBe(0)
+ expect(errors).toHaveLength(0)
expect(matches.length).toBe(4)
})
@@ -79,7 +66,7 @@ describe('functions', () => {
queryCodes: queries,
})
- expect(errors.length).toBe(0)
+ expect(errors).toHaveLength(0)
expect(matches.length).toBe(1)
expect(compareCode(matches[0].code, queries[0])).toBeTruthy()
@@ -109,7 +96,7 @@ describe('functions', () => {
filePaths: filesList,
queryCodes: queries,
})
- expect(errors.length).toBe(0)
+ expect(errors).toHaveLength(0)
expect(matches.length).toBe(1)
})
@@ -136,7 +123,7 @@ describe('functions', () => {
queryCodes: queries,
})
- expect(errors.length).toBe(0)
+ expect(errors).toHaveLength(0)
expect(matches.length).toBe(1)
})
@@ -164,7 +151,7 @@ describe('functions', () => {
queryCodes: queries,
})
- expect(errors.length).toBe(0)
+ expect(errors).toHaveLength(0)
expect(matches.length).toBe(0)
})
@@ -191,7 +178,7 @@ describe('functions', () => {
queryCodes: queries,
})
- expect(errors.length).toBe(0)
+ expect(errors).toHaveLength(0)
expect(matches.length).toBe(0)
})
@@ -219,7 +206,7 @@ describe('functions', () => {
queryCodes: queries,
})
- expect(errors.length).toBe(0)
+ expect(errors).toHaveLength(0)
expect(matches.length).toBe(1)
})
@@ -246,58 +233,7 @@ describe('functions', () => {
queryCodes: queries,
})
- expect(errors.length).toBe(0)
- expect(matches.length).toBe(1)
- })
-
- it('should match function with 2 arguments', () => {
- const queries = [
- `
- ($$_ref1, $$_ref2) => {}
- `,
- ]
-
- const { matches, errors } = searchInStrings({
- mode: 'include',
- files: mockedFilesList,
- queryCodes: queries,
- })
-
- expect(errors.length).toBe(0)
- expect(matches.length).toBe(2)
- })
-
- it('should match function with 2 arguments using double wildcard', () => {
- const queries = [
- `
- ($$_ref1, $$$_ref2) => {}
- `,
- ]
-
- const { matches, errors } = searchInStrings({
- mode: 'include',
- files: mockedFilesList,
- queryCodes: queries,
- })
-
- expect(errors.length).toBe(0)
- expect(matches.length).toBe(3)
- })
-
- it('should match function with 3 arguments', () => {
- const queries = [
- `
- ($$_ref1, $$_ref2, $$_ref3) => {}
- `,
- ]
-
- const { matches, errors } = searchInStrings({
- mode: 'include',
- files: mockedFilesList,
- queryCodes: queries,
- })
-
- expect(errors.length).toBe(0)
+ expect(errors).toHaveLength(0)
expect(matches.length).toBe(1)
})
})
diff --git a/packages/core/__tests__/search/import.test.ts b/packages/core/__tests__/TypeScript/searchSmoke/import.test.ts
similarity index 88%
rename from packages/core/__tests__/search/import.test.ts
rename to packages/core/__tests__/TypeScript/searchSmoke/import.test.ts
index 8db65aa..b4b689f 100644
--- a/packages/core/__tests__/search/import.test.ts
+++ b/packages/core/__tests__/TypeScript/searchSmoke/import.test.ts
@@ -1,14 +1,14 @@
-import { searchInFileSystem } from '/searchInFs'
+import { searchInFileSystem } from '../../../src/searchInFs'
-import path from 'path'
-import { getFilesList } from '/getFilesList'
+import { fixturesPath } from '../../utils'
+import { getFilesList } from '../../../src/getFilesList'
-describe('JSX', () => {
+describe('Import', () => {
let filesList = [] as string[]
beforeAll(async () => {
filesList = await getFilesList({
- searchRoot: path.resolve(__dirname, '__fixtures__'),
+ searchRoot: fixturesPath,
omitGitIgnore: true,
})
})
@@ -26,7 +26,7 @@ describe('JSX', () => {
queryCodes: [query],
})
- expect(errors.length).toBe(0)
+ expect(errors).toHaveLength(0)
expect(matches.length).toBe(1)
})
@@ -43,7 +43,7 @@ describe('JSX', () => {
queryCodes: [query],
})
- expect(errors.length).toBe(0)
+ expect(errors).toHaveLength(0)
expect(matches.length).toBe(0)
})
@@ -100,7 +100,7 @@ describe('JSX', () => {
queryCodes: [query],
})
- expect(errors.length).toBe(0)
+ expect(errors).toHaveLength(0)
expect(matches.length).toBe(2)
})
@@ -114,7 +114,7 @@ describe('JSX', () => {
queryCodes: [query],
})
- expect(errors.length).toBe(0)
+ expect(errors).toHaveLength(0)
expect(matches.length).toBe(2)
})
@@ -129,7 +129,7 @@ describe('JSX', () => {
queryCodes: [query],
})
- expect(errors.length).toBe(0)
+ expect(errors).toHaveLength(0)
expect(matches.length).toBe(6)
})
})
diff --git a/packages/core/__tests__/TypeScript/searchSmoke/multiStatement.test.ts b/packages/core/__tests__/TypeScript/searchSmoke/multiStatement.test.ts
new file mode 100644
index 0000000..64d1a92
--- /dev/null
+++ b/packages/core/__tests__/TypeScript/searchSmoke/multiStatement.test.ts
@@ -0,0 +1,152 @@
+import { searchInFileSystem } from '../../../src/searchInFs'
+import { compareCode, fixturesPath } from '../../utils'
+
+import { getFilesList } from '../../../src/getFilesList'
+
+describe('multi statements', () => {
+ let filesList = [] as string[]
+
+ beforeAll(async () => {
+ filesList = await getFilesList({
+ searchRoot: fixturesPath,
+ omitGitIgnore: true,
+ })
+ })
+
+ it('should match three expressions without block wrapper in function body', () => {
+ const queries = [
+ `
+ toggleRTL();
+ I18nManager.forceRTL(!isRTL);
+ Updates.reloadAsync();
+ `,
+ ]
+
+ const { matches, errors } = searchInFileSystem({
+ mode: 'include',
+ filePaths: filesList,
+ queryCodes: queries,
+ })
+
+ expect(errors).toHaveLength(0)
+ expect(matches.length).toBe(1)
+ })
+
+ it('should match three expressions without block wrapper in function body with exact mode', () => {
+ const queries = [
+ `
+ toggleRTL();
+ I18nManager.forceRTL(!isRTL);
+ Updates.reloadAsync();
+ `,
+ ]
+
+ const { matches, errors } = searchInFileSystem({
+ mode: 'exact',
+ filePaths: filesList,
+ queryCodes: queries,
+ })
+
+ expect(errors).toHaveLength(0)
+ expect(matches.length).toBe(1)
+ })
+
+ it('should match three expressions without block wrapper in function body with different order', () => {
+ const queries = [
+ `
+ Updates.reloadAsync();
+ I18nManager.forceRTL(!isRTL);
+ toggleRTL();
+ `,
+ ]
+
+ const { matches, errors } = searchInFileSystem({
+ mode: 'include',
+ filePaths: filesList,
+ queryCodes: queries,
+ })
+
+ expect(errors).toHaveLength(0)
+ expect(matches.length).toBe(1)
+ })
+
+ it('should match three expressions with block wrapper in function body', () => {
+ const queries = [
+ `
+ {
+ toggleRTL();
+ I18nManager.forceRTL(!isRTL);
+ Updates.reloadAsync();
+ }
+ `,
+ ]
+
+ const { matches, errors } = searchInFileSystem({
+ mode: 'include',
+ filePaths: filesList,
+ queryCodes: queries,
+ })
+
+ expect(errors).toHaveLength(0)
+ expect(matches.length).toBe(1)
+ })
+
+ it('should match two expressions in program body and include middle line in result', () => {
+ const queries = [
+ `
+ import { createStackNavigator } from '@react-navigation/stack';
+ const Stack = createStackNavigator();
+ `,
+ ]
+
+ const { matches, errors } = searchInFileSystem({
+ mode: 'include',
+ filePaths: filesList,
+ queryCodes: queries,
+ })
+
+ expect(errors).toHaveLength(0)
+ expect(matches.length).toBe(1)
+
+ expect(matches[0].code.split('\n').filter(Boolean)).toHaveLength(3)
+ })
+
+ it('should match three expressions in program body and only include them in result (without whole block)', () => {
+ const queries = [
+ `
+ import { createStackNavigator } from '@react-navigation/stack'
+ import ExampleList, { examples } from './ExampleList'
+ const Stack = createStackNavigator()
+ `,
+ ]
+
+ const { matches, errors } = searchInFileSystem({
+ mode: 'include',
+ filePaths: filesList,
+ queryCodes: queries,
+ })
+
+ expect(errors).toHaveLength(0)
+ expect(matches.length).toBe(1)
+
+ expect(compareCode(matches[0].code, queries[0])).toBeTruthy()
+ })
+
+ it('should not match two expressions in program body if order does not match', () => {
+ const queries = [
+ `
+ const Stack = createStackNavigator();
+ import { createStackNavigator } from '@react-navigation/stack';
+ `,
+ ]
+
+ const { matches, errors } = searchInFileSystem({
+ mode: 'include-with-order',
+ filePaths: filesList,
+ queryCodes: queries,
+ })
+
+ expect(errors).toHaveLength(0)
+ expect(matches.length).toBe(0)
+ })
+})
diff --git a/packages/core/__tests__/TypeScript/searchSmoke/objects.test.ts b/packages/core/__tests__/TypeScript/searchSmoke/objects.test.ts
new file mode 100644
index 0000000..8030844
--- /dev/null
+++ b/packages/core/__tests__/TypeScript/searchSmoke/objects.test.ts
@@ -0,0 +1,33 @@
+import { getFilesList } from '../../../src/getFilesList'
+import { searchInFileSystem } from '../../../src/searchInFs'
+import { fixturesPath } from '../../utils'
+
+describe('Objects', () => {
+ it('should match possibly repeated object properties', async () => {
+ const filesList = await getFilesList({
+ searchRoot: fixturesPath,
+ omitGitIgnore: true,
+ })
+
+ const queries = [
+ `
+ StyleSheet.create({
+ $$: {
+ flex: 1,
+ alignItems: 'center',
+ justifyContent: 'center',
+ },
+ });
+ `,
+ ]
+
+ const { matches, errors } = searchInFileSystem({
+ mode: 'include',
+ filePaths: filesList,
+ queryCodes: queries,
+ })
+
+ expect(errors).toHaveLength(0)
+ expect(matches.length).toBe(2)
+ })
+})
diff --git a/packages/core/__tests__/TypeScript/searchSmoke/other.test.ts b/packages/core/__tests__/TypeScript/searchSmoke/other.test.ts
new file mode 100644
index 0000000..a899511
--- /dev/null
+++ b/packages/core/__tests__/TypeScript/searchSmoke/other.test.ts
@@ -0,0 +1,95 @@
+import { fixturesPath } from '../../utils'
+import { useTraverseApproachTestOnly } from '../../../src/testOnlyConfig'
+import { getFilesList } from '../../../src/getFilesList'
+import { searchInFileSystem } from '../../../src/searchInFs'
+
+describe('Other', () => {
+ let filesList = [] as string[]
+
+ beforeAll(async () => {
+ filesList = await getFilesList({
+ searchRoot: fixturesPath,
+ omitGitIgnore: true,
+ })
+ })
+
+ it('should not include the same result twice', () => {
+ const queries = [
+ `
+ type $$ = ScrollViewProps & $$$
+ `,
+ `
+ type $$ = $$$ & ScrollViewProps
+ `,
+ ]
+
+ const { matches, errors } = searchInFileSystem({
+ mode: 'include',
+ filePaths: filesList,
+ queryCodes: queries,
+ })
+
+ expect(errors).toHaveLength(0)
+ expect(matches.length).toBe(1)
+ })
+
+ it('should not include the same result twice 2', () => {
+ const queries = [
+ `
+ <$$$
+ $$={() => {}}
+ />
+ `,
+ `
+ <$$$
+ $$={() => $$$}
+ />
+ `,
+ `
+ <$$$
+ $$={() => {}}
+ >
+ $$$>
+ `,
+ `
+ <$$$
+ $$={() => $$$}
+ >
+ $$$>
+ `,
+ ]
+
+ const { matches, errors } = searchInFileSystem({
+ mode: 'include',
+ filePaths: filesList,
+ queryCodes: queries,
+ })
+
+ expect(errors).toHaveLength(0)
+ expect(matches.length).toBe(190)
+ })
+
+ it('should match anything', () => {
+ const queries = [
+ `
+ $$$
+ `,
+ ]
+
+ const { matches, errors } = searchInFileSystem({
+ mode: 'include',
+ filePaths: filesList,
+ queryCodes: queries,
+ })
+
+ const countForTraversalMode = 6381 // will just match identifier-like nodes
+ const countForNonTraversalMode = 17149 // will match any node
+
+ const expectedCount = useTraverseApproachTestOnly
+ ? countForTraversalMode
+ : countForNonTraversalMode
+
+ expect(errors).toHaveLength(0)
+ expect(matches.length).toBe(expectedCount)
+ })
+})
diff --git a/packages/core/__tests__/search/__fixturesOther__/textSearch.ts b/packages/core/__tests__/__fixturesOther__/textSearch.ts
similarity index 100%
rename from packages/core/__tests__/search/__fixturesOther__/textSearch.ts
rename to packages/core/__tests__/__fixturesOther__/textSearch.ts
diff --git a/packages/core/__tests__/getFilesList.test.ts b/packages/core/__tests__/common/getFilesList.test.ts
similarity index 91%
rename from packages/core/__tests__/getFilesList.test.ts
rename to packages/core/__tests__/common/getFilesList.test.ts
index 74452fc..8945b62 100644
--- a/packages/core/__tests__/getFilesList.test.ts
+++ b/packages/core/__tests__/common/getFilesList.test.ts
@@ -1,5 +1,9 @@
import mockFs from 'mock-fs'
-import { getFilesList, getFsRoot, filterIncludeExclude } from '/getFilesList'
+import {
+ getFilesList,
+ getFsRoot,
+ filterIncludeExclude,
+} from '../../src/getFilesList'
import dedent from 'dedent'
afterEach(() => {
@@ -269,6 +273,41 @@ it('should return files for project root with omitting gitignore', async () => {
)
})
+it('should use .gitignore only within the current repository', async () => {
+ mockFs({
+ [root]: {
+ '.git': {},
+ project: {
+ 'fileA.ts': 'content',
+ '.gitignore': 'packageA/*',
+ packageA: {
+ '.git': {},
+ '.env': 'content',
+ '.gitignore': `
+ .env
+ `,
+ src: {
+ 'fileE.json': '',
+ },
+ },
+ },
+ },
+ })
+
+ const filesList = removeCwd(
+ await getFilesList({
+ searchRoot: toPlatformSpecificPath(`${root}/project/packageA`),
+ }),
+ )
+ mockFs.restore()
+
+ expect(filesList.sort()).toMatchObject(
+ [`${root}/project/packageA/src/fileE.json`]
+ .sort()
+ .map(toPlatformSpecificPath),
+ )
+})
+
// We will add option to search in ignored files, so that exception is not needed
it.skip('should return files for project root ignored by parent gitignore, but ignore the nested directories', async () => {
mockFs({
@@ -317,6 +356,7 @@ it.skip('should return files for project root ignored by parent gitignore, but i
it('should ignore files from parent .gitignore', async () => {
mockFs({
[root]: {
+ '.git': {},
project: {
'fileA.ts': 'content',
'fileB.js': 'content',
diff --git a/packages/core/__tests__/common/matchContext.test.ts b/packages/core/__tests__/common/matchContext.test.ts
new file mode 100644
index 0000000..d099d82
--- /dev/null
+++ b/packages/core/__tests__/common/matchContext.test.ts
@@ -0,0 +1,50 @@
+import { createMatchContext } from '../../src/matchContext'
+
+describe('Match context data structure', () => {
+ it('should prove creating new match context form other outputs independent data structure', () => {
+ const first = createMatchContext()
+
+ first.addIdentifierAlias({
+ wildcard: '$$',
+ alias: 'ref',
+ aliasValue: 'identifier',
+ })
+
+ const second = createMatchContext(first.getAllAliases())
+
+ second.addIdentifierAlias({
+ wildcard: '$$',
+ alias: 'ref2',
+ aliasValue: 'identifier2',
+ })
+
+ expect(first.getIdentifierAlias('ref')?.aliasValue).toBe('identifier')
+ expect(first.getIdentifierAlias('ref2')).toBe(null)
+
+ expect(second.getIdentifierAlias('ref')?.aliasValue).toBe('identifier')
+ expect(second.getIdentifierAlias('ref2')?.aliasValue).toBe('identifier2')
+ })
+
+ it('should merge one context into another', () => {
+ const first = createMatchContext()
+
+ first.addIdentifierAlias({
+ wildcard: '$$',
+ alias: 'ref',
+ aliasValue: 'identifier',
+ })
+
+ const second = createMatchContext()
+
+ second.addIdentifierAlias({
+ wildcard: '$$',
+ alias: 'ref2',
+ aliasValue: 'identifier2',
+ })
+
+ first.merge(second.getAllAliases())
+
+ expect(first.getIdentifierAlias('ref')?.aliasValue).toBe('identifier')
+ expect(first.getIdentifierAlias('ref2')?.aliasValue).toBe('identifier2')
+ })
+})
diff --git a/packages/core/__tests__/utils.test.ts b/packages/core/__tests__/common/utils.test.ts
similarity index 94%
rename from packages/core/__tests__/utils.test.ts
rename to packages/core/__tests__/common/utils.test.ts
index 87a2858..68a3ce8 100644
--- a/packages/core/__tests__/utils.test.ts
+++ b/packages/core/__tests__/common/utils.test.ts
@@ -1,8 +1,12 @@
-import { getExtendedCodeFrame, regExpTest } from '/utils'
+import { getExtendedCodeFrame, regExpTest } from '../../src/utils'
import dedent from 'dedent'
-import { createWildcardUtils } from '/wildcardUtilsFactory'
+import { createWildcardUtils } from '../../src/wildcardUtilsFactory'
+import { PoorNodeType } from '../../src/types'
describe('Utils', () => {
+ const getIdentifierNodeName = (node: PoorNodeType) => node.name as string
+ const getNodeType = (node: PoorNodeType) => node.type as string
+
const identifierTypes: string[] = [] // not needed for this test
const numericWildcard = '0x0'
const wildcardChar = '$'
@@ -10,6 +14,8 @@ describe('Utils', () => {
identifierTypes,
numericWildcard,
wildcardChar,
+ getIdentifierNodeName,
+ getNodeType,
)
describe('should transform strings to regexes', () => {
diff --git a/packages/core/__tests__/search/other.test.ts b/packages/core/__tests__/search/other.test.ts
deleted file mode 100644
index 94df540..0000000
--- a/packages/core/__tests__/search/other.test.ts
+++ /dev/null
@@ -1,176 +0,0 @@
-import path from 'path'
-import { useTraverseApproachTestOnly } from '../../src/config'
-import { searchInStrings } from '../../src/searchInStrings'
-import { getFilesList } from '/getFilesList'
-import { searchInFileSystem } from '/searchInFs'
-
-describe('Other', () => {
- let filesList = [] as string[]
-
- beforeAll(async () => {
- filesList = await getFilesList({
- searchRoot: path.resolve(__dirname, '__fixtures__'),
- omitGitIgnore: true,
- })
- })
-
- it('should not include the same result twice', () => {
- const queries = [
- `
- type $$ = ScrollViewProps & $$$
- `,
- `
- type $$ = $$$ & ScrollViewProps
- `,
- ]
-
- const { matches, errors } = searchInFileSystem({
- mode: 'include',
- filePaths: filesList,
- queryCodes: queries,
- })
-
- expect(errors.length).toBe(0)
- expect(matches.length).toBe(1)
- })
-
- it('should not include the same result twice 2', () => {
- const queries = [
- `
- <$$$
- $$={() => {}}
- />
- `,
- `
- <$$$
- $$={() => $$$}
- />
- `,
- `
- <$$$
- $$={() => {}}
- >
- $$$>
- `,
- `
- <$$$
- $$={() => $$$}
- >
- $$$>
- `,
- ]
-
- const { matches, errors } = searchInFileSystem({
- mode: 'include',
- filePaths: filesList,
- queryCodes: queries,
- })
-
- expect(errors).toHaveLength(0)
- expect(matches.length).toBe(190)
- })
-
- it('should match anything', () => {
- const queries = [
- `
- $$$
- `,
- ]
-
- const { matches, errors } = searchInFileSystem({
- mode: 'include',
- filePaths: filesList,
- queryCodes: queries,
- })
-
- const countForTraversalMode = 6381 // will just match identifier-like nodes
- const countForNonTraversalMode = 17149 // will match any node
-
- const expectedCount = useTraverseApproachTestOnly
- ? countForTraversalMode
- : countForNonTraversalMode
-
- expect(errors.length).toBe(0)
- expect(matches.length).toBe(expectedCount)
- })
-
- it('Should properly match identifiers with multiple wildcard sections', () => {
- const fileContent = `
- varOne;
- var_two;
- `
-
- const queries = [`$$_$$`]
-
- const { matches, errors } = searchInStrings({
- mode: 'exact',
- caseInsensitive: true,
- queryCodes: queries,
- files: [
- {
- path: 'mock',
- content: fileContent,
- },
- ],
- })
-
- expect(errors.length).toBe(0)
- expect(matches.length).toBe(1)
- })
-
- it('Should match try-catch block with statement and re-throw of error', () => {
- const fileContent = `
- try {
- await bla.bla.bla
- } catch (error) {
- logger.error(error);
- throw error;
- }
- `
-
- const queries = [`try {} catch($$) { Logger.error($$); throw $$ }`]
-
- const { matches, errors } = searchInStrings({
- mode: 'include',
- caseInsensitive: true,
- queryCodes: queries,
- files: [
- {
- path: 'mock',
- content: fileContent,
- },
- ],
- })
-
- expect(errors.length).toBe(0)
- expect(matches.length).toBe(1)
- })
-
- it('Should match class with static method', () => {
- const fileContent = `
- class Test {
- method() { return 0 }
- static getInstance(){
- return new Test()
- }
- }
- `
-
- const queries = [`class $$ {static getInstance(){}}`]
-
- const { matches, errors } = searchInStrings({
- mode: 'include',
- caseInsensitive: true,
- queryCodes: queries,
- files: [
- {
- path: 'mock',
- content: fileContent,
- },
- ],
- })
-
- expect(errors.length).toBe(0)
- expect(matches.length).toBe(1)
- })
-})
diff --git a/packages/core/__tests__/utils.ts b/packages/core/__tests__/utils.ts
index e34e0d1..352b274 100644
--- a/packages/core/__tests__/utils.ts
+++ b/packages/core/__tests__/utils.ts
@@ -1,8 +1,13 @@
-import { compareCode as compareCodeBase } from '/astUtils'
-import { ParserType } from '/types'
+import {
+ compareCode as compareCodeBase,
+ compareAst as compareAstBase,
+} from '../src/astUtils'
+import { PoorNodeType } from '../src/types'
import { parserSettingsMap } from '../src/parserSettings/index'
+import path from 'path'
+import { testParserTypeOverride } from '../src/testOnlyConfig'
-const parserType = process.env.TEST_PARSER_TYPE as ParserType
+export const parserType = testParserTypeOverride
export const getParserSettings = () => {
if (parserType === undefined) {
@@ -19,3 +24,31 @@ export const compareCode = (codeA: string, codeB: string) => {
return compareCodeBase(codeA, codeB, parserSettings)
}
+
+export const compareAst = (astA: PoorNodeType, astB: PoorNodeType) => {
+ const parserSettings = getParserSettings()
+
+ return compareAstBase(astA, astB, parserSettings)
+}
+
+export const compareAstToCode = (ast: PoorNodeType, code: string) => {
+ const parserSettings = getParserSettings()
+
+ const astFromCode = parserSettings.unwrapExpressionStatement(
+ parserSettings.getProgramBodyFromRootNode(
+ parserSettings.parseCode(code),
+ )[0],
+ )
+
+ return compareAstBase(ast, astFromCode, parserSettings)
+}
+
+export const fixturesPath = path.resolve(
+ process.cwd(),
+ '__tests__/__fixtures__',
+)
+
+export const fixturesOtherPath = path.resolve(
+ process.cwd(),
+ '__tests__/__fixturesOther__',
+)
diff --git a/packages/core/declarations.d.ts b/packages/core/declarations.d.ts
new file mode 100644
index 0000000..2df47c9
--- /dev/null
+++ b/packages/core/declarations.d.ts
@@ -0,0 +1,3 @@
+declare module '@babel/eslint-parser'
+declare module 'espree'
+declare module '@angular-eslint/template-parser'
diff --git a/packages/core/jest.config.js b/packages/core/jest.config.js
index 58ef380..a6c114c 100644
--- a/packages/core/jest.config.js
+++ b/packages/core/jest.config.js
@@ -1,25 +1,187 @@
-const { pathsToModuleNameMapper } = require('ts-jest')
-const fs = require('fs')
+const sharedConfig = {
+ preset: 'ts-jest',
+ testEnvironment: 'node',
+ setupFiles: ['/jest/shared.setup.ts'],
+}
+
+const javaScriptWithJSXParserTestFiles = [
+ '/__tests__/JavaScript/**/*.test.ts',
+ '/__tests__/JavaScriptWithJSX/**/*.test.ts',
+]
-const tsConfig = JSON.parse(
- fs
- .readFileSync(__dirname + '/tsconfig.json')
- .toString()
- .replace(/^(\s)*\/\//gm, '')
- .replace(/\/\*.+?\*\//gm, ''),
-)
+const typeScriptParserTestFiles = [
+ '/__tests__/JavaScript/**/*.test.ts',
+ '/__tests__/JavaScriptWithJSX/**/*.test.ts',
+ '/__tests__/TypeScript/**/*.test.ts',
+]
+
+const htmlParserTestFiles = ['/__tests__/HTML/**/*.test.ts']
+const cssParserTestFiles = ['/__tests__/CSS/**/*.test.ts']
+const pythonParserTestFiles = ['/__tests__/Python/**/*.test.ts']
+const luaParserTestFiles = ['/__tests__/Lua/**/*.test.ts']
+const csharpParserTestFiles = ['/__tests__/CSharp/**/*.test.ts']
module.exports = {
- preset: 'ts-jest',
- testEnvironment: 'node',
- moduleNameMapper: pathsToModuleNameMapper(tsConfig.compilerOptions.paths, {
- prefix: '',
- }),
testPathIgnorePatterns: [
'__fixtures__',
'__fixturesOther__',
'ts-dist',
'utils.ts',
],
- setupFiles: ['./jest.setup.js'],
+ projects: [
+ {
+ displayName: { name: 'common', color: 'white' },
+ ...sharedConfig,
+ testMatch: ['/__tests__/common/**/*.test.ts'],
+ },
+ {
+ displayName: { name: 'text-search', color: 'cyan' },
+ ...sharedConfig,
+ testMatch: ['/__tests__/TextSearch/**/*.test.ts'],
+ },
+ {
+ ...sharedConfig,
+ displayName: { name: 'typescript-eslint-parser', color: 'magenta' },
+ testMatch: typeScriptParserTestFiles,
+ setupFiles: [
+ '/jest/shared.setup.ts',
+ '/jest/typescript-eslint-parser.setup.ts',
+ ],
+ },
+ {
+ ...sharedConfig,
+ displayName: {
+ name: 'typescript-eslint-parser:traversal',
+ color: 'magenta',
+ },
+ testMatch: typeScriptParserTestFiles,
+ setupFiles: [
+ '/jest/shared.setup.ts',
+ '/jest/typescript-eslint-parser:traversal.setup.ts',
+ ],
+ },
+ {
+ ...sharedConfig,
+ displayName: { name: 'babel', color: 'yellow' },
+ testMatch: typeScriptParserTestFiles,
+ setupFiles: [
+ '/jest/shared.setup.ts',
+ '/jest/babel.setup.ts',
+ ],
+ },
+ {
+ ...sharedConfig,
+ displayName: {
+ name: 'babel:traversal',
+ color: 'yellow',
+ },
+ testMatch: typeScriptParserTestFiles,
+ setupFiles: [
+ '/jest/shared.setup.ts',
+ '/jest/babel:traversal.setup.ts',
+ ],
+ },
+ {
+ ...sharedConfig,
+ displayName: { name: 'babel-eslint-parser', color: 'yellow' },
+ testMatch: javaScriptWithJSXParserTestFiles,
+ setupFiles: [
+ '/jest/shared.setup.ts',
+ '/jest/babel-eslint-parser.setup.ts',
+ ],
+ },
+ {
+ ...sharedConfig,
+ displayName: {
+ name: 'babel-eslint-parser:traversal',
+ color: 'yellow',
+ },
+ testMatch: javaScriptWithJSXParserTestFiles,
+ setupFiles: [
+ '/jest/shared.setup.ts',
+ '/jest/babel-eslint-parser:traversal.setup.ts',
+ ],
+ },
+ {
+ ...sharedConfig,
+ displayName: { name: 'esprima', color: 'gray' },
+ testMatch: javaScriptWithJSXParserTestFiles,
+ setupFiles: [
+ '/jest/shared.setup.ts',
+ '/jest/esprima.setup.ts',
+ ],
+ },
+ {
+ ...sharedConfig,
+ displayName: { name: 'esprima:traversal', color: 'gray' },
+ testMatch: javaScriptWithJSXParserTestFiles,
+ setupFiles: [
+ '/jest/shared.setup.ts',
+ '/jest/esprima:traversal.setup.ts',
+ ],
+ },
+ {
+ ...sharedConfig,
+ displayName: { name: 'espree', color: 'blue' },
+ testMatch: javaScriptWithJSXParserTestFiles,
+ setupFiles: [
+ '/jest/shared.setup.ts',
+ '/jest/espree.setup.ts',
+ ],
+ },
+ {
+ ...sharedConfig,
+ displayName: { name: 'espree:traversal', color: 'blue' },
+ testMatch: javaScriptWithJSXParserTestFiles,
+ setupFiles: [
+ '/jest/shared.setup.ts',
+ '/jest/espree:traversal.setup.ts',
+ ],
+ },
+ {
+ ...sharedConfig,
+ displayName: { name: 'angular-eslint-template-parser', color: 'orange' },
+ testMatch: htmlParserTestFiles,
+ setupFiles: [
+ '/jest/shared.setup.ts',
+ '/jest/angular-eslint-template-parser.setup.ts',
+ ],
+ },
+ {
+ ...sharedConfig,
+ displayName: { name: 'css-tree', color: 'blue' },
+ testMatch: cssParserTestFiles,
+ setupFiles: [
+ '/jest/shared.setup.ts',
+ '/jest/css-tree.setup.ts',
+ ],
+ },
+ {
+ ...sharedConfig,
+ displayName: { name: 'python', color: 'blue' },
+ testMatch: pythonParserTestFiles,
+ setupFiles: [
+ '/jest/shared.setup.ts',
+ '/jest/python.setup.ts',
+ ],
+ },
+ {
+ ...sharedConfig,
+ displayName: { name: 'lua', color: 'gray' },
+ testMatch: luaParserTestFiles,
+ setupFiles: [
+ '/jest/shared.setup.ts',
+ '/jest/lua.setup.ts',
+ ],
+ },
+ {
+ ...sharedConfig,
+ displayName: { name: 'csharp', color: 'magenta' },
+ testMatch: csharpParserTestFiles,
+ setupFiles: [
+ '/jest/shared.setup.ts',
+ '/jest/csharp.setup.ts',
+ ],
+ },
+ ],
}
diff --git a/packages/core/jest.setup.js b/packages/core/jest.setup.js
deleted file mode 100644
index b1e2bd6..0000000
--- a/packages/core/jest.setup.js
+++ /dev/null
@@ -1 +0,0 @@
-process.env.NODE_ENV = 'test'
diff --git a/packages/core/jest/angular-eslint-template-parser.setup.ts b/packages/core/jest/angular-eslint-template-parser.setup.ts
new file mode 100644
index 0000000..518c002
--- /dev/null
+++ b/packages/core/jest/angular-eslint-template-parser.setup.ts
@@ -0,0 +1,4 @@
+global.testSettings = {
+ parserType: 'angular-eslint-template-parser',
+ isTraversal: false,
+}
diff --git a/packages/core/jest/babel-eslint-parser.setup.ts b/packages/core/jest/babel-eslint-parser.setup.ts
new file mode 100644
index 0000000..42e8fa9
--- /dev/null
+++ b/packages/core/jest/babel-eslint-parser.setup.ts
@@ -0,0 +1,4 @@
+global.testSettings = {
+ parserType: 'babel-eslint-parser',
+ isTraversal: false,
+}
diff --git a/packages/core/jest/babel-eslint-parser:traversal.setup.ts b/packages/core/jest/babel-eslint-parser:traversal.setup.ts
new file mode 100644
index 0000000..2ada1d1
--- /dev/null
+++ b/packages/core/jest/babel-eslint-parser:traversal.setup.ts
@@ -0,0 +1,4 @@
+global.testSettings = {
+ parserType: 'babel-eslint-parser',
+ isTraversal: true,
+}
diff --git a/packages/core/jest/babel.setup.ts b/packages/core/jest/babel.setup.ts
new file mode 100644
index 0000000..5f7cc46
--- /dev/null
+++ b/packages/core/jest/babel.setup.ts
@@ -0,0 +1,4 @@
+global.testSettings = {
+ parserType: 'babel',
+ isTraversal: false,
+}
diff --git a/packages/core/jest/babel:traversal.setup.ts b/packages/core/jest/babel:traversal.setup.ts
new file mode 100644
index 0000000..d7cbbef
--- /dev/null
+++ b/packages/core/jest/babel:traversal.setup.ts
@@ -0,0 +1,4 @@
+global.testSettings = {
+ parserType: 'babel',
+ isTraversal: true,
+}
diff --git a/packages/core/jest/csharp.setup.ts b/packages/core/jest/csharp.setup.ts
new file mode 100644
index 0000000..2151adc
--- /dev/null
+++ b/packages/core/jest/csharp.setup.ts
@@ -0,0 +1,4 @@
+global.testSettings = {
+ parserType: 'csharp',
+ isTraversal: false,
+}
diff --git a/packages/core/jest/css-tree.setup.ts b/packages/core/jest/css-tree.setup.ts
new file mode 100644
index 0000000..014a917
--- /dev/null
+++ b/packages/core/jest/css-tree.setup.ts
@@ -0,0 +1,4 @@
+global.testSettings = {
+ parserType: 'css-tree',
+ isTraversal: false,
+}
diff --git a/packages/core/jest/espree.setup.ts b/packages/core/jest/espree.setup.ts
new file mode 100644
index 0000000..a773abc
--- /dev/null
+++ b/packages/core/jest/espree.setup.ts
@@ -0,0 +1,4 @@
+global.testSettings = {
+ parserType: 'espree',
+ isTraversal: false,
+}
diff --git a/packages/core/jest/espree:traversal.setup.ts b/packages/core/jest/espree:traversal.setup.ts
new file mode 100644
index 0000000..02d3041
--- /dev/null
+++ b/packages/core/jest/espree:traversal.setup.ts
@@ -0,0 +1,4 @@
+global.testSettings = {
+ parserType: 'espree',
+ isTraversal: true,
+}
diff --git a/packages/core/jest/esprima.setup.ts b/packages/core/jest/esprima.setup.ts
new file mode 100644
index 0000000..3d0f844
--- /dev/null
+++ b/packages/core/jest/esprima.setup.ts
@@ -0,0 +1,4 @@
+global.testSettings = {
+ parserType: 'esprima',
+ isTraversal: false,
+}
diff --git a/packages/core/jest/esprima:traversal.setup.ts b/packages/core/jest/esprima:traversal.setup.ts
new file mode 100644
index 0000000..87df7d7
--- /dev/null
+++ b/packages/core/jest/esprima:traversal.setup.ts
@@ -0,0 +1,4 @@
+global.testSettings = {
+ parserType: 'esprima',
+ isTraversal: true,
+}
diff --git a/packages/core/jest/lua.setup.ts b/packages/core/jest/lua.setup.ts
new file mode 100644
index 0000000..70af4be
--- /dev/null
+++ b/packages/core/jest/lua.setup.ts
@@ -0,0 +1,4 @@
+global.testSettings = {
+ parserType: 'lua',
+ isTraversal: false,
+}
diff --git a/packages/core/jest/python.setup.ts b/packages/core/jest/python.setup.ts
new file mode 100644
index 0000000..3605358
--- /dev/null
+++ b/packages/core/jest/python.setup.ts
@@ -0,0 +1,4 @@
+global.testSettings = {
+ parserType: 'python',
+ isTraversal: false,
+}
diff --git a/packages/core/jest/shared.setup.ts b/packages/core/jest/shared.setup.ts
new file mode 100644
index 0000000..cae8393
--- /dev/null
+++ b/packages/core/jest/shared.setup.ts
@@ -0,0 +1,12 @@
+process.env.NODE_ENV = 'test'
+
+global.console = {
+ ...console,
+ warn: (...inputs) => {
+ if (typeof inputs[0] === 'string' && inputs[0].includes('Browserslist')) {
+ return
+ } else {
+ return console.log('console.warn', ...inputs)
+ }
+ },
+}
diff --git a/packages/core/jest/typescript-eslint-parser.setup.ts b/packages/core/jest/typescript-eslint-parser.setup.ts
new file mode 100644
index 0000000..7ca8b6c
--- /dev/null
+++ b/packages/core/jest/typescript-eslint-parser.setup.ts
@@ -0,0 +1,4 @@
+global.testSettings = {
+ parserType: 'typescript-eslint-parser',
+ isTraversal: false,
+}
diff --git a/packages/core/jest/typescript-eslint-parser:traversal.setup.ts b/packages/core/jest/typescript-eslint-parser:traversal.setup.ts
new file mode 100644
index 0000000..62bb4ff
--- /dev/null
+++ b/packages/core/jest/typescript-eslint-parser:traversal.setup.ts
@@ -0,0 +1,4 @@
+global.testSettings = {
+ parserType: 'typescript-eslint-parser',
+ isTraversal: true,
+}
diff --git a/packages/core/package.json b/packages/core/package.json
index fc6b395..ce75449 100644
--- a/packages/core/package.json
+++ b/packages/core/package.json
@@ -1,7 +1,7 @@
{
"name": "@codeque/core",
- "version": "0.4.0",
- "description": "Supercharged multiline code search and replace tool",
+ "version": "0.6.1",
+ "description": "Multiline code search for every language. Structural code search for JavaScript, TypeScript, HTML and CSS",
"author": "Jakub Mazurek (@jayu) ",
"license": "Sustainable Use License",
"engines": {
@@ -26,10 +26,13 @@
"url": "https://github.com/codeque-co/codeque"
},
"devDependencies": {
+ "@angular-eslint/template-parser": "^15.2.1",
+ "@babel/eslint-parser": "7.28.5",
+ "@babel/generator": "7.28.5",
"@types/dedent": "^0.7.0",
"@types/esprima": "^4.0.3",
"@types/glob": "^7.2.0",
- "@types/jest": "^27.0.3",
+ "@types/jest": "^29.4.0",
"@types/mock-fs": "^4.13.1",
"@types/node-fetch": "^3.0.3",
"@types/object.omit": "^3.0.0",
@@ -39,43 +42,58 @@
"babel-jest": "^27.4.4",
"babel-plugin-root-import": "^6.6.0",
"concurrently": "^7.2.1",
+ "css-tree": "^2.3.1",
"deep-object-diff": "^1.1.7",
+ "espree": "^9.5.2",
"esprima": "^4.0.1",
"jest": "^27.4.4",
"mock-fs": "^5.1.2",
"node-fetch-commonjs": "^3.1.1",
"release-it": "^15.0.0",
"ts-jest": "^27.1.1",
- "unzipper": "^0.10.11"
+ "unzipper": "^0.10.11",
+ "typescript": "5.9.3"
},
"dependencies": {
- "@babel/parser": "7.19.4",
- "@babel/plugin-syntax-typescript": "7.18.6",
- "@babel/types": "7.19.4",
+ "@babel/parser": "7.28.5",
+ "@babel/plugin-syntax-typescript": "7.27.1",
+ "@types/css-tree": "^2.3.1",
"dedent": "^0.7.0",
"dpdm": "^3.12.0",
"glob-escape": "^0.0.2",
"ignore": "^5.1.9",
- "minimatch": "^5.1.0"
+ "minimatch": "^5.1.0",
+ "web-tree-sitter": "^0.20.8"
},
"peerDependencies": {
"@typescript-eslint/parser": "^5.50.0",
"esprima": "^4.0.1"
},
"scripts": {
- "build": "rm -rf dist && concurrently \"yarn build:declarations\" \"BABEL_ENV=production yarn build:code\" ",
+ "build": "rm -rf dist && concurrently \"yarn build:declarations\" \"BABEL_ENV=production yarn build:code\"",
"build:performance": "rm -rf dist && concurrently \"yarn build:declarations\" \"BABEL_ENV=production_performance yarn build:code\" ",
"build:test": "rm -rf dist && concurrently \"yarn build:declarations\" \"BABEL_ENV=test yarn build:code\" ",
"build:watch": "rm -rf dist && concurrently \"yarn build:declarations --watch\" \"yarn build:code --watch\" ",
"build:declarations": "tsc --project tsconfig.build.json",
"build:code": "babel ./src --extensions \".ts,.tsx\" -d dist",
"typecheck": "tsc --project tsconfig.json",
- "test": "yarn build:test && yarn test:babel && yarn test:typescript-eslint && yarn test:babel:traversal && yarn test:typescript-eslint:traversal",
- "test:babel": "TEST_PARSER_TYPE=babel jest",
- "test:babel:traversal": "TEST_PARSER_TYPE=babel TEST_TRAVERSAL=true jest",
- "test:typescript-eslint": "TEST_PARSER_TYPE=typescript-eslint jest",
- "test:typescript-eslint:traversal": "TEST_PARSER_TYPE=typescript-eslint TEST_TRAVERSAL=true jest",
- "test:esprima": "TEST_PARSER_TYPE=esprima jest",
+ "test": "yarn build:test && NODE_OPTIONS=--max-old-space-size=4000 yarn jest --maxWorkers=25%",
+ "test:babel": "jest --selectProjects=babel",
+ "test:common": "jest --selectProjects=common",
+ "test:babel:traversal": "jest --selectProjects=babel:traversal",
+ "test:babel-eslint-parser": "jest --selectProjects=babel-eslint-parser",
+ "test:babel-eslint-parser:traversal": "jest --selectProjects=babel-eslint-parser:traversal",
+ "test:typescript-eslint-parser": "jest --selectProjects=typescript-eslint-parser",
+ "test:typescript-eslint-parser:traversal": "jest --selectProjects=typescript-eslint-parser:traversal",
+ "test:esprima": "jest --selectProjects=esprima",
+ "test:esprima:traversal": "jest --selectProjects=esprima:traversal",
+ "test:espree": "jest --selectProjects=espree",
+ "test:espree:traversal": "jest --selectProjects=espree:traversal",
+ "test:angular-eslint-template-parser": "jest --selectProjects=angular-eslint-template-parser",
+ "test:python": "jest --selectProjects=python",
+ "test:lua": "jest --selectProjects=lua",
+ "test:csharp": "jest --selectProjects=csharp",
+ "test:css-tree": "jest --selectProjects=css-tree",
"test:circular": "dpdm --exit-code circular:1 --tree=false --warning=false './src/**'",
"test:setup": "node ./tools/getFixtures.js",
"lint": "eslint --ext .js,.ts src",
@@ -112,4 +130,4 @@
"regexp search",
"json search"
]
-}
\ No newline at end of file
+}
diff --git a/packages/core/src/astUtils.ts b/packages/core/src/astUtils.ts
index becb3db..4af9f88 100644
--- a/packages/core/src/astUtils.ts
+++ b/packages/core/src/astUtils.ts
@@ -1,4 +1,5 @@
-import { PoorNodeType, ParserSettings, WildcardUtils, Match } from './types'
+import { MatchContextAliases } from './matchContext'
+import { Match, ParserSettings, PoorNodeType, WildcardUtils } from './types'
import { isNullOrUndef } from './utils'
export const isNodeArray = (
@@ -31,19 +32,22 @@ const isNodeKey = (
node: PoorNodeType,
key: string,
keysToCheck: ParserSettings['astPropsToSkip'],
+ getNodeType: ParserSettings['getNodeType'],
) =>
+ key.startsWith('__') ||
keysToCheck.some((keyToCheck) =>
typeof keyToCheck === 'string'
? key === keyToCheck
- : node.type === keyToCheck.type && keyToCheck.key === key,
+ : getNodeType(node) === keyToCheck.type && keyToCheck.key === key,
)
export const getKeysToCompare = (
node: PoorNodeType,
astPropsToSkip: ParserSettings['astPropsToSkip'],
+ getNodeType: ParserSettings['getNodeType'],
) => {
return Object.keys(node).filter(
- (key) => !isNodeKey(node, key, astPropsToSkip),
+ (key) => !isNodeKey(node, key, astPropsToSkip, getNodeType),
)
}
@@ -52,12 +56,12 @@ export const getSetsOfKeysToCompare = (
queryNode: PoorNodeType,
isExact: boolean,
astPropsToSkip: ParserSettings['astPropsToSkip'],
- isNodeFieldOptional: ParserSettings['isNodeFieldOptional'],
+ getNodeType: ParserSettings['getNodeType'],
) => {
- const allFileKeys = getKeysToCompare(fileNode, astPropsToSkip)
- const allQueryKeys = getKeysToCompare(queryNode, astPropsToSkip)
+ const allFileKeys = getKeysToCompare(fileNode, astPropsToSkip, getNodeType)
+ const allQueryKeys = getKeysToCompare(queryNode, astPropsToSkip, getNodeType)
- if (isExact || fileNode.type !== queryNode.type) {
+ if (isExact || getNodeType(fileNode) !== getNodeType(queryNode)) {
return [allFileKeys, allQueryKeys, allFileKeys, allQueryKeys]
}
@@ -71,8 +75,7 @@ export const getSetsOfKeysToCompare = (
const fileKeysToRemove = allFileKeys.filter(
(fileKey) =>
- (!allQueryKeys.includes(fileKey) || isNullOrUndef(queryNode[fileKey])) &&
- isNodeFieldOptional(fileNode.type as string, fileKey),
+ !allQueryKeys.includes(fileKey) || isNullOrUndef(queryNode[fileKey]),
)
const includeFileKeys = allFileKeys.filter(
@@ -92,11 +95,12 @@ export const getSetsOfKeysToCompare = (
const removeKeysFromNode = (
obj: PoorNodeType,
keys: ParserSettings['astPropsToSkip'],
+ getNodeType: ParserSettings['getNodeType'],
) => {
const newObj = {} as PoorNodeType
Object.entries(obj).forEach(([key, val]) => {
- if (!isNodeKey(obj, key, keys)) {
+ if (!isNodeKey(obj, key, keys, getNodeType)) {
newObj[key] = val
}
})
@@ -110,12 +114,15 @@ export const cleanupAst = (
isNode: ParserSettings['isNode']
shouldCompareNode: ParserSettings['shouldCompareNode']
astPropsToSkip: ParserSettings['astPropsToSkip']
- sanitizeNode: ParserSettings['sanitizeNode']
+ getSanitizedNodeValue: ParserSettings['getSanitizedNodeValue']
+ getNodeType: ParserSettings['getNodeType']
},
) => {
- parserSettings.sanitizeNode(ast)
-
- const cleanedAst = removeKeysFromNode(ast, parserSettings.astPropsToSkip)
+ const cleanedAst = removeKeysFromNode(
+ ast,
+ parserSettings.astPropsToSkip,
+ parserSettings.getNodeType,
+ )
Object.keys(cleanedAst).forEach((key) => {
if (parserSettings.isNode(cleanedAst[key] as PoorNodeType)) {
@@ -123,40 +130,78 @@ export const cleanupAst = (
cleanedAst[key] as PoorNodeType,
parserSettings,
)
- }
-
- if (isNodeArray(cleanedAst[key] as PoorNodeType[], parserSettings.isNode)) {
+ } else if (
+ isNodeArray(cleanedAst[key] as PoorNodeType[], parserSettings.isNode)
+ ) {
cleanedAst[key] = (cleanedAst[key] as PoorNodeType[])
.filter(parserSettings.shouldCompareNode)
.map((subAst) => cleanupAst(subAst, parserSettings))
+ } else {
+ cleanedAst[key] = parserSettings.getSanitizedNodeValue(
+ parserSettings.getNodeType(cleanedAst),
+ key,
+ cleanedAst[key],
+ )
}
})
return cleanedAst
}
+type CompareCodeParserSettingsSubset = {
+ isNode: ParserSettings['isNode']
+ shouldCompareNode: ParserSettings['shouldCompareNode']
+ astPropsToSkip: ParserSettings['astPropsToSkip']
+ parseCode: ParserSettings['parseCode']
+ getSanitizedNodeValue: ParserSettings['getSanitizedNodeValue']
+ getProgramNodeFromRootNode: ParserSettings['getProgramNodeFromRootNode']
+ getNodeType: ParserSettings['getNodeType']
+}
+
export const compareCode = (
codeA: string,
codeB: string,
- parserSettings: {
- isNode: ParserSettings['isNode']
- shouldCompareNode: ParserSettings['shouldCompareNode']
- astPropsToSkip: ParserSettings['astPropsToSkip']
- parseCode: ParserSettings['parseCode']
- sanitizeNode: ParserSettings['sanitizeNode']
- getProgramNodeFromRootNode: ParserSettings['getProgramNodeFromRootNode']
- },
+ parserSettingsSubset: CompareCodeParserSettingsSubset,
) => {
- const astA = parserSettings.getProgramNodeFromRootNode(
- parserSettings.parseCode(codeA),
+ const astA = parserSettingsSubset.getProgramNodeFromRootNode(
+ parserSettingsSubset.parseCode(codeA),
)
- const astB = parserSettings.getProgramNodeFromRootNode(
- parserSettings.parseCode(codeB),
+ const astB = parserSettingsSubset.getProgramNodeFromRootNode(
+ parserSettingsSubset.parseCode(codeB),
)
- const cleanedA = cleanupAst(astA, parserSettings)
- const cleanedB = cleanupAst(astB, parserSettings)
+ return compareAst(astA, astB, parserSettingsSubset)
+}
+
+const cloneAst = (ast: PoorNodeType) => {
+ const uniqueObjectLikeValuesCache: unknown[] = []
+
+ /**
+ * Skip circular references (like '__parent')
+ */
+ const stringified = JSON.stringify(ast, (_: string, value: unknown) => {
+ if (typeof value === 'object' && value !== null) {
+ // Duplicate reference found, discard key
+ if (uniqueObjectLikeValuesCache.includes(value)) return
+
+ // Store value in our collection
+ uniqueObjectLikeValuesCache.push(value)
+ }
+
+ return value
+ })
+
+ return JSON.parse(stringified)
+}
+
+export const compareAst = (
+ astA: PoorNodeType,
+ astB: PoorNodeType,
+ parserSettingsSubset: CompareCodeParserSettingsSubset,
+) => {
+ const cleanedA = cleanupAst(cloneAst(astA), parserSettingsSubset)
+ const cleanedB = cleanupAst(cloneAst(astB), parserSettingsSubset)
return JSON.stringify(cleanedA) === JSON.stringify(cleanedB)
}
@@ -165,16 +210,25 @@ export const sortByLeastIdentifierStrength = (
nodeA: PoorNodeType,
nodeB: PoorNodeType,
wildcardUtils: WildcardUtils,
+ getIdentifierNodeName: (node: PoorNodeType) => string,
) => {
- const aWildcard = wildcardUtils.getWildcardFromNode(nodeA)
- const bWildcard = wildcardUtils.getWildcardFromNode(nodeB)
+ const aWildcards = wildcardUtils.getIdentifierWildcardsFromNode(nodeA)
+ const bWildcards = wildcardUtils.getIdentifierWildcardsFromNode(nodeB)
- const aIsIdentifierWithWildcard = aWildcard !== null
- const bIsIdentifierWithWildcard = bWildcard !== null
+ const aIsIdentifierWithWildcards = aWildcards.length > 0
+ const bIsIdentifierWithWildcards = bWildcards.length > 0
- if (aIsIdentifierWithWildcard && bIsIdentifierWithWildcard) {
- const idA = aWildcard.wildcardWithoutRef
- const idB = bWildcard.wildcardWithoutRef
+ if (aIsIdentifierWithWildcards && bIsIdentifierWithWildcards) {
+ const idA = wildcardUtils.removeWildcardAliasesFromIdentifierName(
+ getIdentifierNodeName(nodeA),
+ )
+ const idB = wildcardUtils.removeWildcardAliasesFromIdentifierName(
+ getIdentifierNodeName(nodeB),
+ )
+
+ if (idA === idB) {
+ return 0
+ }
if (idA === wildcardUtils.nodesTreeWildcard) {
return 1
@@ -196,11 +250,11 @@ export const sortByLeastIdentifierStrength = (
return bNonWildcardCharsLen - aNonWildcardCharsLen
}
- if (aIsIdentifierWithWildcard) {
+ if (aIsIdentifierWithWildcards) {
return 1
}
- if (bIsIdentifierWithWildcard) {
+ if (bIsIdentifierWithWildcards) {
return -1
}
@@ -210,10 +264,12 @@ export const sortByLeastIdentifierStrength = (
export const getMatchFromNode = (
node: PoorNodeType,
parserSettings: Pick,
+ aliases: MatchContextAliases,
) =>
({
...parserSettings.getNodePosition(node),
node,
+ aliases,
} as Match)
export const getVisitorKeysForQueryNodeType = (
diff --git a/packages/core/src/config.ts b/packages/core/src/config.ts
deleted file mode 100644
index 150e61b..0000000
--- a/packages/core/src/config.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-export const useTraverseApproachTestOnly =
- process.env['TEST_TRAVERSAL'] === 'true'
diff --git a/packages/core/src/getFilesList.ts b/packages/core/src/getFilesList.ts
index 4def437..f64b20a 100644
--- a/packages/core/src/getFilesList.ts
+++ b/packages/core/src/getFilesList.ts
@@ -2,7 +2,7 @@ import path from 'path'
import { promises as fs } from 'fs'
import ignore from 'ignore'
-import { asyncFilter, measureStart } from './utils'
+import { measureStart } from './utils'
import minimatch from 'minimatch'
import { parseDependencyTree } from 'dpdm/lib/index.js'
import { spawnSync } from 'child_process'
@@ -12,6 +12,11 @@ import escapeGlob from 'glob-escape'
import { HardStopFlag } from './types'
export const typeScriptFamilyExtensionTester = /\.(js|jsx|ts|tsx|json|mjs|cjs)$/
+export const htmlFamilyExtensionTester = /\.(html|htm)$/
+export const cssExtensionTester = /\.(css)$/
+export const pythonExtensionTester = /\.(py)$/
+export const luaExtensionTester = /\.(lua)$/
+export const csharpExtensionTester = /\.(cs)$/
/**
* @deprecated use `typeScriptFamilyExtensionTester` instead
@@ -161,7 +166,7 @@ export const filterExtensions = (
return filesList.filter((filePath) => extensionTester.test(filePath))
}
-type GetFilesListArgs = {
+export type GetFilesListArgs = {
searchRoot: string
entryPoint?: string
byGitChanges?: boolean
@@ -174,6 +179,32 @@ type GetFilesListArgs = {
extensionTester?: RegExp
}
+const findRepoRoot = async ({
+ searchRoot,
+ fsRoot,
+}: {
+ searchRoot: string
+ fsRoot: string
+}) => {
+ let currentDir = path.resolve(searchRoot)
+ while (currentDir !== fsRoot) {
+ try {
+ const gitDir = path.join(currentDir, '.git')
+ const stat = await fs.lstat(gitDir)
+
+ if (stat.isDirectory()) {
+ return currentDir
+ }
+ } catch (_e) {
+ // .git not found, continue
+ }
+
+ currentDir = path.dirname(currentDir)
+ }
+
+ return searchRoot
+}
+
export const getFilesList = async ({
searchRoot: _searchRoot,
entryPoint = undefined,
@@ -199,25 +230,21 @@ export const getFilesList = async ({
} else {
const InitialIgnore = ignoreNodeModules ? ['node_modules'] : []
- // Get parent to root gitignore
if (!omitGitIgnore) {
- const searchRootSegments = searchRoot
- .replace(fsRoot, '')
- .split(pathSeparatorChar)
+ const repoRoot = await findRepoRoot({ searchRoot, fsRoot })
+ const parentPaths = []
+ let currentPath = searchRoot
- const pathSegmentsToSystemRoot = []
-
- for (let i = 0; i < searchRootSegments.length; i++) {
- let currentPath = searchRootSegments.slice(0, i).join(pathSeparatorChar)
-
- currentPath = fsRoot + currentPath
-
- pathSegmentsToSystemRoot.push(currentPath)
+ while (currentPath !== repoRoot) {
+ parentPaths.push(currentPath)
+ currentPath = path.dirname(currentPath)
}
+ parentPaths.push(repoRoot)
+
const parentDirsIgnore = (
await Promise.all(
- pathSegmentsToSystemRoot.map((parentPath) =>
+ parentPaths.map((parentPath) =>
getGitIgnoreContentForDirectory(parentPath),
),
)
@@ -258,15 +285,38 @@ export const getFilesList = async ({
// add initial '/' or 'C:\' back
.map((p) => `${fsRoot}${p}`)
- let directories = await asyncFilter(
- filteredAbsolutePaths,
- async (pathName) => {
- const stat = await fs.lstat(pathName)
-
- return stat.isDirectory()
- },
+ const absolutePathsWithStats = await Promise.all(
+ filteredAbsolutePaths.map(async (absolutePath) => {
+ try {
+ let resolvedPath = absolutePath
+ let stat = await fs.lstat(absolutePath)
+
+ if (stat.isSymbolicLink()) {
+ resolvedPath = await fs.realpath(absolutePath)
+ stat = await fs.stat(resolvedPath)
+ }
+
+ return {
+ absolutePath,
+ size: stat.size,
+ isFile: stat.isFile(),
+ isDirectory: stat.isDirectory(),
+ }
+ } catch (e) {
+ return {
+ absolutePath,
+ size: -1,
+ isFile: false,
+ isDirectory: false,
+ }
+ }
+ }),
)
+ let directories = absolutePathsWithStats
+ .filter(({ isDirectory }) => isDirectory)
+ .map(({ absolutePath }) => absolutePath)
+
directories = directories.filter((pathName) => {
const isOnBlackList = directoriesBlackList.some((directoryName) =>
pathName.endsWith(directoryName),
@@ -275,16 +325,12 @@ export const getFilesList = async ({
return !isOnBlackList
})
- const files = await asyncFilter(
- filteredAbsolutePaths,
- async (pathName) => {
- const stat = await fs.lstat(pathName)
-
- return (
- stat.isFile() && (stat.size < bigFileSizeInBytes || searchBigFiles)
- )
- },
- )
+ const files = absolutePathsWithStats
+ .filter(
+ ({ isFile, size }) =>
+ (isFile && size < bigFileSizeInBytes) || searchBigFiles,
+ )
+ .map(({ absolutePath }) => absolutePath)
const directoriesScanResult = (
await Promise.all(directories.map((dir) => scan(dir, localIgnore)))
diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts
index f0fa5fd..8610240 100644
--- a/packages/core/src/index.ts
+++ b/packages/core/src/index.ts
@@ -1,7 +1,6 @@
export { default as searchInStrings } from './searchInStrings'
export { searchMultiThread } from './searchMultiThread'
export { searchInFileSystem } from './searchInFs'
-
export { getMode, groupMatchesByFile } from './utils'
export { parseQueries } from './parseQuery'
export {
@@ -9,6 +8,11 @@ export {
filterIncludeExclude,
extensionTester,
typeScriptFamilyExtensionTester,
+ htmlFamilyExtensionTester,
+ cssExtensionTester,
+ pythonExtensionTester,
+ luaExtensionTester,
+ csharpExtensionTester,
pathToPosix,
filterExtensions,
} from './getFilesList'
@@ -22,6 +26,7 @@ import { getMatchFromNode, getVisitorKeysForQueryNodeType } from './astUtils'
import { validateMatch } from './searchStages/validateMatch'
import { getLocationOfMultilineMatch } from './searchStages/getLocationOfMultilineMatch'
import { traverseAndMatch } from './searchStages/traverseAndMatch'
+import { createMatchContext } from './matchContext'
export const __internal = {
parserSettingsMap,
@@ -31,4 +36,5 @@ export const __internal = {
getVisitorKeysForQueryNodeType,
getLocationOfMultilineMatch,
traverseAndMatch,
+ createMatchContext,
}
diff --git a/packages/core/src/index.web.ts b/packages/core/src/index.web.ts
index 2a5598e..6462f43 100644
--- a/packages/core/src/index.web.ts
+++ b/packages/core/src/index.web.ts
@@ -1,2 +1,7 @@
export * from './types'
export { default as searchInStrings } from './searchInStrings'
+import { parserSettingsMap } from './parserSettings/index'
+
+export const __internal = {
+ parserSettingsMap,
+}
diff --git a/packages/core/src/matchContext.ts b/packages/core/src/matchContext.ts
new file mode 100644
index 0000000..9ec7965
--- /dev/null
+++ b/packages/core/src/matchContext.ts
@@ -0,0 +1,122 @@
+import { Mode, ParserSettings, PoorNodeType } from './types'
+
+export type IdentifierWildcardAlias = {
+ alias: string
+ aliasValue: string
+ wildcard: string
+}
+
+export type StringWildcardAlias = {
+ alias: string
+ aliasValue: string
+ wildcard: string
+}
+
+export type NodesTreeWildcardAlias = {
+ alias: string
+ aliasNode: PoorNodeType
+ aliasValue: string
+ wildcard: string
+}
+
+type IdentifierWildcardAliasesMap = Record<
+ IdentifierWildcardAlias['alias'],
+ IdentifierWildcardAlias
+>
+
+type StringWildcardAliasesMap = Record<
+ StringWildcardAlias['alias'],
+ StringWildcardAlias
+>
+
+type NodesTreeWildcardAliasesMap = Record<
+ NodesTreeWildcardAlias['alias'],
+ NodesTreeWildcardAlias
+>
+
+export type MatchContextAliases = {
+ identifierAliasesMap: IdentifierWildcardAliasesMap
+ stringAliasesMap: StringWildcardAliasesMap
+ nodesTreeAliasesMap: NodesTreeWildcardAliasesMap
+}
+
+export type MatchContext = {
+ addIdentifierAlias: (ref: IdentifierWildcardAlias) => void
+ getIdentifierAlias: (alias: string) => IdentifierWildcardAlias | null
+ addStringAlias: (ref: StringWildcardAlias) => void
+ getStringAlias: (alias: string) => StringWildcardAlias | null
+ addNodesTreeAlias: (ref: NodesTreeWildcardAlias) => void
+ getNodesTreeAlias: (alias: string) => NodesTreeWildcardAlias | null
+ getAllAliases: () => MatchContextAliases
+ merge: (contextMatchAliases: MatchContextAliases) => void
+}
+
+export const createMatchContext = (
+ initialContext?: MatchContextAliases,
+): MatchContext => {
+ let identifierAliasesMap: IdentifierWildcardAliasesMap = initialContext
+ ? { ...(initialContext.identifierAliasesMap ?? {}) }
+ : {}
+ const addIdentifierAlias = (wildcardAlias: IdentifierWildcardAlias) => {
+ identifierAliasesMap[wildcardAlias.alias] = wildcardAlias
+ }
+
+ const getIdentifierAlias = (alias: string) => {
+ return identifierAliasesMap[alias] ?? null
+ }
+
+ let stringAliasesMap: StringWildcardAliasesMap = initialContext
+ ? { ...(initialContext.stringAliasesMap ?? {}) }
+ : {}
+ const addStringAlias = (wildcardAlias: StringWildcardAlias) => {
+ stringAliasesMap[wildcardAlias.alias] = wildcardAlias
+ }
+
+ const getStringAlias = (alias: string) => {
+ return stringAliasesMap[alias] ?? null
+ }
+
+ let nodesTreeAliasesMap: NodesTreeWildcardAliasesMap = initialContext
+ ? { ...(initialContext.nodesTreeAliasesMap ?? {}) }
+ : {}
+
+ const addNodesTreeAlias = (wildcardAlias: NodesTreeWildcardAlias) => {
+ nodesTreeAliasesMap[wildcardAlias.alias] = wildcardAlias
+ }
+
+ const getNodesTreeAlias = (alias: string) => {
+ return nodesTreeAliasesMap[alias] ?? null
+ }
+
+ const merge = (aliasesToMerge: MatchContextAliases) => {
+ identifierAliasesMap = {
+ ...identifierAliasesMap,
+ ...aliasesToMerge.identifierAliasesMap,
+ }
+
+ stringAliasesMap = {
+ ...stringAliasesMap,
+ ...aliasesToMerge.stringAliasesMap,
+ }
+
+ nodesTreeAliasesMap = {
+ ...nodesTreeAliasesMap,
+ ...aliasesToMerge.nodesTreeAliasesMap,
+ }
+ }
+
+ return {
+ addIdentifierAlias,
+ getIdentifierAlias,
+ addStringAlias,
+ getStringAlias,
+ addNodesTreeAlias,
+ getNodesTreeAlias,
+ getAllAliases: () => ({
+ identifierAliasesMap,
+ stringAliasesMap,
+ nodesTreeAliasesMap,
+ }),
+ merge,
+ }
+}
diff --git a/packages/core/src/parseQuery.ts b/packages/core/src/parseQuery.ts
index 3247712..77111ad 100644
--- a/packages/core/src/parseQuery.ts
+++ b/packages/core/src/parseQuery.ts
@@ -6,41 +6,47 @@ import {
PoorNodeType,
Position,
} from './types'
-import { measureStart, SPACE_CHAR, normalizeText } from './utils'
+import { measureStart, decomposeString } from './utils'
import { isNodeArray, getKeysToCompare } from './astUtils'
const MIN_TOKEN_LEN = 2
-export const decomposeString = (str: string, anyStringWildcardRegExp: RegExp) =>
- str
- .split(anyStringWildcardRegExp)
- .map((part) => normalizeText(part).split(SPACE_CHAR))
- .flat(1)
-
-export const getUniqueTokens = (
- queryNode: PoorNodeType,
- caseInsensitive: boolean,
- parserSettings: ParserSettings,
- tokens: Set = new Set(),
-) => {
- const { numericLiteralUtils, stringLikeLiteralUtils } = parserSettings
+const defaultGetUniqueTokensFromStringOrIdentifierNode = ({
+ queryNode,
+ caseInsensitive,
+ parserSettings,
+}: {
+ queryNode: PoorNodeType
+ caseInsensitive: boolean
+ parserSettings: Pick<
+ ParserSettings,
+ | 'isIdentifierNode'
+ | 'stringLikeLiteralUtils'
+ | 'getIdentifierNodeName'
+ | 'wildcardUtils'
+ >
+}) => {
+ const { stringLikeLiteralUtils, getIdentifierNodeName } = parserSettings
const { anyStringWildcardRegExp } = parserSettings.wildcardUtils
+ const tokens: string[] = []
if (parserSettings.isIdentifierNode(queryNode)) {
const trimmedWildcards = parserSettings.wildcardUtils
- .removeIdentifierRefFromWildcard(queryNode.name as string)
+ .removeWildcardAliasesFromIdentifierName(getIdentifierNodeName(queryNode))
.split(parserSettings.wildcardUtils.identifierWildcard)
trimmedWildcards.forEach((part) => {
if (part.length >= MIN_TOKEN_LEN) {
- tokens.add(caseInsensitive ? part.toLocaleLowerCase() : part)
+ tokens.push(caseInsensitive ? part.toLocaleLowerCase() : part)
}
})
}
if (stringLikeLiteralUtils.isStringLikeLiteralNode(queryNode)) {
const stringContent =
- stringLikeLiteralUtils.getStringLikeLiteralValue(queryNode)
+ parserSettings.wildcardUtils.removeWildcardAliasesFromStringLiteral(
+ stringLikeLiteralUtils.getStringLikeLiteralValue(queryNode),
+ )
const trimmedWildcards = decomposeString(
stringContent,
@@ -49,22 +55,47 @@ export const getUniqueTokens = (
trimmedWildcards.forEach((part) => {
if (part.length >= MIN_TOKEN_LEN) {
- tokens.add(caseInsensitive ? part.toLocaleLowerCase() : part)
+ tokens.push(caseInsensitive ? part.toLocaleLowerCase() : part)
}
})
}
+ return tokens
+}
+
+export const getUniqueTokens = (
+ queryNode: PoorNodeType,
+ caseInsensitive: boolean,
+ parserSettings: ParserSettings,
+ tokens: Set = new Set(),
+) => {
+ const { numericLiteralUtils, getUniqueTokensFromStringOrIdentifierNode } =
+ parserSettings
+
+ const getUniqueTokensFn =
+ getUniqueTokensFromStringOrIdentifierNode ??
+ defaultGetUniqueTokensFromStringOrIdentifierNode
+
+ const tokensFromStringsOrIdNode = getUniqueTokensFn({
+ queryNode,
+ caseInsensitive,
+ parserSettings,
+ })
+
+ tokensFromStringsOrIdNode.forEach(tokens.add, tokens)
+
if (numericLiteralUtils.isNumericLiteralNode(queryNode)) {
const raw = numericLiteralUtils.getNumericLiteralValue(queryNode)
if (raw !== parserSettings.wildcardUtils.numericWildcard) {
- tokens.add(raw)
+ tokens.add(caseInsensitive ? raw.toLocaleLowerCase() : raw)
}
}
const nodeKeys = getKeysToCompare(
queryNode,
parserSettings.astPropsToSkip,
+ parserSettings.getNodeType,
).filter(
(key) =>
parserSettings.isNode(queryNode[key] as PoorNodeType) ||
@@ -94,10 +125,14 @@ export const getUniqueTokens = (
}
export const extractQueryNode = (
- fileNode: PoorNodeType,
+ topLevelQueryNode: PoorNodeType,
parserSettings: ParserSettings,
) => {
- const queryBody = parserSettings.getProgramBodyFromRootNode(fileNode)
+ const queryBody = parserSettings.getProgramBodyFromRootNode(topLevelQueryNode)
+
+ if (queryBody.length === 0) {
+ throw new Error('Query is empty or code was not parsed correctly')
+ }
if (queryBody.length === 1) {
return {
@@ -106,7 +141,7 @@ export const extractQueryNode = (
}
}
- const position = parserSettings.getNodePosition(fileNode)
+ const position = parserSettings.getNodePosition(topLevelQueryNode)
return {
queryNode: parserSettings.createBlockStatementNode(queryBody, position),
@@ -203,8 +238,13 @@ export const parseQueries = (
}
}
+ const preprocessedQueryCode =
+ parserSettings.preprocessQueryCode?.(queryText) ?? queryText
+
try {
- const parsedAsIs = parserSettings.parseCode(queryText)
+ const parsedAsIs = parserSettings.parseCode(
+ preprocessedQueryCode.trim(),
+ )
const { queryNode, isMultistatement } = extractQueryNode(
parsedAsIs,
@@ -232,9 +272,10 @@ export const parseQueries = (
}
}
+ // TODO move to parse code, specific to JS
try {
const parsedAsExp = parserSettings.parseCode(
- `(${queryText})`,
+ `(${preprocessedQueryCode})`,
) as unknown as PoorNodeType
const { queryNode } = extractQueryNode(parsedAsExp, parserSettings)
@@ -253,7 +294,9 @@ export const parseQueries = (
}
})
.map(({ error, queryNode, isMultistatement }) => ({
- queryNode,
+ queryNode:
+ (queryNode && parserSettings.postprocessQueryNode?.(queryNode)) ??
+ queryNode,
error: !queryNode ? { text: 'Empty query!' } : error,
isMultistatement,
}))
diff --git a/packages/core/src/parserSettings/_common/JSFamilyCommon.ts b/packages/core/src/parserSettings/_common/JSFamilyCommon.ts
index 5a7bedd..261fa2d 100644
--- a/packages/core/src/parserSettings/_common/JSFamilyCommon.ts
+++ b/packages/core/src/parserSettings/_common/JSFamilyCommon.ts
@@ -1,3 +1,4 @@
+import type { ParserOptions, ParserPlugin } from '@babel/parser'
export const numericWildcard = '0x0'
export const wildcardChar = '$'
@@ -10,3 +11,29 @@ export const supportedExtensions = [
'mjs',
'json',
]
+
+export const babelPluginsWithoutJSX = [
+ 'typescript',
+ 'decorators-legacy',
+ 'importAssertions',
+ 'doExpressions',
+] as ParserPlugin[]
+
+export const babelPluginsWithJSX = [
+ ...babelPluginsWithoutJSX,
+ 'jsx',
+] as ParserPlugin[]
+
+export const babelParseOptionsWithJSX = {
+ sourceType: 'module',
+ plugins: babelPluginsWithJSX,
+ allowReturnOutsideFunction: true,
+ allowImportExportEverywhere: true,
+} as ParserOptions
+
+export const babelParseOptionsWithoutJSX = {
+ sourceType: 'module',
+ plugins: babelPluginsWithoutJSX,
+ allowReturnOutsideFunction: true,
+ allowImportExportEverywhere: true,
+} as ParserOptions
diff --git a/packages/core/src/parserSettings/angularEslintTemplateParser/beforeWildcardsComparators.ts b/packages/core/src/parserSettings/angularEslintTemplateParser/beforeWildcardsComparators.ts
new file mode 100644
index 0000000..d436f2d
--- /dev/null
+++ b/packages/core/src/parserSettings/angularEslintTemplateParser/beforeWildcardsComparators.ts
@@ -0,0 +1,24 @@
+import { NodesComparator } from '../../types'
+import { createMatchWildcardsInPropValueNodesComparator } from '../nodeComparatorFactories/Other/matchWildcardsInPropValueNodes'
+import { matchMultilineQueriesNodesComparator } from './matchMultilineQueriesNodesComparator'
+
+const matchWildcardsInTextAttributeNodesComparator =
+ createMatchWildcardsInPropValueNodesComparator({
+ nodeType: 'TextAttribute',
+ keysToTraverse: [],
+ // Order of keys definition does matter for matchContext! In case someone would use the same alias in eg. prop and value
+ keysWithWildcards: ['name', 'value'],
+ })
+
+const matchWildcardsInElement$1NodesComparator =
+ createMatchWildcardsInPropValueNodesComparator({
+ nodeType: 'Element$1',
+ keysToTraverse: ['attributes', 'children'],
+ keysWithWildcards: ['name'],
+ })
+
+export const beforeWildcardsComparators: NodesComparator[] = [
+ matchWildcardsInTextAttributeNodesComparator,
+ matchWildcardsInElement$1NodesComparator,
+ matchMultilineQueriesNodesComparator,
+]
diff --git a/packages/core/src/parserSettings/angularEslintTemplateParser/common.ts b/packages/core/src/parserSettings/angularEslintTemplateParser/common.ts
new file mode 100644
index 0000000..eec4701
--- /dev/null
+++ b/packages/core/src/parserSettings/angularEslintTemplateParser/common.ts
@@ -0,0 +1,26 @@
+import { createWildcardUtils } from '../../wildcardUtilsFactory'
+import { PoorNodeType } from '../../types'
+import { getNodeType } from '../espreeParser/common'
+
+/*
+ * We don't have purely identifier nodes in this parser
+ * We compare everything using string wildcards
+ */
+
+export const identifierNodeTypes: string[] = []
+
+const wildcardChar = '$'
+const numericWildcard = '0x0'
+
+export const getIdentifierNodeName = (node: PoorNodeType) => node.name as string
+export const setIdentifierNodeName = (node: PoorNodeType, name: string) => {
+ node.name = name
+}
+
+export const wildcardUtils = createWildcardUtils(
+ identifierNodeTypes,
+ numericWildcard,
+ wildcardChar,
+ getIdentifierNodeName,
+ getNodeType,
+)
diff --git a/packages/core/src/parserSettings/angularEslintTemplateParser/matchMultilineQueriesNodesComparator.ts b/packages/core/src/parserSettings/angularEslintTemplateParser/matchMultilineQueriesNodesComparator.ts
new file mode 100644
index 0000000..7e349aa
--- /dev/null
+++ b/packages/core/src/parserSettings/angularEslintTemplateParser/matchMultilineQueriesNodesComparator.ts
@@ -0,0 +1,19 @@
+import { NodesComparator } from '../../types'
+
+/*
+ * Support performing multiline html queries by changing query Program node into ElementNode
+ */
+export const matchMultilineQueriesNodesComparator: NodesComparator = (
+ { queryNode, fileNode },
+ _,
+ { fileKeysToTraverseForOtherMatches },
+) => {
+ if (queryNode?.type === 'Program' && fileNode?.type === 'Element$1') {
+ return {
+ levelMatch: true, // we are not interested in other fields than children of both
+ queryKeysToTraverseForValidatingMatch: ['templateNodes'],
+ fileKeysToTraverseForValidatingMatch: ['children'],
+ fileKeysToTraverseForOtherMatches,
+ }
+ }
+}
diff --git a/packages/core/src/parserSettings/angularEslintTemplateParser/settings.ts b/packages/core/src/parserSettings/angularEslintTemplateParser/settings.ts
new file mode 100644
index 0000000..539696d
--- /dev/null
+++ b/packages/core/src/parserSettings/angularEslintTemplateParser/settings.ts
@@ -0,0 +1,273 @@
+import { parseForESLint } from '@angular-eslint/template-parser'
+import {
+ Location,
+ MatchPosition,
+ NumericLiteralUtils,
+ ParserSettings,
+ PoorNodeType,
+ ProgramNodeAndBlockNodeUtils,
+ StringLikeLiteralUtils,
+ NodesComparatorParameters,
+ GetUniqueTokensFromStringOrIdentifierNode,
+} from '../../types'
+import {
+ decomposeString,
+ normalizeText,
+ runNodesComparators,
+} from '../../utils'
+import {
+ getIdentifierNodeName,
+ identifierNodeTypes,
+ setIdentifierNodeName,
+ wildcardUtils,
+} from './common'
+import { traverseAst } from '../../searchStages/traverseAndMatch'
+import { beforeWildcardsComparators } from './beforeWildcardsComparators'
+
+const supportedExtensions = ['html', 'htm']
+
+const getProgramNodeFromRootNode = (rootNode: PoorNodeType) => rootNode // root node is program node
+
+const getProgramBodyFromRootNode = (fileNode: PoorNodeType) => {
+ return fileNode.templateNodes as PoorNodeType[]
+}
+
+const unwrapExpressionStatement = (node: PoorNodeType) => {
+ return node as PoorNodeType
+}
+
+const createBlockStatementNode = (
+ templateNodes: PoorNodeType[],
+ position: MatchPosition,
+) => ({
+ type: 'Program',
+ templateNodes,
+ ...position,
+})
+
+const isNode = (maybeNode: PoorNodeType) => {
+ return typeof maybeNode?.type === 'string'
+}
+
+const astPropsToSkip = [
+ 'range',
+ 'sourceSpan',
+ 'startSourceSpan',
+ 'endSourceSpan',
+ 'valueSpan',
+ 'keySpan',
+ 'loc',
+ 'start',
+ 'end',
+ 'extra',
+ 'trailingComments',
+ 'leadingComments',
+ 'innerComments',
+ 'comments',
+ 'tail', // Support for partial matching of template literals
+]
+
+const parseCode = (code: string, filePath = '') => {
+ return parseForESLint(code, { filePath, range: true, loc: true })
+ .ast as PoorNodeType
+}
+
+type NodeValueSanitizers = Record any>>
+
+const nodeValuesSanitizers: NodeValueSanitizers = {
+ ['Text$3']: {
+ value: normalizeText,
+ },
+}
+
+const getSanitizedNodeValue = (
+ nodeType: string,
+ valueKey: string,
+ value: unknown,
+) => {
+ const valueSanitizer = nodeValuesSanitizers?.[nodeType]?.[valueKey]
+
+ if (valueSanitizer) {
+ return valueSanitizer(value)
+ }
+
+ return value
+}
+
+const shouldCompareNode = (node: PoorNodeType) => {
+ if (node.type === 'Text$3') {
+ const value: string = getSanitizedNodeValue('Text$3', 'value', node.value)
+
+ const shouldCompare = value.length > 0
+
+ return shouldCompare
+ }
+
+ return true
+}
+
+const getNodeType = (node: PoorNodeType) => node.type as string
+
+const isIdentifierNode = (node: PoorNodeType) =>
+ identifierNodeTypes.includes(getNodeType(node))
+
+const stringLikeLiteralUtils: StringLikeLiteralUtils = {
+ // Text$3 is only pure string node
+ isStringLikeLiteralNode: (node: PoorNodeType) => node.type === 'Text$3',
+ getStringLikeLiteralValue: (node: PoorNodeType) => {
+ return node?.value as string
+ },
+}
+
+const numericLiteralUtils: NumericLiteralUtils = {
+ isNumericLiteralNode: (node: PoorNodeType) => node.type === 'NumericLiteral',
+ getNumericLiteralValue: (node: PoorNodeType) =>
+ (node.extra as any).raw as string,
+}
+
+const programNodeAndBlockNodeUtils: ProgramNodeAndBlockNodeUtils = {
+ isProgramNode: (node: PoorNodeType) => node.type === 'Program',
+ isBlockNode: (node: PoorNodeType) => node.type === 'Program',
+ programNodeBodyKey: 'templateNodes',
+ blockNodeBodyKey: 'templateNodes',
+}
+
+const getNodePosition: ParserSettings['getNodePosition'] = (
+ node: PoorNodeType,
+) => ({
+ start: ((node?.sourceSpan as any)?.start?.offset as number) ?? 0,
+ end: ((node?.sourceSpan as any)?.end?.offset as number) ?? 0,
+ loc: node.loc as unknown as Location,
+})
+
+const getParseErrorLocation = (e: any) => ({
+ line: e.loc?.line ?? 0,
+ column: e.loc?.column ?? 0,
+})
+
+const alternativeNodeTypes = {
+ Identifier: identifierNodeTypes,
+}
+
+/**
+ * To support wildcards in html we have to
+ * - encode wildcard, do it in query text before parsing $$ => a_a_$$
+ * - decode wildcard, traverse parsed query and: a_a_$$ => $$
+ * `$$` is invalid tag name start in all html parsers
+ */
+const encodedWildcardSequence = 'a_$$_x'
+
+const preprocessQueryCode = (code: string) => {
+ const queryCode = code.replace(/(\$\$)/g, () => encodedWildcardSequence)
+
+ return queryCode
+}
+
+const replaceEncodedWildcards = (value: string) =>
+ value.replace(/a_\$\$_x/g, () => '$$')
+
+const postprocessQueryNode = (queryNode: PoorNodeType) => {
+ traverseAst(queryNode, isNode, getNodeType, {
+ Element$1: (node) => {
+ const nodeName = node.name as string
+
+ if (nodeName.includes(encodedWildcardSequence)) {
+ node.name = replaceEncodedWildcards(nodeName)
+ }
+ },
+ TextAttribute: (node) => {
+ const nodeValue = node.value as string
+
+ if (nodeValue.includes(encodedWildcardSequence)) {
+ node.value = replaceEncodedWildcards(nodeValue)
+ }
+ },
+ Text$3: (node) => {
+ const nodeValue = node.value as string
+
+ if (nodeValue.includes(encodedWildcardSequence)) {
+ node.value = replaceEncodedWildcards(nodeValue)
+ }
+ },
+ })
+
+ return queryNode
+}
+
+const compareNodesBeforeWildcardsComparison = (
+ ...nodeComparatorParams: NodesComparatorParameters
+) => {
+ return runNodesComparators(beforeWildcardsComparators, nodeComparatorParams)
+}
+
+const getUniqueTokensFromStringOrIdentifierNode: GetUniqueTokensFromStringOrIdentifierNode =
+ ({ queryNode, caseInsensitive, parserSettings }) => {
+ const MIN_TOKEN_LEN = 2
+
+ const { anyStringWildcardRegExp } = parserSettings.wildcardUtils
+ const tokens: string[] = []
+
+ const valuesToProcess: string[] = []
+
+ if (queryNode.type === 'TextAttribute') {
+ valuesToProcess.push(queryNode.name as string)
+ valuesToProcess.push(queryNode.value as string)
+ }
+
+ if (queryNode.type === 'Element$1') {
+ valuesToProcess.push(queryNode.name as string)
+ }
+
+ if (queryNode.type === 'Text$3') {
+ valuesToProcess.push(queryNode.value as string)
+ }
+
+ valuesToProcess
+ .map((val) =>
+ parserSettings.wildcardUtils.removeWildcardAliasesFromStringLiteral(
+ val,
+ ),
+ )
+ .map((val) => decomposeString(val, anyStringWildcardRegExp))
+ .flat(1)
+ .forEach((part) => {
+ if (part.length >= MIN_TOKEN_LEN) {
+ tokens.push(caseInsensitive ? part.toLocaleLowerCase() : part)
+ }
+ })
+
+ return tokens
+ }
+
+export const angularEslintTemplateParser: ParserSettings = {
+ supportedExtensions,
+ parseCode,
+ isNode,
+ isIdentifierNode,
+ astPropsToSkip,
+ getProgramBodyFromRootNode,
+ getProgramNodeFromRootNode,
+ getIdentifierNodeName,
+ getNodeType,
+ unwrapExpressionStatement,
+ createBlockStatementNode,
+ getSanitizedNodeValue,
+ identifierNodeTypes,
+ setIdentifierNodeName,
+ shouldCompareNode,
+ wildcardUtils,
+ compareNodesBeforeWildcardsComparison,
+ compareNodesAfterWildcardsComparison: () => undefined,
+ identifierTypeAnnotationFieldName: 'typeAnnotation',
+ stringLikeLiteralUtils,
+ numericLiteralUtils,
+ programNodeAndBlockNodeUtils,
+ getNodePosition,
+ getParseErrorLocation,
+ alternativeNodeTypes,
+ postprocessQueryNode,
+ preprocessQueryCode,
+ getUniqueTokensFromStringOrIdentifierNode,
+}
+
+export default angularEslintTemplateParser
diff --git a/packages/core/src/parserSettings/babelEslintParser/afterWildcardsComparators.ts b/packages/core/src/parserSettings/babelEslintParser/afterWildcardsComparators.ts
new file mode 100644
index 0000000..57ef1a0
--- /dev/null
+++ b/packages/core/src/parserSettings/babelEslintParser/afterWildcardsComparators.ts
@@ -0,0 +1,23 @@
+import { NodesComparator } from '../../types'
+import { wildcardForAnyImport } from './nodeComparators/wildcardForAnyImport'
+import { matchJsxElementRegardlessClosingTagNodesComparator } from './nodeComparators/matchJsxElementRegardlessClosingTag'
+import { matchJsxIdentifierUsingIdentifierNodesComparator } from './nodeComparators/matchJsxIdentifierUsingIdentifier'
+import { partialMatchTemplateLiteralNodesComparator } from './nodeComparators/partialMatchTemplateLiteral'
+import { matchOptionalFlagInMemberExpressionNodesComparator } from './nodeComparators/matchOptionalFlagInMemberExpression'
+import { matchDestructPropBeforeRenameNodesComparator } from './nodeComparators/matchDestructPropBeforeRename'
+import { wildcardForAnyTypeAnnotation } from './nodeComparators/wildcardForAnyTypeAnnotation'
+import { wildcardForAnyTypeParameter } from './nodeComparators/wildcardForAnyTypeParameter'
+import { matchObjectPropertiesOfDifferentTypesNodesComparator } from './nodeComparators/matchObjectPropertiesOfDifferentTypes'
+
+// Better keep this order
+export const afterWildcardsComparators: NodesComparator[] = [
+ wildcardForAnyImport,
+ wildcardForAnyTypeAnnotation,
+ wildcardForAnyTypeParameter,
+ matchDestructPropBeforeRenameNodesComparator,
+ matchObjectPropertiesOfDifferentTypesNodesComparator,
+ matchJsxElementRegardlessClosingTagNodesComparator,
+ matchJsxIdentifierUsingIdentifierNodesComparator,
+ partialMatchTemplateLiteralNodesComparator,
+ matchOptionalFlagInMemberExpressionNodesComparator,
+]
diff --git a/packages/core/src/parserSettings/babelEslintParser/beforeWildcardsComparators.ts b/packages/core/src/parserSettings/babelEslintParser/beforeWildcardsComparators.ts
new file mode 100644
index 0000000..7c6c68d
--- /dev/null
+++ b/packages/core/src/parserSettings/babelEslintParser/beforeWildcardsComparators.ts
@@ -0,0 +1,8 @@
+import { NodesComparator } from '../../types'
+import { wildcardForTypeKeywordsNodesComparator } from './nodeComparators/wildcardForTypeKeywords'
+import { wildcardForAssignmentPatternOrDefaultParamValuesNodesComparator } from './nodeComparators/wildcardForAssignmentPatternOrDefaultParamValues'
+
+export const beforeWildcardsComparators: NodesComparator[] = [
+ wildcardForTypeKeywordsNodesComparator,
+ wildcardForAssignmentPatternOrDefaultParamValuesNodesComparator,
+]
diff --git a/packages/core/src/parserSettings/babelEslintParser/common.ts b/packages/core/src/parserSettings/babelEslintParser/common.ts
new file mode 100644
index 0000000..72331f3
--- /dev/null
+++ b/packages/core/src/parserSettings/babelEslintParser/common.ts
@@ -0,0 +1,24 @@
+import { numericWildcard, wildcardChar } from '../_common/JSFamilyCommon'
+import { createWildcardUtils } from '../../wildcardUtilsFactory'
+import { PoorNodeType } from '../../types'
+
+export const identifierNodeTypes = [
+ 'Identifier',
+ 'JSXIdentifier',
+ 'TSTypeParameter',
+]
+
+export const getIdentifierNodeName = (node: PoorNodeType) => node.name as string
+export const setIdentifierNodeName = (node: PoorNodeType, name: string) => {
+ node.name = name
+}
+
+export const getNodeType = (node: PoorNodeType) => node.type as string
+
+export const wildcardUtils = createWildcardUtils(
+ identifierNodeTypes,
+ numericWildcard,
+ wildcardChar,
+ getIdentifierNodeName,
+ getNodeType,
+)
diff --git a/packages/core/src/parserSettings/babelEslintParser/nodeComparators/matchDestructPropBeforeRename.ts b/packages/core/src/parserSettings/babelEslintParser/nodeComparators/matchDestructPropBeforeRename.ts
new file mode 100644
index 0000000..1d522cf
--- /dev/null
+++ b/packages/core/src/parserSettings/babelEslintParser/nodeComparators/matchDestructPropBeforeRename.ts
@@ -0,0 +1,6 @@
+import { createMatchDestructPropBeforeRenameNodesComparator } from '../../nodeComparatorFactories/JavaScriptSpecific/matchDestructPropBeforeRename'
+
+export const matchDestructPropBeforeRenameNodesComparator =
+ createMatchDestructPropBeforeRenameNodesComparator({
+ objectPropertyNodeName: 'Property',
+ })
diff --git a/packages/core/src/parserSettings/babelEslintParser/nodeComparators/matchJsxElementRegardlessClosingTag.ts b/packages/core/src/parserSettings/babelEslintParser/nodeComparators/matchJsxElementRegardlessClosingTag.ts
new file mode 100644
index 0000000..a60143b
--- /dev/null
+++ b/packages/core/src/parserSettings/babelEslintParser/nodeComparators/matchJsxElementRegardlessClosingTag.ts
@@ -0,0 +1,4 @@
+import { createMatchJsxElementRegardlessClosingTagNodesComparator } from '../../nodeComparatorFactories/JsxSpecific/matchJsxElementRegardlessClosingTag'
+
+export const matchJsxElementRegardlessClosingTagNodesComparator =
+ createMatchJsxElementRegardlessClosingTagNodesComparator()
diff --git a/packages/core/src/parserSettings/babelEslintParser/nodeComparators/matchJsxIdentifierUsingIdentifier.ts b/packages/core/src/parserSettings/babelEslintParser/nodeComparators/matchJsxIdentifierUsingIdentifier.ts
new file mode 100644
index 0000000..7a21bf7
--- /dev/null
+++ b/packages/core/src/parserSettings/babelEslintParser/nodeComparators/matchJsxIdentifierUsingIdentifier.ts
@@ -0,0 +1,4 @@
+import { createMatchJsxIdentifierUsingIdentifierNodesComparator } from '../../nodeComparatorFactories/JsxSpecific/matchJsxIdentifierUsingIdentifier'
+
+export const matchJsxIdentifierUsingIdentifierNodesComparator =
+ createMatchJsxIdentifierUsingIdentifierNodesComparator()
diff --git a/packages/core/src/parserSettings/babelEslintParser/nodeComparators/matchObjectPropertiesOfDifferentTypes.ts b/packages/core/src/parserSettings/babelEslintParser/nodeComparators/matchObjectPropertiesOfDifferentTypes.ts
new file mode 100644
index 0000000..99bdf9b
--- /dev/null
+++ b/packages/core/src/parserSettings/babelEslintParser/nodeComparators/matchObjectPropertiesOfDifferentTypes.ts
@@ -0,0 +1,6 @@
+import { createMatchObjectPropertiesOfDifferentTypesNodesComparator } from '../../nodeComparatorFactories/JavaScriptSpecific/matchObjectPropertiesOfDifferentTypes'
+
+export const matchObjectPropertiesOfDifferentTypesNodesComparator =
+ createMatchObjectPropertiesOfDifferentTypesNodesComparator({
+ objectPropertyNodeName: 'Property',
+ })
diff --git a/packages/core/src/parserSettings/babelEslintParser/nodeComparators/matchOptionalFlagInMemberExpression.ts b/packages/core/src/parserSettings/babelEslintParser/nodeComparators/matchOptionalFlagInMemberExpression.ts
new file mode 100644
index 0000000..2287657
--- /dev/null
+++ b/packages/core/src/parserSettings/babelEslintParser/nodeComparators/matchOptionalFlagInMemberExpression.ts
@@ -0,0 +1,4 @@
+import { createMatchOptionalFlagInMemberExpressionNodesComparator } from '../../nodeComparatorFactories/JavaScriptSpecific/matchOptionalFlagInMemberExpression'
+
+export const matchOptionalFlagInMemberExpressionNodesComparator =
+ createMatchOptionalFlagInMemberExpressionNodesComparator()
diff --git a/packages/core/src/parserSettings/babelEslintParser/nodeComparators/partialMatchTemplateLiteral.ts b/packages/core/src/parserSettings/babelEslintParser/nodeComparators/partialMatchTemplateLiteral.ts
new file mode 100644
index 0000000..3579c69
--- /dev/null
+++ b/packages/core/src/parserSettings/babelEslintParser/nodeComparators/partialMatchTemplateLiteral.ts
@@ -0,0 +1,4 @@
+import { createPartialMatchTemplateLiteralNodesComparator } from '../../nodeComparatorFactories/JavaScriptSpecific/partialMatchTemplateLiteral'
+
+export const partialMatchTemplateLiteralNodesComparator =
+ createPartialMatchTemplateLiteralNodesComparator()
diff --git a/packages/core/src/parserSettings/babelEslintParser/nodeComparators/wildcardForAnyImport.ts b/packages/core/src/parserSettings/babelEslintParser/nodeComparators/wildcardForAnyImport.ts
new file mode 100644
index 0000000..103a66d
--- /dev/null
+++ b/packages/core/src/parserSettings/babelEslintParser/nodeComparators/wildcardForAnyImport.ts
@@ -0,0 +1,6 @@
+import { createWildcardForAnyImportNodesComparator } from '../../nodeComparatorFactories/JavaScriptSpecific/wildcardForAnyImport'
+import { wildcardUtils } from '../common'
+
+export const wildcardForAnyImport = createWildcardForAnyImportNodesComparator({
+ wildcardUtils,
+})
diff --git a/packages/core/src/parserSettings/babelEslintParser/nodeComparators/wildcardForAnyTypeAnnotation.ts b/packages/core/src/parserSettings/babelEslintParser/nodeComparators/wildcardForAnyTypeAnnotation.ts
new file mode 100644
index 0000000..832977b
--- /dev/null
+++ b/packages/core/src/parserSettings/babelEslintParser/nodeComparators/wildcardForAnyTypeAnnotation.ts
@@ -0,0 +1,7 @@
+import { createWildcardForAnyTypeAnnotationNodesComparator } from '../../nodeComparatorFactories/TypeScriptSpecific/wildcardForAnyTypeAnnotation'
+import { wildcardUtils } from '../common'
+
+export const wildcardForAnyTypeAnnotation =
+ createWildcardForAnyTypeAnnotationNodesComparator({
+ wildcardUtils,
+ })
diff --git a/packages/core/src/parserSettings/babelEslintParser/nodeComparators/wildcardForAnyTypeParameter.ts b/packages/core/src/parserSettings/babelEslintParser/nodeComparators/wildcardForAnyTypeParameter.ts
new file mode 100644
index 0000000..1ed2a24
--- /dev/null
+++ b/packages/core/src/parserSettings/babelEslintParser/nodeComparators/wildcardForAnyTypeParameter.ts
@@ -0,0 +1,25 @@
+import { PoorNodeType, NodesComparator } from '../../../types'
+import { wildcardUtils } from '../common'
+export const wildcardForAnyTypeParameter: NodesComparator = (
+ { queryNode },
+ _,
+ { fileKeysToTraverseForOtherMatches, measureCompare },
+) => {
+ if (queryNode) {
+ if (
+ (queryNode.type as string) === 'TSTypeParameter' &&
+ wildcardUtils.removeWildcardAliasesFromIdentifierName(
+ (queryNode.name as PoorNodeType).name as string,
+ ) === wildcardUtils.nodesTreeWildcard
+ ) {
+ measureCompare()
+
+ return {
+ levelMatch: true,
+ queryKeysToTraverseForValidatingMatch: [],
+ fileKeysToTraverseForValidatingMatch: [],
+ fileKeysToTraverseForOtherMatches,
+ }
+ }
+ }
+}
diff --git a/packages/core/src/parserSettings/babelEslintParser/nodeComparators/wildcardForAssignmentPatternOrDefaultParamValues.ts b/packages/core/src/parserSettings/babelEslintParser/nodeComparators/wildcardForAssignmentPatternOrDefaultParamValues.ts
new file mode 100644
index 0000000..6f1c78c
--- /dev/null
+++ b/packages/core/src/parserSettings/babelEslintParser/nodeComparators/wildcardForAssignmentPatternOrDefaultParamValues.ts
@@ -0,0 +1,4 @@
+import { createWildcardForAssignmentPatternOrDefaultParamValuesNodesComparator } from '../../nodeComparatorFactories/JavaScriptSpecific/wildcardForAssignmentPatternOrDefaultParamValues'
+
+export const wildcardForAssignmentPatternOrDefaultParamValuesNodesComparator =
+ createWildcardForAssignmentPatternOrDefaultParamValuesNodesComparator()
diff --git a/packages/core/src/parserSettings/babelEslintParser/nodeComparators/wildcardForTypeKeywords.ts b/packages/core/src/parserSettings/babelEslintParser/nodeComparators/wildcardForTypeKeywords.ts
new file mode 100644
index 0000000..3b1c143
--- /dev/null
+++ b/packages/core/src/parserSettings/babelEslintParser/nodeComparators/wildcardForTypeKeywords.ts
@@ -0,0 +1,5 @@
+import { createWildcardForTypeKeywordNodesComparator } from '../../nodeComparatorFactories/TypeScriptSpecific/wildcardForTypeKeywords'
+import { wildcardUtils } from '../common'
+
+export const wildcardForTypeKeywordsNodesComparator =
+ createWildcardForTypeKeywordNodesComparator({ wildcardUtils })
diff --git a/packages/core/src/parserSettings/babelEslintParser/settings.ts b/packages/core/src/parserSettings/babelEslintParser/settings.ts
new file mode 100644
index 0000000..b779aff
--- /dev/null
+++ b/packages/core/src/parserSettings/babelEslintParser/settings.ts
@@ -0,0 +1,268 @@
+import {
+ ParserSettings,
+ PoorNodeType,
+ Location,
+ NodesComparatorParameters,
+ NumericLiteralUtils,
+ ProgramNodeAndBlockNodeUtils,
+ StringLikeLiteralUtils,
+ MatchPosition,
+} from '../../types'
+import { parse } from '@babel/eslint-parser'
+
+import { supportedExtensions } from '../_common/JSFamilyCommon'
+
+import {
+ getNodeType,
+ identifierNodeTypes,
+ wildcardUtils,
+ setIdentifierNodeName,
+ getIdentifierNodeName,
+} from './common'
+
+import { normalizeText, runNodesComparators } from '../../utils'
+import { afterWildcardsComparators } from './afterWildcardsComparators'
+import { beforeWildcardsComparators } from './beforeWildcardsComparators'
+
+const parseCode = (code: string, filePath = '') => {
+ const maybeWrappedJSON = /\.json$/.test(filePath) ? `(${code})` : code
+ try {
+ return parse(maybeWrappedJSON, {
+ filePath,
+ sourceType: 'module',
+ requireConfigFile: false,
+ allowImportExportEverywhere: false,
+ babelOptions: {
+ babelrc: false,
+ /**
+ * ❗ Note that enabling config file makes babel look for package.json, which will crash in browser runtime
+ * At some point we might need to enable resolving plugins from users config files, it might be blocking some syntaxes.
+ * But since @babel/eslint-parser is bit retarded it terms of configuration, it might be an edge case which we will never run into.
+ */
+ configFile: false,
+ parserOpts: {
+ plugins: ['jsx'],
+ },
+ },
+ }) as unknown as PoorNodeType
+ } catch (e) {
+ return parse(maybeWrappedJSON, {
+ filePath,
+ sourceType: 'module',
+ requireConfigFile: false,
+ allowImportExportEverywhere: false,
+ babelOptions: {
+ babelrc: false,
+ configFile: false,
+ parserOpts: {
+ plugins: [],
+ },
+ },
+ }) as unknown as PoorNodeType
+ }
+}
+
+/**
+ * We mimic @babel/eslint-parser, but we don't use it directly, as it has not documented API
+ * We need this only for purpose of eslint plugin and to make sure that output AST is searchable
+ */
+const getProgramNodeFromRootNode = (fileOrProgramNode: PoorNodeType) =>
+ 'program' in fileOrProgramNode
+ ? (fileOrProgramNode.program as PoorNodeType)
+ : fileOrProgramNode
+
+const getProgramBodyFromRootNode = (fileOrProgramNode: PoorNodeType) => {
+ return getProgramNodeFromRootNode(fileOrProgramNode).body as PoorNodeType[]
+}
+
+const isIdentifierNode = (node: PoorNodeType) =>
+ identifierNodeTypes.includes(getNodeType(node))
+
+const alternativeNodeTypes = {
+ Identifier: identifierNodeTypes,
+ ChainExpression: ['MemberExpression'],
+ MemberExpression: ['ChainExpression'],
+ BlockStatement: ['Program'],
+}
+
+const unwrapExpressionStatement = (node: PoorNodeType) => {
+ if (typeof node !== 'object') {
+ return node
+ }
+
+ if (node.type === 'ExpressionStatement') {
+ return node.expression as PoorNodeType
+ }
+
+ return node as PoorNodeType
+}
+
+const createBlockStatementNode = (
+ body: PoorNodeType[],
+ position: MatchPosition,
+) =>
+ ({
+ type: 'BlockStatement',
+ body,
+ loc: position.loc,
+ range: [position.start, position.end],
+ } as unknown as PoorNodeType)
+
+const isNode = (maybeNode: PoorNodeType) => {
+ return typeof maybeNode?.type === 'string'
+}
+
+const astPropsToSkip = [
+ 'loc',
+ 'range',
+ 'raw',
+ 'trailingComments',
+ 'leadingComments',
+ 'comments',
+ 'tail', // Support for partial matching of template literals
+ 'parent', // in eslint there is parent prop in node
+ { type: 'ArrowFunctionExpression', key: 'expression' }, // flag on ArrowFunctionExpression
+ 'tokens',
+ 'start',
+ 'end',
+ 'extra',
+]
+
+const sanitizeTemplateElementValue = ({
+ raw,
+ cooked,
+}: {
+ raw: string
+ cooked: string
+}) => {
+ return {
+ raw: normalizeText(raw),
+ cooked: normalizeText(cooked),
+ }
+}
+
+type NodeValueSanitizers = Record any>>
+
+const nodeValuesSanitizers: NodeValueSanitizers = {
+ ['JSXText']: {
+ value: normalizeText,
+ raw: normalizeText,
+ },
+ ['TemplateElement']: {
+ value: sanitizeTemplateElementValue,
+ },
+}
+
+const getSanitizedNodeValue = (
+ nodeType: string,
+ valueKey: string,
+ value: unknown,
+) => {
+ const valueSanitizer = nodeValuesSanitizers?.[nodeType]?.[valueKey]
+
+ if (valueSanitizer) {
+ return valueSanitizer(value)
+ }
+
+ return value
+}
+
+const shouldCompareNode = (node: PoorNodeType) => {
+ if (node.type === 'JSXText') {
+ const value: string = getSanitizedNodeValue('JSXText', 'value', node.value)
+
+ return value.length > 0
+ }
+
+ return true
+}
+
+const compareNodesBeforeWildcardsComparison = (
+ ...nodeComparatorParams: NodesComparatorParameters
+) => {
+ return runNodesComparators(beforeWildcardsComparators, nodeComparatorParams)
+}
+
+const compareNodesAfterWildcardsComparison = (
+ ...nodeComparatorParams: NodesComparatorParameters
+) => {
+ return runNodesComparators(afterWildcardsComparators, nodeComparatorParams)
+}
+
+const isFirstCharStringStart = (str: string) =>
+ str.charAt(0) === `'` || str.charAt(0) === `"`
+
+const stringLikeLiteralUtils: StringLikeLiteralUtils = {
+ isStringLikeLiteralNode: (node: PoorNodeType) =>
+ (node.type === 'Literal' && isFirstCharStringStart(node.raw as string)) ||
+ node.type === 'TemplateElement' ||
+ node.type === 'JSXText',
+ getStringLikeLiteralValue: (node: PoorNodeType) => {
+ if (node.type === 'TemplateElement') {
+ const { raw } = sanitizeTemplateElementValue(
+ node.value as { raw: string; cooked: string },
+ )
+
+ return raw
+ }
+
+ // (node.type === 'Literal' || node.type === 'JSXText'
+ return normalizeText(node.value as string)
+ },
+}
+
+const numericLiteralUtils: NumericLiteralUtils = {
+ isNumericLiteralNode: (node: PoorNodeType) =>
+ node.type === 'Literal' && !isFirstCharStringStart(node.raw as string),
+ getNumericLiteralValue: (node: PoorNodeType) => node.raw as string,
+}
+
+const programNodeAndBlockNodeUtils: ProgramNodeAndBlockNodeUtils = {
+ isProgramNode: (node: PoorNodeType) => node.type === 'Program',
+ isBlockNode: (node: PoorNodeType) => node.type === 'BlockStatement',
+ programNodeBodyKey: 'body',
+ blockNodeBodyKey: 'body',
+}
+
+const getNodePosition: ParserSettings['getNodePosition'] = (
+ node: PoorNodeType,
+) => ({
+ start: (node.range as any)[0] as number,
+ end: (node.range as any)[1] as number,
+ loc: node.loc as unknown as Location,
+})
+
+const getParseErrorLocation = (e: any) => ({
+ line: e.lineNumber ?? 0,
+ column: e.column ?? 0,
+})
+
+export const babelEslintParserSettings: ParserSettings = {
+ parseCode,
+ getProgramNodeFromRootNode,
+ getProgramBodyFromRootNode,
+ isIdentifierNode,
+ getNodeType,
+ wildcardUtils,
+ setIdentifierNodeName,
+ alternativeNodeTypes,
+ astPropsToSkip,
+ supportedExtensions,
+ isNode,
+ identifierNodeTypes,
+ getIdentifierNodeName,
+ unwrapExpressionStatement,
+ createBlockStatementNode,
+ getSanitizedNodeValue,
+ shouldCompareNode,
+ compareNodesBeforeWildcardsComparison,
+ compareNodesAfterWildcardsComparison,
+ identifierTypeAnnotationFieldName: 'typeAnnotation',
+ stringLikeLiteralUtils,
+ numericLiteralUtils,
+ programNodeAndBlockNodeUtils,
+ getNodePosition,
+ getParseErrorLocation,
+}
+
+export default babelEslintParserSettings
diff --git a/packages/core/src/parserSettings/babelParser/common.ts b/packages/core/src/parserSettings/babelParser/common.ts
index b2a7418..72331f3 100644
--- a/packages/core/src/parserSettings/babelParser/common.ts
+++ b/packages/core/src/parserSettings/babelParser/common.ts
@@ -1,5 +1,6 @@
import { numericWildcard, wildcardChar } from '../_common/JSFamilyCommon'
import { createWildcardUtils } from '../../wildcardUtilsFactory'
+import { PoorNodeType } from '../../types'
export const identifierNodeTypes = [
'Identifier',
@@ -7,8 +8,17 @@ export const identifierNodeTypes = [
'TSTypeParameter',
]
+export const getIdentifierNodeName = (node: PoorNodeType) => node.name as string
+export const setIdentifierNodeName = (node: PoorNodeType, name: string) => {
+ node.name = name
+}
+
+export const getNodeType = (node: PoorNodeType) => node.type as string
+
export const wildcardUtils = createWildcardUtils(
identifierNodeTypes,
numericWildcard,
wildcardChar,
+ getIdentifierNodeName,
+ getNodeType,
)
diff --git a/packages/core/src/parserSettings/babelParser/settings.ts b/packages/core/src/parserSettings/babelParser/settings.ts
index 332ec09..b78b157 100644
--- a/packages/core/src/parserSettings/babelParser/settings.ts
+++ b/packages/core/src/parserSettings/babelParser/settings.ts
@@ -1,5 +1,4 @@
import { parse, ParserOptions, ParserPlugin } from '@babel/parser'
-import { NODE_FIELDS } from '@babel/types'
import {
ParserSettings,
PoorNodeType,
@@ -8,14 +7,24 @@ import {
NumericLiteralUtils,
ProgramNodeAndBlockNodeUtils,
Location,
- Match,
+ MatchPosition,
} from '../../types'
+
import { normalizeText, runNodesComparators } from '../../utils'
import { beforeWildcardsComparators } from './beforeWildcardsComparators'
import { afterWildcardsComparators } from './afterWildcardsComparators'
-import { supportedExtensions } from '../_common/JSFamilyCommon'
-import {} from '../../wildcardUtilsFactory'
-import { identifierNodeTypes, wildcardUtils } from './common'
+import {
+ supportedExtensions,
+ babelParseOptionsWithJSX,
+ babelParseOptionsWithoutJSX,
+} from '../_common/JSFamilyCommon'
+import {
+ getIdentifierNodeName,
+ getNodeType,
+ identifierNodeTypes,
+ wildcardUtils,
+ setIdentifierNodeName,
+} from './common'
const getProgramNodeFromRootNode = (fileNode: PoorNodeType) =>
fileNode.program as PoorNodeType
@@ -38,7 +47,7 @@ const unwrapExpressionStatement = (node: PoorNodeType) => {
const createBlockStatementNode = (
body: PoorNodeType[],
- position: Omit,
+ position: MatchPosition,
) => ({
type: 'BlockStatement',
body,
@@ -50,14 +59,6 @@ const isNode = (maybeNode: PoorNodeType) => {
return typeof maybeNode?.type === 'string'
}
-const isNodeFieldOptional = (nodeType: string, nodeFieldKey: string) => {
- return Boolean(
- (NODE_FIELDS[nodeType] as { [key: string]: { optional: boolean } })[
- nodeFieldKey
- ]?.optional ?? true,
- )
-}
-
const astPropsToSkip = [
'loc',
'start',
@@ -71,70 +72,77 @@ const astPropsToSkip = [
]
const parseCode = (code: string, filePath = '') => {
- const pluginsWithoutJSX = [
- 'typescript',
- 'decorators-legacy',
- 'importAssertions',
- 'doExpressions',
- ] as ParserPlugin[]
- const pluginsWithJSX = [...pluginsWithoutJSX, 'jsx'] as ParserPlugin[]
-
- const parseOptionsWithJSX = {
- sourceType: 'module',
- plugins: pluginsWithJSX,
- allowReturnOutsideFunction: true,
- } as ParserOptions
-
- const parseOptionsWithoutJSX = {
- sourceType: 'module',
- plugins: pluginsWithoutJSX,
- allowReturnOutsideFunction: true,
- } as ParserOptions
-
const maybeWrappedJSON = /\.json$/.test(filePath) ? `(${code})` : code
-
try {
return parse(
maybeWrappedJSON,
- parseOptionsWithJSX,
+ babelParseOptionsWithJSX,
) as unknown as PoorNodeType
} catch (e) {
return parse(
maybeWrappedJSON,
- parseOptionsWithoutJSX,
+ babelParseOptionsWithoutJSX,
) as unknown as PoorNodeType
}
}
-const sanitizeJSXText = (node: PoorNodeType) => {
- //@ts-ignore
- node.value = normalizeText(node.value)
- //@ts-ignore
- node.extra.raw = normalizeText(node.extra.raw)
- //@ts-ignore
- node.extra.rawValue = normalizeText(node.extra.rawValue)
+const sanitizeJSXTextExtraValue = ({
+ raw,
+ rawValue,
+}: {
+ raw: string
+ rawValue: string
+}) => {
+ return {
+ raw: normalizeText(raw),
+ rawValue: normalizeText(rawValue),
+ }
}
-const sanitizeTemplateElement = (node: PoorNodeType) => {
- //@ts-ignore
- node.value.raw = normalizeText(node.value.raw)
- //@ts-ignore
- node.value.cooked = normalizeText(node.value.cooked)
+const sanitizeTemplateElementValue = ({
+ raw,
+ cooked,
+}: {
+ raw: string
+ cooked: string
+}) => {
+ return {
+ raw: normalizeText(raw),
+ cooked: normalizeText(cooked),
+ }
}
-const sanitizeNode = (node: PoorNodeType) => {
- if (node?.type === 'TemplateElement') {
- sanitizeTemplateElement(node)
- } else if (node?.type === 'JSXText') {
- sanitizeJSXText(node)
+type NodeValueSanitizers = Record any>>
+
+const nodeValuesSanitizers: NodeValueSanitizers = {
+ ['JSXText']: {
+ value: normalizeText,
+ extra: sanitizeJSXTextExtraValue,
+ },
+ ['TemplateElement']: {
+ value: sanitizeTemplateElementValue,
+ },
+}
+
+const getSanitizedNodeValue = (
+ nodeType: string,
+ valueKey: string,
+ value: unknown,
+) => {
+ const valueSanitizer = nodeValuesSanitizers?.[nodeType]?.[valueKey]
+
+ if (valueSanitizer) {
+ return valueSanitizer(value)
}
+
+ return value
}
const shouldCompareNode = (node: PoorNodeType) => {
if (node.type === 'JSXText') {
- sanitizeJSXText(node)
+ const value: string = getSanitizedNodeValue('JSXText', 'value', node.value)
- return (node.value as string).length > 0
+ return value.length > 0
}
return true
@@ -152,9 +160,6 @@ const compareNodesAfterWildcardsComparison = (
return runNodesComparators(afterWildcardsComparators, nodeComparatorParams)
}
-const getIdentifierNodeName = (node: PoorNodeType) => node.name as string
-const getNodeType = (node: PoorNodeType) => node.type as string
-
const isIdentifierNode = (node: PoorNodeType) =>
identifierNodeTypes.includes(getNodeType(node))
@@ -164,7 +169,16 @@ const stringLikeLiteralUtils: StringLikeLiteralUtils = {
node.type === 'TemplateElement' ||
node.type === 'JSXText',
getStringLikeLiteralValue: (node: PoorNodeType) => {
- return ((node.value as any)?.raw as string) ?? (node?.value as string)
+ if (node.type === 'TemplateElement') {
+ const { raw } = sanitizeTemplateElementValue(
+ node.value as { raw: string; cooked: string },
+ )
+
+ return raw
+ }
+
+ // (node.type === 'StringLiteral' || node.type === 'JSXText'
+ return normalizeText(node.value as string)
},
}
@@ -183,7 +197,7 @@ const programNodeAndBlockNodeUtils: ProgramNodeAndBlockNodeUtils = {
const getNodePosition: ParserSettings['getNodePosition'] = (
node: PoorNodeType,
-) => ({
+): MatchPosition => ({
start: node.start as number,
end: node.end as number,
loc: node.loc as unknown as Location,
@@ -206,15 +220,16 @@ export const babelParserSettings: ParserSettings = {
parseCode,
isNode,
isIdentifierNode,
+ identifierNodeTypes,
astPropsToSkip,
- isNodeFieldOptional,
getProgramBodyFromRootNode,
getProgramNodeFromRootNode,
getIdentifierNodeName,
+ setIdentifierNodeName,
getNodeType,
unwrapExpressionStatement,
createBlockStatementNode,
- sanitizeNode,
+ getSanitizedNodeValue,
shouldCompareNode,
wildcardUtils,
compareNodesBeforeWildcardsComparison,
diff --git a/packages/core/src/parserSettings/csharp/common.ts b/packages/core/src/parserSettings/csharp/common.ts
new file mode 100644
index 0000000..c045f63
--- /dev/null
+++ b/packages/core/src/parserSettings/csharp/common.ts
@@ -0,0 +1,24 @@
+import { createWildcardUtils } from '../../wildcardUtilsFactory'
+import { PoorNodeType } from '../../types'
+
+export const identifierNodeTypes: string[] = ['identifier']
+
+const wildcardChar = '$'
+const numericWildcard = '0x0'
+
+export const getIdentifierNodeName = (node: PoorNodeType) =>
+ node.rawValue as string
+
+export const setIdentifierNodeName = (node: PoorNodeType, name: string) => {
+ node.rawValue = name
+}
+
+export const getNodeType = (node: PoorNodeType) => node.nodeType as string
+
+export const wildcardUtils = createWildcardUtils(
+ identifierNodeTypes,
+ numericWildcard,
+ wildcardChar,
+ getIdentifierNodeName,
+ getNodeType,
+)
diff --git a/packages/core/src/parserSettings/csharp/parseCode.ts b/packages/core/src/parserSettings/csharp/parseCode.ts
new file mode 100644
index 0000000..e9688cf
--- /dev/null
+++ b/packages/core/src/parserSettings/csharp/parseCode.ts
@@ -0,0 +1,17 @@
+import { treeSitterParserModuleFactory } from '../../treeSitterUtils'
+
+const defineRawValueForNodeTypes = [
+ 'identifier',
+ 'integer_literal',
+ 'string_literal_content',
+ 'real_literal',
+]
+
+export const parserModule = treeSitterParserModuleFactory({
+ treeSitterParserName: 'tree-sitter-c-sharp',
+ defineRawValueForNodeTypes,
+})
+
+export function parseCode(code: string) {
+ return parserModule.parse(code)
+}
diff --git a/packages/core/src/parserSettings/csharp/settings.ts b/packages/core/src/parserSettings/csharp/settings.ts
new file mode 100644
index 0000000..5134784
--- /dev/null
+++ b/packages/core/src/parserSettings/csharp/settings.ts
@@ -0,0 +1,199 @@
+import { traverseAst } from '../../searchStages/traverseAndMatch'
+import {
+ Location,
+ MatchPosition,
+ NumericLiteralUtils,
+ ParserSettings,
+ PoorNodeType,
+ ProgramNodeAndBlockNodeUtils,
+ StringLikeLiteralUtils,
+} from '../../types'
+
+import {
+ getIdentifierNodeName,
+ getNodeType,
+ identifierNodeTypes,
+ setIdentifierNodeName,
+ wildcardUtils,
+} from './common'
+import { parseCode, parserModule } from './parseCode'
+
+const supportedExtensions = ['cs']
+
+const getProgramNodeFromRootNode = (rootNode: PoorNodeType) => rootNode // root node is program node
+
+const getProgramBodyFromRootNode = (fileNode: PoorNodeType) => {
+ return fileNode.children as PoorNodeType[]
+}
+
+const unwrapExpressionStatement = (node: PoorNodeType) => {
+ if (node.nodeType === 'global_statement' && node.children) {
+ const exprChild = (node.children as PoorNodeType[])[0] as PoorNodeType
+
+ if (exprChild.nodeType === 'expression_statement' && exprChild.children) {
+ const parChild = (exprChild.children as PoorNodeType[])[0] as PoorNodeType
+
+ if (
+ parChild.nodeType === 'parenthesized_expression' &&
+ parChild.children
+ ) {
+ return (parChild.children as PoorNodeType[])[0] as PoorNodeType
+ }
+ }
+ }
+
+ return node
+}
+
+const createBlockStatementNode = (
+ children: PoorNodeType[],
+ position: MatchPosition,
+) => ({
+ nodeType: 'block',
+ children,
+ ...position,
+})
+
+const isNode = (maybeNode: PoorNodeType) => {
+ return typeof maybeNode?.nodeType === 'string'
+}
+
+/* start and end is added by CQ in multiline queries */
+const astPropsToSkip = ['loc', 'start', 'end']
+
+type NodeValueSanitizers = Record any>>
+
+const nodeValuesSanitizers: NodeValueSanitizers = {}
+
+const getSanitizedNodeValue = (
+ nodeType: string,
+ valueKey: string,
+ value: unknown,
+) => {
+ const valueSanitizer = nodeValuesSanitizers?.[nodeType]?.[valueKey]
+
+ if (valueSanitizer) {
+ return valueSanitizer(value)
+ }
+
+ return value
+}
+
+const shouldCompareNode = (node: PoorNodeType) => {
+ return true
+}
+
+const isIdentifierNode = (node: PoorNodeType) =>
+ identifierNodeTypes.includes(getNodeType(node))
+
+const stringLikeLiteralUtils: StringLikeLiteralUtils = {
+ isStringLikeLiteralNode: (node: PoorNodeType) =>
+ node.nodeType === 'string_literal_content',
+ getStringLikeLiteralValue: (node: PoorNodeType) => {
+ return node?.rawValue as string
+ },
+}
+
+const numericLiteralUtils: NumericLiteralUtils = {
+ isNumericLiteralNode: (node: PoorNodeType) =>
+ node.nodeType === 'integer_literal' || node.nodeType === 'real_literal',
+ getNumericLiteralValue: (node: PoorNodeType) => node?.rawValue as string,
+}
+
+const programNodeAndBlockNodeUtils: ProgramNodeAndBlockNodeUtils = {
+ isProgramNode: (node: PoorNodeType) => node.nodeType === 'compilation_unit',
+ isBlockNode: (node: PoorNodeType) => node.nodeType === 'block',
+ programNodeBodyKey: 'children',
+ blockNodeBodyKey: 'children',
+}
+
+const getNodePosition: ParserSettings['getNodePosition'] = (
+ node: PoorNodeType,
+) => ({
+ start: ((node?.loc as any)?.start?.index as number) ?? 0,
+ end: ((node?.loc as any)?.end?.index as number) ?? 0,
+ loc: node.loc as unknown as Location,
+})
+
+const getParseErrorLocation = (e: any) => ({
+ line: e.loc?.start?.line ?? 0,
+ column: e.loc?.start?.column ?? 0,
+})
+
+const alternativeNodeTypes = {
+ identifier: identifierNodeTypes,
+}
+
+const encodedIdentifierWildcardSequence = 'a_x_2_x_a'
+const encodedNodeWildcardSequence = 'a_x_3_x_a'
+
+const preprocessQueryCode = (code: string) => {
+ const queryCode = code
+ .replace(/(\$\$\$)/g, () => encodedNodeWildcardSequence)
+ .replace(/(\$\$)/g, () => encodedIdentifierWildcardSequence)
+
+ return queryCode
+}
+
+const replaceEncodedWildcards = (value: string) =>
+ value.replace(/a_x_3_x_a/g, () => '$$$').replace(/a_x_2_x_a/g, () => '$$')
+
+const postprocessQueryNode = (queryNode: PoorNodeType) => {
+ traverseAst(queryNode, isNode, getNodeType, {
+ identifier: (node) => {
+ const nodeName = node.rawValue as string
+
+ if (
+ nodeName.includes(encodedNodeWildcardSequence) ||
+ nodeName.includes(encodedIdentifierWildcardSequence)
+ ) {
+ node.rawValue = replaceEncodedWildcards(nodeName)
+ }
+ },
+ string_literal_content: (node) => {
+ const nodeName = node.rawValue as string
+
+ if (
+ nodeName.includes(encodedNodeWildcardSequence) ||
+ nodeName.includes(encodedIdentifierWildcardSequence)
+ ) {
+ node.rawValue = replaceEncodedWildcards(nodeName)
+ }
+ },
+ })
+
+ return queryNode
+}
+
+export const csharpParser: ParserSettings = {
+ supportedExtensions,
+ parseCode,
+ isNode,
+ isIdentifierNode,
+ astPropsToSkip,
+ getProgramBodyFromRootNode,
+ getProgramNodeFromRootNode,
+ getIdentifierNodeName,
+ getNodeType,
+ unwrapExpressionStatement,
+ createBlockStatementNode,
+ getSanitizedNodeValue,
+ identifierNodeTypes,
+ setIdentifierNodeName,
+ shouldCompareNode,
+ wildcardUtils,
+ compareNodesBeforeWildcardsComparison: () => undefined,
+ compareNodesAfterWildcardsComparison: () => undefined,
+ identifierTypeAnnotationFieldName: '',
+ stringLikeLiteralUtils,
+ numericLiteralUtils,
+ programNodeAndBlockNodeUtils,
+ getNodePosition,
+ getParseErrorLocation,
+ alternativeNodeTypes,
+ preprocessQueryCode,
+ postprocessQueryNode,
+ init: parserModule.init,
+}
+
+export default csharpParser
diff --git a/packages/core/src/parserSettings/cssTree/afterWildcardsComparators.ts b/packages/core/src/parserSettings/cssTree/afterWildcardsComparators.ts
new file mode 100644
index 0000000..20c7a78
--- /dev/null
+++ b/packages/core/src/parserSettings/cssTree/afterWildcardsComparators.ts
@@ -0,0 +1,6 @@
+import { NodesComparator } from '../../types'
+import { matchRuleWithoutSelector } from './matchRuleWithoutSelector'
+
+export const afterWildcardsComparators: NodesComparator[] = [
+ matchRuleWithoutSelector,
+]
diff --git a/packages/core/src/parserSettings/cssTree/beforeWildcardsComparators.ts b/packages/core/src/parserSettings/cssTree/beforeWildcardsComparators.ts
new file mode 100644
index 0000000..73a81ee
--- /dev/null
+++ b/packages/core/src/parserSettings/cssTree/beforeWildcardsComparators.ts
@@ -0,0 +1,35 @@
+import { NodesComparator } from '../../types'
+import { createMatchWildcardsInPropValueNodesComparator } from '../nodeComparatorFactories/Other/matchWildcardsInPropValueNodes'
+import { matchWildcardInDeclarationProperty } from './matchWildcardInDeclarationProperty'
+import { matchWildcardsInDimension } from './matchWildcardsInDimension'
+import { matchHashWithWildcard } from './matchHashWithWildcard'
+
+const nodeTypesWithNameAndChildren = ['Function']
+
+const matchWildcardsInNodeTypesWithNameAndChildrenNodesComparator =
+ nodeTypesWithNameAndChildren.map((nodeType) =>
+ createMatchWildcardsInPropValueNodesComparator({
+ nodeType,
+ keysToTraverse: ['children'],
+ keysWithWildcards: ['name'],
+ }),
+ )
+
+const nodeTypesWithNameAndValue = ['MediaFeature']
+
+const matchWildcardsInNodeTypesWithNameAndValueNodesComparator =
+ nodeTypesWithNameAndValue.map((nodeType) =>
+ createMatchWildcardsInPropValueNodesComparator({
+ nodeType,
+ keysToTraverse: ['value'],
+ keysWithWildcards: ['name'],
+ }),
+ )
+
+export const beforeWildcardsComparators: NodesComparator[] = [
+ ...matchWildcardsInNodeTypesWithNameAndChildrenNodesComparator,
+ ...matchWildcardsInNodeTypesWithNameAndValueNodesComparator,
+ matchWildcardInDeclarationProperty,
+ matchWildcardsInDimension,
+ matchHashWithWildcard,
+]
diff --git a/packages/core/src/parserSettings/cssTree/common.ts b/packages/core/src/parserSettings/cssTree/common.ts
new file mode 100644
index 0000000..b420010
--- /dev/null
+++ b/packages/core/src/parserSettings/cssTree/common.ts
@@ -0,0 +1,26 @@
+import { createWildcardUtils } from '../../wildcardUtilsFactory'
+import { PoorNodeType } from '../../types'
+import { getNodeType } from '../espreeParser/common'
+
+/*
+ * We don't have purely identifier nodes in this parser
+ * We compare everything using string wildcards
+ */
+
+export const identifierNodeTypes: string[] = ['Identifier']
+
+const wildcardChar = '$'
+const numericWildcard = '0x0'
+
+export const getIdentifierNodeName = (node: PoorNodeType) => node.name as string
+export const setIdentifierNodeName = (node: PoorNodeType, name: string) => {
+ node.name = name
+}
+
+export const wildcardUtils = createWildcardUtils(
+ identifierNodeTypes,
+ numericWildcard,
+ wildcardChar,
+ getIdentifierNodeName,
+ getNodeType,
+)
diff --git a/packages/core/src/parserSettings/cssTree/matchHashWithWildcard.ts b/packages/core/src/parserSettings/cssTree/matchHashWithWildcard.ts
new file mode 100644
index 0000000..0a336ff
--- /dev/null
+++ b/packages/core/src/parserSettings/cssTree/matchHashWithWildcard.ts
@@ -0,0 +1,51 @@
+import { NodesComparator, PoorNodeType } from '../../types'
+import { matchStringOrIdentifierAliases } from '../../searchStages/matchStringOrIdentifierAliases'
+
+/*
+ * Adds support for matching color Hash with wildcard
+ * Q: {color: $$ } C: {color: #000 }
+ */
+export const matchHashWithWildcard: NodesComparator = (
+ { queryNode, fileNode, searchSettings, matchContext },
+ _,
+ { fileKeysToTraverseForOtherMatches, log },
+) => {
+ if (queryNode?.type === 'Identifier' && fileNode?.type === 'Hash') {
+ log(
+ 'Compare Identifier with Hash node',
+ queryNode.name as string,
+ fileNode.value as string,
+ )
+
+ const { wildcardUtils } = searchSettings.parserSettings
+ const { caseInsensitive } = searchSettings
+
+ const queryNodeStringContent = queryNode.name as string
+
+ const fileNodeStringContent = fileNode.value as string
+
+ const wildcardsMeta = wildcardUtils.getStringWildcardsFromString(
+ queryNodeStringContent,
+ )
+
+ if (wildcardsMeta.length > 0) {
+ const levelMatch = matchStringOrIdentifierAliases({
+ queryValue: queryNodeStringContent,
+ fileValue: fileNodeStringContent,
+ wildcardsMeta,
+ matchContext,
+ wildcardUtils,
+ caseInsensitive,
+ })
+
+ if (levelMatch) {
+ return {
+ levelMatch,
+ queryKeysToTraverseForValidatingMatch: [],
+ fileKeysToTraverseForValidatingMatch: [],
+ fileKeysToTraverseForOtherMatches,
+ }
+ }
+ }
+ }
+}
diff --git a/packages/core/src/parserSettings/cssTree/matchRuleWithoutSelector.ts b/packages/core/src/parserSettings/cssTree/matchRuleWithoutSelector.ts
new file mode 100644
index 0000000..b6e2575
--- /dev/null
+++ b/packages/core/src/parserSettings/cssTree/matchRuleWithoutSelector.ts
@@ -0,0 +1,25 @@
+import { NodesComparator, PoorNodeType } from '../../types'
+
+/*
+ * Skip comparing `prelude` for rules where prelude is empty 'Raw'
+ * Q: {background-color: red} C: p {background-color: red}
+ */
+export const matchRuleWithoutSelector: NodesComparator = (
+ { queryNode, fileNode },
+ _,
+ { fileKeysToTraverseForOtherMatches },
+) => {
+ if (
+ queryNode?.type === 'Rule' &&
+ fileNode?.type === 'Rule' &&
+ (queryNode?.prelude as PoorNodeType)?.type === 'Raw' &&
+ (queryNode?.prelude as PoorNodeType)?.value === ''
+ ) {
+ return {
+ levelMatch: true,
+ queryKeysToTraverseForValidatingMatch: ['block'],
+ fileKeysToTraverseForValidatingMatch: ['block'],
+ fileKeysToTraverseForOtherMatches,
+ }
+ }
+}
diff --git a/packages/core/src/parserSettings/cssTree/matchWildcardInDeclarationProperty.ts b/packages/core/src/parserSettings/cssTree/matchWildcardInDeclarationProperty.ts
new file mode 100644
index 0000000..1484ff9
--- /dev/null
+++ b/packages/core/src/parserSettings/cssTree/matchWildcardInDeclarationProperty.ts
@@ -0,0 +1,60 @@
+import { NodesComparator, PoorNodeType } from '../../types'
+import { matchStringOrIdentifierAliases } from '../../searchStages/matchStringOrIdentifierAliases'
+
+/*
+ * Adds support for matching wildcard in "Declaration" property key
+ * Q: {background-$$: red} C: p {background-color: red}
+ */
+export const matchWildcardInDeclarationProperty: NodesComparator = (
+ { queryNode, fileNode, searchSettings, matchContext },
+ _,
+ { fileKeysToTraverseForOtherMatches },
+) => {
+ if (queryNode?.type === 'Declaration' && fileNode?.type === 'Declaration') {
+ const { wildcardUtils } = searchSettings.parserSettings
+ const { caseInsensitive, mode } = searchSettings
+ const isExact = mode === 'exact'
+
+ // Important modifier is optional for query in include mode
+ let levelMatch = isExact
+ ? queryNode.important === fileNode.important
+ : queryNode.important
+ ? Boolean(fileNode.important)
+ : true
+
+ const queryNodeStringContent = queryNode.property as string
+
+ const fileNodeStringContent = fileNode.property as string
+
+ const wildcardsMeta = wildcardUtils.getStringWildcardsFromString(
+ queryNodeStringContent,
+ )
+
+ if (wildcardsMeta.length > 0) {
+ levelMatch =
+ levelMatch &&
+ matchStringOrIdentifierAliases({
+ queryValue: queryNodeStringContent,
+ fileValue: fileNodeStringContent,
+ wildcardsMeta,
+ matchContext,
+ wildcardUtils,
+ caseInsensitive,
+ })
+ } else {
+ /**
+ * If there are no wildcards in given prop, compare prop values directly
+ */
+ levelMatch =
+ levelMatch && queryNodeStringContent === fileNodeStringContent
+ }
+
+ // We always want to return here, otherwise generic string wildcard matching would take over and match incorrectly
+ return {
+ levelMatch,
+ queryKeysToTraverseForValidatingMatch: ['value'],
+ fileKeysToTraverseForValidatingMatch: ['value'],
+ fileKeysToTraverseForOtherMatches,
+ }
+ }
+}
diff --git a/packages/core/src/parserSettings/cssTree/matchWildcardsInDimension.ts b/packages/core/src/parserSettings/cssTree/matchWildcardsInDimension.ts
new file mode 100644
index 0000000..37f4852
--- /dev/null
+++ b/packages/core/src/parserSettings/cssTree/matchWildcardsInDimension.ts
@@ -0,0 +1,71 @@
+import { NodesComparator, PoorNodeType } from '../../types'
+import { matchStringOrIdentifierAliases } from '../../searchStages/matchStringOrIdentifierAliases'
+
+/*
+ * Adds support for matching wildcard in "Dimension" unit and value
+ * Q: {width: 0x0px} C: {width: 5px}
+ * Q: {width: 5$$} C: {width: 5px}
+ * Q: {width: 0x0$$} C: {width: 5px}
+ */
+export const matchWildcardsInDimension: NodesComparator = (
+ { queryNode, fileNode, searchSettings, matchContext },
+ _,
+ { fileKeysToTraverseForOtherMatches, log },
+) => {
+ if (queryNode?.type === 'Dimension' && fileNode?.type === 'Dimension') {
+ log(
+ 'Compare dimension nodes',
+ queryNode.value as string,
+ queryNode.unit as string,
+ fileNode.value as string,
+ fileNode.unit as string,
+ )
+
+ const { wildcardUtils } = searchSettings.parserSettings
+ const { caseInsensitive } = searchSettings
+
+ let levelMatch = true
+
+ const queryNodeStringContent = queryNode.unit as string
+
+ const fileNodeStringContent = fileNode.unit as string
+
+ const wildcardsMeta = wildcardUtils.getStringWildcardsFromString(
+ queryNodeStringContent,
+ )
+
+ if (wildcardsMeta.length > 0) {
+ levelMatch =
+ levelMatch &&
+ matchStringOrIdentifierAliases({
+ queryValue: queryNodeStringContent,
+ fileValue: fileNodeStringContent,
+ wildcardsMeta,
+ matchContext,
+ wildcardUtils,
+ caseInsensitive,
+ })
+ } else {
+ /**
+ * If there are no wildcards in given prop, compare prop values directly
+ */
+ levelMatch =
+ levelMatch && queryNodeStringContent === fileNodeStringContent
+ }
+
+ /**
+ * Compare values only if there is no numeric wildcard in query
+ */
+ if (queryNode.value !== wildcardUtils.numericWildcard) {
+ levelMatch = levelMatch && queryNode.value === fileNode.value
+ }
+
+ // We always want to return here, otherwise generic string wildcard matching would take over and match incorrectly
+ return {
+ levelMatch,
+ queryKeysToTraverseForValidatingMatch: [],
+ fileKeysToTraverseForValidatingMatch: [],
+ fileKeysToTraverseForOtherMatches,
+ }
+ }
+}
diff --git a/packages/core/src/parserSettings/cssTree/settings.ts b/packages/core/src/parserSettings/cssTree/settings.ts
new file mode 100644
index 0000000..1cffbca
--- /dev/null
+++ b/packages/core/src/parserSettings/cssTree/settings.ts
@@ -0,0 +1,383 @@
+import { parse, ParseOptions, toPlainObject } from 'css-tree'
+import {
+ Location,
+ MatchPosition,
+ NumericLiteralUtils,
+ ParserSettings,
+ PoorNodeType,
+ ProgramNodeAndBlockNodeUtils,
+ StringLikeLiteralUtils,
+ NodesComparatorParameters,
+ GetUniqueTokensFromStringOrIdentifierNode,
+} from '../../types'
+import {
+ decomposeString,
+ normalizeText,
+ runNodesComparators,
+} from '../../utils'
+import {
+ getIdentifierNodeName,
+ identifierNodeTypes,
+ setIdentifierNodeName,
+ wildcardUtils,
+} from './common'
+import { traverseAst } from '../../searchStages/traverseAndMatch'
+import { beforeWildcardsComparators } from './beforeWildcardsComparators'
+import { afterWildcardsComparators } from './afterWildcardsComparators'
+
+const supportedExtensions = ['css']
+
+const getProgramNodeFromRootNode = (rootNode: PoorNodeType) => rootNode // root node is program node
+
+const getProgramBodyFromRootNode = (fileNode: PoorNodeType) => {
+ return fileNode.children as PoorNodeType[]
+}
+
+const unwrapExpressionStatement = (node: PoorNodeType) => {
+ return node as PoorNodeType
+}
+
+const createBlockStatementNode = (
+ children: PoorNodeType[],
+ position: MatchPosition,
+) => ({
+ type: 'Block',
+ children,
+ ...position,
+})
+
+const isNode = (maybeNode: PoorNodeType) => {
+ return typeof maybeNode?.type === 'string'
+}
+
+const astPropsToSkip = ['loc']
+
+const parseCode = (code: string) => {
+ const sharedOptions: ParseOptions = {
+ parseAtrulePrelude: true,
+ parseRulePrelude: true,
+ parseValue: true,
+ positions: true,
+ }
+
+ if (code.includes('{')) {
+ return toPlainObject(
+ parse(code, { ...sharedOptions, context: 'stylesheet' }),
+ ) as unknown as PoorNodeType
+ } else {
+ return toPlainObject(
+ parse(code, { ...sharedOptions, context: 'declarationList' }),
+ ) as unknown as PoorNodeType
+ }
+}
+
+type NodeValueSanitizers = Record any>>
+
+const nodeValuesSanitizers: NodeValueSanitizers = {
+ ['Raw']: {
+ value: normalizeText,
+ },
+}
+
+const getSanitizedNodeValue = (
+ nodeType: string,
+ valueKey: string,
+ value: unknown,
+) => {
+ const valueSanitizer = nodeValuesSanitizers?.[nodeType]?.[valueKey]
+
+ if (valueSanitizer) {
+ return valueSanitizer(value)
+ }
+
+ return value
+}
+
+const shouldCompareNode = (node: PoorNodeType) => {
+ if (node.type === 'WhiteSpace') {
+ return false
+ }
+
+ if (node.type === 'Raw') {
+ const value: string = getSanitizedNodeValue('Raw', 'value', node.value)
+
+ const shouldCompare = value.length > 0
+
+ return shouldCompare
+ }
+
+ return true
+}
+
+const getNodeType = (node: PoorNodeType) => node.type as string
+
+const isIdentifierNode = (node: PoorNodeType) =>
+ identifierNodeTypes.includes(getNodeType(node))
+
+const stringLikeNodeTypes = [
+ 'TypeSelector',
+ 'Raw',
+ 'ClassSelector',
+ 'Identifier',
+ 'IdSelector',
+ 'Url',
+]
+
+const stringLikeLiteralUtils: StringLikeLiteralUtils = {
+ // Raw is only pure string node
+ isStringLikeLiteralNode: (node: PoorNodeType) =>
+ stringLikeNodeTypes.includes(node.type as string),
+ getStringLikeLiteralValue: (node: PoorNodeType) => {
+ return (node?.value as string) || (node?.name as string)
+ },
+}
+
+const pureNumericNodes = ['Percentage', 'Number', 'Hash']
+
+const numericLiteralUtils: NumericLiteralUtils = {
+ isNumericLiteralNode: (node: PoorNodeType) =>
+ pureNumericNodes.includes(node.type as string),
+ getNumericLiteralValue: (node: PoorNodeType) => node.value as string,
+}
+
+const programNodeAndBlockNodeUtils: ProgramNodeAndBlockNodeUtils = {
+ isProgramNode: (node: PoorNodeType) => node.type === 'StyleSheet',
+ isBlockNode: (node: PoorNodeType) => node.type === 'Block',
+ programNodeBodyKey: 'children',
+ blockNodeBodyKey: 'children',
+}
+
+const getNodePosition: ParserSettings['getNodePosition'] = (
+ node: PoorNodeType,
+) => {
+ const location = node.loc as unknown as Location
+
+ return {
+ start: ((location as any)?.start?.offset as number) ?? 0,
+ end: ((location as any)?.end?.offset as number) ?? 0,
+ loc: {
+ start: {
+ line: location.start.line,
+ column: location.start.column - 1, // We need 0-based, parser return 1-based
+ },
+ end: {
+ line: location.end.line,
+ column: location.end.column - 1, // We need 0-based, parser return 1-based
+ },
+ },
+ }
+}
+
+const getParseErrorLocation = (e: any) => ({
+ line: e.loc?.line ?? 0,
+ column: e.loc?.column ?? 0,
+})
+
+const alternativeNodeTypes = {
+ Identifier: identifierNodeTypes,
+}
+
+/**
+ * To support wildcards in caa we have to
+ * - encode wildcard, do it in query text before parsing $$ => a_a_x
+ * - decode wildcard, traverse parsed query and: a_a_x => $$
+ * - Same for numeric wildcard 0x0 -> 00000000 // 0{8}
+ * `$$` is invalid tag name start in all html parsers
+ */
+const encodedStringWildcardSequence = 'a_a_a'
+const encodedNodesTreeWildcardSequence = 'z_z_z'
+
+const encodedNumericWildcardSequence = '00000000'
+
+const preprocessQueryCode = (code: string) => {
+ const queryCode = code
+ .replace(/(\$\$\$)/g, () => encodedNodesTreeWildcardSequence)
+ .replace(/(\$\$)/g, () => encodedStringWildcardSequence)
+ .replace(/0x0/g, encodedNumericWildcardSequence)
+
+ return queryCode
+}
+
+const replaceEncodedWildcards = (value: string) =>
+ value
+ .replace(/a_a_a/g, () => '$$')
+ .replace(/z_z_z/g, () => '$$$')
+ .replace(/0{8}/g, '0x0')
+
+const stringNodeTypes = {
+ withName: [
+ 'Identifier',
+ 'IdSelector',
+ 'MediaFeature',
+ 'ClassSelector',
+ 'PseudoClassSelector',
+ 'PseudoElementSelector',
+ 'TypeSelector',
+ 'Function',
+ 'Combinator',
+ ],
+ withValue: ['String', 'Url'],
+ withProperty: ['Declaration'],
+}
+
+const postprocessQueryNodeWithName = (node: PoorNodeType) => {
+ const name = node.name as string
+
+ if (
+ name.includes(encodedStringWildcardSequence) ||
+ name.includes(encodedNodesTreeWildcardSequence)
+ ) {
+ node.name = replaceEncodedWildcards(name)
+ }
+}
+
+const postprocessQueryNodeWithValue = (node: PoorNodeType) => {
+ const value = node.value as string
+
+ if (
+ value.includes(encodedStringWildcardSequence) ||
+ value.includes(encodedNodesTreeWildcardSequence) ||
+ value.includes(encodedNumericWildcardSequence)
+ ) {
+ node.value = replaceEncodedWildcards(value)
+ }
+}
+
+const postprocessQueryNodeWithProperty = (node: PoorNodeType) => {
+ const property = node.property as string
+
+ if (
+ property.includes(encodedStringWildcardSequence) ||
+ property.includes(encodedNodesTreeWildcardSequence)
+ ) {
+ node.property = replaceEncodedWildcards(property)
+ }
+}
+
+const createVisitorsForNodeTypes = (
+ types: string[],
+ visitorFn: (node: PoorNodeType) => void,
+) =>
+ types.reduce(
+ (visitorsMap, nodeType) => ({
+ ...visitorsMap,
+ [nodeType]: visitorFn,
+ }),
+ {},
+ )
+
+const postprocessVisitors = {
+ ...createVisitorsForNodeTypes(
+ stringNodeTypes.withName,
+ postprocessQueryNodeWithName,
+ ),
+ ...createVisitorsForNodeTypes(
+ stringNodeTypes.withProperty,
+ postprocessQueryNodeWithProperty,
+ ),
+ ...createVisitorsForNodeTypes(
+ [...stringNodeTypes.withValue, ...pureNumericNodes],
+ postprocessQueryNodeWithValue,
+ ),
+ Dimension: (node: PoorNodeType) => {
+ const unit = node.unit as string
+ const value = node.value as string
+
+ if (unit.includes(encodedStringWildcardSequence)) {
+ node.unit = replaceEncodedWildcards(unit)
+ }
+
+ if (value === encodedNumericWildcardSequence) {
+ node.value = replaceEncodedWildcards(value)
+ }
+ },
+}
+
+const postprocessQueryNode = (queryNode: PoorNodeType) => {
+ traverseAst(queryNode, isNode, getNodeType, postprocessVisitors)
+
+ return queryNode
+}
+
+const compareNodesBeforeWildcardsComparison = (
+ ...nodeComparatorParams: NodesComparatorParameters
+) => {
+ return runNodesComparators(beforeWildcardsComparators, nodeComparatorParams)
+}
+
+const compareNodesAfterWildcardsComparison = (
+ ...nodeComparatorParams: NodesComparatorParameters
+) => {
+ return runNodesComparators(afterWildcardsComparators, nodeComparatorParams)
+}
+
+const getUniqueTokensFromStringOrIdentifierNode: GetUniqueTokensFromStringOrIdentifierNode =
+ ({ queryNode, caseInsensitive, parserSettings }) => {
+ const MIN_TOKEN_LEN = 2
+
+ const { anyStringWildcardRegExp } = parserSettings.wildcardUtils
+ const tokens: string[] = []
+
+ const valuesToProcess: string[] = []
+
+ if (stringNodeTypes.withName.includes(queryNode.type as string)) {
+ valuesToProcess.push(queryNode.name as string)
+ }
+
+ if (stringNodeTypes.withProperty.includes(queryNode.type as string)) {
+ valuesToProcess.push(queryNode.property as string)
+ }
+
+ if (stringNodeTypes.withValue.includes(queryNode.type as string)) {
+ valuesToProcess.push(queryNode.value as string)
+ }
+
+ valuesToProcess
+ .map((val) =>
+ parserSettings.wildcardUtils.removeWildcardAliasesFromStringLiteral(
+ val,
+ ),
+ )
+ .map((val) => decomposeString(val, anyStringWildcardRegExp))
+ .flat(1)
+ .forEach((part) => {
+ if (part.length >= MIN_TOKEN_LEN) {
+ tokens.push(caseInsensitive ? part.toLocaleLowerCase() : part)
+ }
+ })
+
+ return tokens
+ }
+
+export const cssTree: ParserSettings = {
+ supportedExtensions,
+ parseCode,
+ isNode,
+ isIdentifierNode,
+ astPropsToSkip,
+ getProgramBodyFromRootNode,
+ getProgramNodeFromRootNode,
+ getIdentifierNodeName,
+ getNodeType,
+ unwrapExpressionStatement,
+ createBlockStatementNode,
+ getSanitizedNodeValue,
+ identifierNodeTypes,
+ setIdentifierNodeName,
+ shouldCompareNode,
+ wildcardUtils,
+ compareNodesBeforeWildcardsComparison,
+ compareNodesAfterWildcardsComparison,
+ identifierTypeAnnotationFieldName: 'typeAnnotation',
+ stringLikeLiteralUtils,
+ numericLiteralUtils,
+ programNodeAndBlockNodeUtils,
+ getNodePosition,
+ getParseErrorLocation,
+ alternativeNodeTypes,
+ postprocessQueryNode,
+ preprocessQueryCode,
+ getUniqueTokensFromStringOrIdentifierNode,
+}
+
+export default cssTree
diff --git a/packages/core/src/parserSettings/espreeParser/afterWildcardsComparators.ts b/packages/core/src/parserSettings/espreeParser/afterWildcardsComparators.ts
new file mode 100644
index 0000000..cdee906
--- /dev/null
+++ b/packages/core/src/parserSettings/espreeParser/afterWildcardsComparators.ts
@@ -0,0 +1,19 @@
+import { NodesComparator } from '../../types'
+import { wildcardForAnyImport } from './nodeComparators/wildcardForAnyImport'
+import { matchJsxElementRegardlessClosingTagNodesComparator } from './nodeComparators/matchJsxElementRegardlessClosingTag'
+import { matchJsxIdentifierUsingIdentifierNodesComparator } from './nodeComparators/matchJsxIdentifierUsingIdentifier'
+import { partialMatchTemplateLiteralNodesComparator } from './nodeComparators/partialMatchTemplateLiteral'
+import { matchOptionalFlagInMemberExpressionNodesComparator } from './nodeComparators/matchOptionalFlagInMemberExpression'
+import { matchDestructPropBeforeRenameNodesComparator } from './nodeComparators/matchDestructPropBeforeRename'
+import { matchObjectPropertiesOfDifferentTypesNodesComparator } from './nodeComparators/matchObjectPropertiesOfDifferentTypes'
+
+// Better keep this order
+export const afterWildcardsComparators: NodesComparator[] = [
+ wildcardForAnyImport,
+ matchDestructPropBeforeRenameNodesComparator,
+ matchObjectPropertiesOfDifferentTypesNodesComparator,
+ matchJsxElementRegardlessClosingTagNodesComparator,
+ matchJsxIdentifierUsingIdentifierNodesComparator,
+ partialMatchTemplateLiteralNodesComparator,
+ matchOptionalFlagInMemberExpressionNodesComparator,
+]
diff --git a/packages/core/src/parserSettings/espreeParser/beforeWildcardsComparators.ts b/packages/core/src/parserSettings/espreeParser/beforeWildcardsComparators.ts
new file mode 100644
index 0000000..6203233
--- /dev/null
+++ b/packages/core/src/parserSettings/espreeParser/beforeWildcardsComparators.ts
@@ -0,0 +1,6 @@
+import { NodesComparator } from '../../types'
+import { wildcardForAssignmentPatternOrDefaultParamValuesNodesComparator } from './nodeComparators/wildcardForAssignmentPatternOrDefaultParamValues'
+
+export const beforeWildcardsComparators: NodesComparator[] = [
+ wildcardForAssignmentPatternOrDefaultParamValuesNodesComparator,
+]
diff --git a/packages/core/src/parserSettings/espreeParser/common.ts b/packages/core/src/parserSettings/espreeParser/common.ts
new file mode 100644
index 0000000..f9ac9bc
--- /dev/null
+++ b/packages/core/src/parserSettings/espreeParser/common.ts
@@ -0,0 +1,18 @@
+import { numericWildcard, wildcardChar } from '../_common/JSFamilyCommon'
+import { createWildcardUtils } from '../../wildcardUtilsFactory'
+import { PoorNodeType } from '../../types'
+export const identifierNodeTypes = ['Identifier', 'JSXIdentifier']
+export const getIdentifierNodeName = (node: PoorNodeType) => node.name as string
+export const setIdentifierNodeName = (node: PoorNodeType, name: string) => {
+ node.name = name
+}
+
+export const getNodeType = (node: PoorNodeType) => node.type as string
+
+export const wildcardUtils = createWildcardUtils(
+ identifierNodeTypes,
+ numericWildcard,
+ wildcardChar,
+ getIdentifierNodeName,
+ getNodeType,
+)
diff --git a/packages/core/src/parserSettings/espreeParser/nodeComparators/matchDestructPropBeforeRename.ts b/packages/core/src/parserSettings/espreeParser/nodeComparators/matchDestructPropBeforeRename.ts
new file mode 100644
index 0000000..1d522cf
--- /dev/null
+++ b/packages/core/src/parserSettings/espreeParser/nodeComparators/matchDestructPropBeforeRename.ts
@@ -0,0 +1,6 @@
+import { createMatchDestructPropBeforeRenameNodesComparator } from '../../nodeComparatorFactories/JavaScriptSpecific/matchDestructPropBeforeRename'
+
+export const matchDestructPropBeforeRenameNodesComparator =
+ createMatchDestructPropBeforeRenameNodesComparator({
+ objectPropertyNodeName: 'Property',
+ })
diff --git a/packages/core/src/parserSettings/espreeParser/nodeComparators/matchJsxElementRegardlessClosingTag.ts b/packages/core/src/parserSettings/espreeParser/nodeComparators/matchJsxElementRegardlessClosingTag.ts
new file mode 100644
index 0000000..a60143b
--- /dev/null
+++ b/packages/core/src/parserSettings/espreeParser/nodeComparators/matchJsxElementRegardlessClosingTag.ts
@@ -0,0 +1,4 @@
+import { createMatchJsxElementRegardlessClosingTagNodesComparator } from '../../nodeComparatorFactories/JsxSpecific/matchJsxElementRegardlessClosingTag'
+
+export const matchJsxElementRegardlessClosingTagNodesComparator =
+ createMatchJsxElementRegardlessClosingTagNodesComparator()
diff --git a/packages/core/src/parserSettings/espreeParser/nodeComparators/matchJsxIdentifierUsingIdentifier.ts b/packages/core/src/parserSettings/espreeParser/nodeComparators/matchJsxIdentifierUsingIdentifier.ts
new file mode 100644
index 0000000..7a21bf7
--- /dev/null
+++ b/packages/core/src/parserSettings/espreeParser/nodeComparators/matchJsxIdentifierUsingIdentifier.ts
@@ -0,0 +1,4 @@
+import { createMatchJsxIdentifierUsingIdentifierNodesComparator } from '../../nodeComparatorFactories/JsxSpecific/matchJsxIdentifierUsingIdentifier'
+
+export const matchJsxIdentifierUsingIdentifierNodesComparator =
+ createMatchJsxIdentifierUsingIdentifierNodesComparator()
diff --git a/packages/core/src/parserSettings/espreeParser/nodeComparators/matchObjectPropertiesOfDifferentTypes.ts b/packages/core/src/parserSettings/espreeParser/nodeComparators/matchObjectPropertiesOfDifferentTypes.ts
new file mode 100644
index 0000000..99bdf9b
--- /dev/null
+++ b/packages/core/src/parserSettings/espreeParser/nodeComparators/matchObjectPropertiesOfDifferentTypes.ts
@@ -0,0 +1,6 @@
+import { createMatchObjectPropertiesOfDifferentTypesNodesComparator } from '../../nodeComparatorFactories/JavaScriptSpecific/matchObjectPropertiesOfDifferentTypes'
+
+export const matchObjectPropertiesOfDifferentTypesNodesComparator =
+ createMatchObjectPropertiesOfDifferentTypesNodesComparator({
+ objectPropertyNodeName: 'Property',
+ })
diff --git a/packages/core/src/parserSettings/espreeParser/nodeComparators/matchOptionalFlagInMemberExpression.ts b/packages/core/src/parserSettings/espreeParser/nodeComparators/matchOptionalFlagInMemberExpression.ts
new file mode 100644
index 0000000..2287657
--- /dev/null
+++ b/packages/core/src/parserSettings/espreeParser/nodeComparators/matchOptionalFlagInMemberExpression.ts
@@ -0,0 +1,4 @@
+import { createMatchOptionalFlagInMemberExpressionNodesComparator } from '../../nodeComparatorFactories/JavaScriptSpecific/matchOptionalFlagInMemberExpression'
+
+export const matchOptionalFlagInMemberExpressionNodesComparator =
+ createMatchOptionalFlagInMemberExpressionNodesComparator()
diff --git a/packages/core/src/parserSettings/espreeParser/nodeComparators/partialMatchTemplateLiteral.ts b/packages/core/src/parserSettings/espreeParser/nodeComparators/partialMatchTemplateLiteral.ts
new file mode 100644
index 0000000..3579c69
--- /dev/null
+++ b/packages/core/src/parserSettings/espreeParser/nodeComparators/partialMatchTemplateLiteral.ts
@@ -0,0 +1,4 @@
+import { createPartialMatchTemplateLiteralNodesComparator } from '../../nodeComparatorFactories/JavaScriptSpecific/partialMatchTemplateLiteral'
+
+export const partialMatchTemplateLiteralNodesComparator =
+ createPartialMatchTemplateLiteralNodesComparator()
diff --git a/packages/core/src/parserSettings/espreeParser/nodeComparators/wildcardForAnyImport.ts b/packages/core/src/parserSettings/espreeParser/nodeComparators/wildcardForAnyImport.ts
new file mode 100644
index 0000000..103a66d
--- /dev/null
+++ b/packages/core/src/parserSettings/espreeParser/nodeComparators/wildcardForAnyImport.ts
@@ -0,0 +1,6 @@
+import { createWildcardForAnyImportNodesComparator } from '../../nodeComparatorFactories/JavaScriptSpecific/wildcardForAnyImport'
+import { wildcardUtils } from '../common'
+
+export const wildcardForAnyImport = createWildcardForAnyImportNodesComparator({
+ wildcardUtils,
+})
diff --git a/packages/core/src/parserSettings/espreeParser/nodeComparators/wildcardForAssignmentPatternOrDefaultParamValues.ts b/packages/core/src/parserSettings/espreeParser/nodeComparators/wildcardForAssignmentPatternOrDefaultParamValues.ts
new file mode 100644
index 0000000..6f1c78c
--- /dev/null
+++ b/packages/core/src/parserSettings/espreeParser/nodeComparators/wildcardForAssignmentPatternOrDefaultParamValues.ts
@@ -0,0 +1,4 @@
+import { createWildcardForAssignmentPatternOrDefaultParamValuesNodesComparator } from '../../nodeComparatorFactories/JavaScriptSpecific/wildcardForAssignmentPatternOrDefaultParamValues'
+
+export const wildcardForAssignmentPatternOrDefaultParamValuesNodesComparator =
+ createWildcardForAssignmentPatternOrDefaultParamValuesNodesComparator()
diff --git a/packages/core/src/parserSettings/espreeParser/settings.ts b/packages/core/src/parserSettings/espreeParser/settings.ts
new file mode 100644
index 0000000..76ad0b6
--- /dev/null
+++ b/packages/core/src/parserSettings/espreeParser/settings.ts
@@ -0,0 +1,240 @@
+import { parse } from 'espree'
+
+import {
+ Location,
+ NodesComparatorParameters,
+ NumericLiteralUtils,
+ ParserSettings,
+ PoorNodeType,
+ ProgramNodeAndBlockNodeUtils,
+ StringLikeLiteralUtils,
+ MatchPosition,
+} from '../../types'
+import { normalizeText, runNodesComparators } from '../../utils'
+import { supportedExtensions } from '../_common/JSFamilyCommon'
+import { afterWildcardsComparators } from './afterWildcardsComparators'
+import { beforeWildcardsComparators } from './beforeWildcardsComparators'
+import {
+ getIdentifierNodeName,
+ getNodeType,
+ identifierNodeTypes,
+ wildcardUtils,
+ setIdentifierNodeName,
+} from './common'
+
+const getProgramNodeFromRootNode = (rootNode: PoorNodeType) => rootNode // root node is program node
+
+const getProgramBodyFromRootNode = (rootNode: PoorNodeType) => {
+ return getProgramNodeFromRootNode(rootNode).body as PoorNodeType[]
+}
+
+const unwrapExpressionStatement = (node: PoorNodeType) => {
+ if (typeof node !== 'object') {
+ return node
+ }
+
+ if (node.type === 'ExpressionStatement') {
+ return node.expression as PoorNodeType
+ }
+
+ return node as PoorNodeType
+}
+
+const createBlockStatementNode = (
+ body: PoorNodeType[],
+ position: MatchPosition,
+) =>
+ ({
+ type: 'BlockStatement',
+ body,
+ loc: position.loc,
+ range: [position.start, position.end],
+ } as unknown as PoorNodeType)
+
+const isNode = (maybeNode: PoorNodeType) => {
+ return typeof maybeNode?.type === 'string'
+}
+
+const astPropsToSkip = [
+ 'start',
+ 'end',
+ 'loc',
+ 'range',
+ 'raw',
+ 'trailingComments',
+ 'leadingComments',
+ 'comments',
+ 'tail', // Support for partial matching of template literals
+ 'parent', // in eslint there is parent prop in node
+ { type: 'ArrowFunctionExpression', key: 'expression' }, // flag on ArrowFunctionExpression
+]
+
+const parseCode = (code: string, filePath = '') => {
+ const options = {
+ range: true,
+ loc: true,
+ comment: false,
+ tokens: false,
+ ecmaVersion: 'latest',
+ sourceType: 'module',
+ ecmaFeatures: {
+ jsx: true,
+ globalReturn: true,
+ impliedStrict: false,
+ },
+ }
+
+ const maybeWrappedJSON = /\.json$/.test(filePath) ? `(${code})` : code
+
+ const ast = parse(maybeWrappedJSON, options)
+
+ return ast as unknown as PoorNodeType
+}
+
+const sanitizeTemplateElementValue = ({
+ raw,
+ cooked,
+}: {
+ raw: string
+ cooked: string
+}) => {
+ return {
+ raw: normalizeText(raw),
+ cooked: normalizeText(cooked),
+ }
+}
+
+type NodeValueSanitizers = Record any>>
+
+const nodeValuesSanitizers: NodeValueSanitizers = {
+ ['JSXText']: {
+ value: normalizeText,
+ raw: normalizeText,
+ },
+ ['TemplateElement']: {
+ value: sanitizeTemplateElementValue,
+ },
+}
+
+const getSanitizedNodeValue = (
+ nodeType: string,
+ valueKey: string,
+ value: unknown,
+) => {
+ const valueSanitizer = nodeValuesSanitizers?.[nodeType]?.[valueKey]
+
+ if (valueSanitizer) {
+ return valueSanitizer(value)
+ }
+
+ return value
+}
+
+const shouldCompareNode = (node: PoorNodeType) => {
+ if (node.type === 'JSXText') {
+ const value: string = getSanitizedNodeValue('JSXText', 'value', node.value)
+
+ return value.length > 0
+ }
+
+ return true
+}
+
+const compareNodesBeforeWildcardsComparison = (
+ ...nodeComparatorParams: NodesComparatorParameters
+) => {
+ return runNodesComparators(beforeWildcardsComparators, nodeComparatorParams)
+}
+
+const compareNodesAfterWildcardsComparison = (
+ ...nodeComparatorParams: NodesComparatorParameters
+) => {
+ return runNodesComparators(afterWildcardsComparators, nodeComparatorParams)
+}
+
+const isIdentifierNode = (node: PoorNodeType) =>
+ identifierNodeTypes.includes(getNodeType(node))
+
+const isFirstCharStringStart = (str: string) =>
+ str.charAt(0) === `'` || str.charAt(0) === `"`
+
+const stringLikeLiteralUtils: StringLikeLiteralUtils = {
+ isStringLikeLiteralNode: (node: PoorNodeType) =>
+ (node.type === 'Literal' && isFirstCharStringStart(node.raw as string)) ||
+ node.type === 'TemplateElement' ||
+ node.type === 'JSXText',
+ getStringLikeLiteralValue: (node: PoorNodeType) => {
+ if (node.type === 'TemplateElement') {
+ const { raw } = sanitizeTemplateElementValue(
+ node.value as { raw: string; cooked: string },
+ )
+
+ return raw
+ }
+
+ // (node.type === 'Literal' || node.type === 'JSXText'
+ return normalizeText(node.value as string)
+ },
+}
+
+const numericLiteralUtils: NumericLiteralUtils = {
+ isNumericLiteralNode: (node: PoorNodeType) =>
+ node.type === 'Literal' && !isFirstCharStringStart(node.raw as string),
+ getNumericLiteralValue: (node: PoorNodeType) => node.raw as string,
+}
+
+const programNodeAndBlockNodeUtils: ProgramNodeAndBlockNodeUtils = {
+ isProgramNode: (node: PoorNodeType) => node.type === 'Program',
+ isBlockNode: (node: PoorNodeType) => node.type === 'BlockStatement',
+ programNodeBodyKey: 'body',
+ blockNodeBodyKey: 'body',
+}
+
+const getNodePosition: ParserSettings['getNodePosition'] = (
+ node: PoorNodeType,
+) => ({
+ start: (node.range as any)[0] as number,
+ end: (node.range as any)[1] as number,
+ loc: node.loc as unknown as Location,
+})
+
+const getParseErrorLocation = (e: any) => ({
+ line: e.lineNumber ?? 0,
+ column: e.column ?? 0,
+})
+
+const alternativeNodeTypes = {
+ Identifier: identifierNodeTypes,
+ ChainExpression: ['MemberExpression'],
+ MemberExpression: ['ChainExpression'],
+ BlockStatement: ['Program'],
+}
+export const espreeParserSettings: ParserSettings = {
+ supportedExtensions,
+ parseCode,
+ isNode,
+ isIdentifierNode,
+ identifierNodeTypes,
+ astPropsToSkip,
+ getProgramBodyFromRootNode,
+ getProgramNodeFromRootNode,
+ getIdentifierNodeName,
+ setIdentifierNodeName,
+ getNodeType,
+ unwrapExpressionStatement,
+ createBlockStatementNode,
+ getSanitizedNodeValue,
+ shouldCompareNode,
+ wildcardUtils,
+ compareNodesBeforeWildcardsComparison,
+ compareNodesAfterWildcardsComparison,
+ identifierTypeAnnotationFieldName: 'typeAnnotation',
+ stringLikeLiteralUtils,
+ numericLiteralUtils,
+ programNodeAndBlockNodeUtils,
+ getNodePosition,
+ getParseErrorLocation,
+ alternativeNodeTypes,
+}
+
+export default espreeParserSettings
diff --git a/packages/core/src/parserSettings/esprimaParser/afterWildcardsComparators.ts b/packages/core/src/parserSettings/esprimaParser/afterWildcardsComparators.ts
new file mode 100644
index 0000000..cdee906
--- /dev/null
+++ b/packages/core/src/parserSettings/esprimaParser/afterWildcardsComparators.ts
@@ -0,0 +1,19 @@
+import { NodesComparator } from '../../types'
+import { wildcardForAnyImport } from './nodeComparators/wildcardForAnyImport'
+import { matchJsxElementRegardlessClosingTagNodesComparator } from './nodeComparators/matchJsxElementRegardlessClosingTag'
+import { matchJsxIdentifierUsingIdentifierNodesComparator } from './nodeComparators/matchJsxIdentifierUsingIdentifier'
+import { partialMatchTemplateLiteralNodesComparator } from './nodeComparators/partialMatchTemplateLiteral'
+import { matchOptionalFlagInMemberExpressionNodesComparator } from './nodeComparators/matchOptionalFlagInMemberExpression'
+import { matchDestructPropBeforeRenameNodesComparator } from './nodeComparators/matchDestructPropBeforeRename'
+import { matchObjectPropertiesOfDifferentTypesNodesComparator } from './nodeComparators/matchObjectPropertiesOfDifferentTypes'
+
+// Better keep this order
+export const afterWildcardsComparators: NodesComparator[] = [
+ wildcardForAnyImport,
+ matchDestructPropBeforeRenameNodesComparator,
+ matchObjectPropertiesOfDifferentTypesNodesComparator,
+ matchJsxElementRegardlessClosingTagNodesComparator,
+ matchJsxIdentifierUsingIdentifierNodesComparator,
+ partialMatchTemplateLiteralNodesComparator,
+ matchOptionalFlagInMemberExpressionNodesComparator,
+]
diff --git a/packages/core/src/parserSettings/esprimaParser/beforeWildcardsComparators.ts b/packages/core/src/parserSettings/esprimaParser/beforeWildcardsComparators.ts
new file mode 100644
index 0000000..6203233
--- /dev/null
+++ b/packages/core/src/parserSettings/esprimaParser/beforeWildcardsComparators.ts
@@ -0,0 +1,6 @@
+import { NodesComparator } from '../../types'
+import { wildcardForAssignmentPatternOrDefaultParamValuesNodesComparator } from './nodeComparators/wildcardForAssignmentPatternOrDefaultParamValues'
+
+export const beforeWildcardsComparators: NodesComparator[] = [
+ wildcardForAssignmentPatternOrDefaultParamValuesNodesComparator,
+]
diff --git a/packages/core/src/parserSettings/esprimaParser/common.ts b/packages/core/src/parserSettings/esprimaParser/common.ts
new file mode 100644
index 0000000..f9ac9bc
--- /dev/null
+++ b/packages/core/src/parserSettings/esprimaParser/common.ts
@@ -0,0 +1,18 @@
+import { numericWildcard, wildcardChar } from '../_common/JSFamilyCommon'
+import { createWildcardUtils } from '../../wildcardUtilsFactory'
+import { PoorNodeType } from '../../types'
+export const identifierNodeTypes = ['Identifier', 'JSXIdentifier']
+export const getIdentifierNodeName = (node: PoorNodeType) => node.name as string
+export const setIdentifierNodeName = (node: PoorNodeType, name: string) => {
+ node.name = name
+}
+
+export const getNodeType = (node: PoorNodeType) => node.type as string
+
+export const wildcardUtils = createWildcardUtils(
+ identifierNodeTypes,
+ numericWildcard,
+ wildcardChar,
+ getIdentifierNodeName,
+ getNodeType,
+)
diff --git a/packages/core/src/parserSettings/esprimaParser/nodeComparators/matchDestructPropBeforeRename.ts b/packages/core/src/parserSettings/esprimaParser/nodeComparators/matchDestructPropBeforeRename.ts
new file mode 100644
index 0000000..1d522cf
--- /dev/null
+++ b/packages/core/src/parserSettings/esprimaParser/nodeComparators/matchDestructPropBeforeRename.ts
@@ -0,0 +1,6 @@
+import { createMatchDestructPropBeforeRenameNodesComparator } from '../../nodeComparatorFactories/JavaScriptSpecific/matchDestructPropBeforeRename'
+
+export const matchDestructPropBeforeRenameNodesComparator =
+ createMatchDestructPropBeforeRenameNodesComparator({
+ objectPropertyNodeName: 'Property',
+ })
diff --git a/packages/core/src/parserSettings/esprimaParser/nodeComparators/matchJsxElementRegardlessClosingTag.ts b/packages/core/src/parserSettings/esprimaParser/nodeComparators/matchJsxElementRegardlessClosingTag.ts
new file mode 100644
index 0000000..a60143b
--- /dev/null
+++ b/packages/core/src/parserSettings/esprimaParser/nodeComparators/matchJsxElementRegardlessClosingTag.ts
@@ -0,0 +1,4 @@
+import { createMatchJsxElementRegardlessClosingTagNodesComparator } from '../../nodeComparatorFactories/JsxSpecific/matchJsxElementRegardlessClosingTag'
+
+export const matchJsxElementRegardlessClosingTagNodesComparator =
+ createMatchJsxElementRegardlessClosingTagNodesComparator()
diff --git a/packages/core/src/parserSettings/esprimaParser/nodeComparators/matchJsxIdentifierUsingIdentifier.ts b/packages/core/src/parserSettings/esprimaParser/nodeComparators/matchJsxIdentifierUsingIdentifier.ts
new file mode 100644
index 0000000..7a21bf7
--- /dev/null
+++ b/packages/core/src/parserSettings/esprimaParser/nodeComparators/matchJsxIdentifierUsingIdentifier.ts
@@ -0,0 +1,4 @@
+import { createMatchJsxIdentifierUsingIdentifierNodesComparator } from '../../nodeComparatorFactories/JsxSpecific/matchJsxIdentifierUsingIdentifier'
+
+export const matchJsxIdentifierUsingIdentifierNodesComparator =
+ createMatchJsxIdentifierUsingIdentifierNodesComparator()
diff --git a/packages/core/src/parserSettings/esprimaParser/nodeComparators/matchObjectPropertiesOfDifferentTypes.ts b/packages/core/src/parserSettings/esprimaParser/nodeComparators/matchObjectPropertiesOfDifferentTypes.ts
new file mode 100644
index 0000000..99bdf9b
--- /dev/null
+++ b/packages/core/src/parserSettings/esprimaParser/nodeComparators/matchObjectPropertiesOfDifferentTypes.ts
@@ -0,0 +1,6 @@
+import { createMatchObjectPropertiesOfDifferentTypesNodesComparator } from '../../nodeComparatorFactories/JavaScriptSpecific/matchObjectPropertiesOfDifferentTypes'
+
+export const matchObjectPropertiesOfDifferentTypesNodesComparator =
+ createMatchObjectPropertiesOfDifferentTypesNodesComparator({
+ objectPropertyNodeName: 'Property',
+ })
diff --git a/packages/core/src/parserSettings/esprimaParser/nodeComparators/matchOptionalFlagInMemberExpression.ts b/packages/core/src/parserSettings/esprimaParser/nodeComparators/matchOptionalFlagInMemberExpression.ts
new file mode 100644
index 0000000..2287657
--- /dev/null
+++ b/packages/core/src/parserSettings/esprimaParser/nodeComparators/matchOptionalFlagInMemberExpression.ts
@@ -0,0 +1,4 @@
+import { createMatchOptionalFlagInMemberExpressionNodesComparator } from '../../nodeComparatorFactories/JavaScriptSpecific/matchOptionalFlagInMemberExpression'
+
+export const matchOptionalFlagInMemberExpressionNodesComparator =
+ createMatchOptionalFlagInMemberExpressionNodesComparator()
diff --git a/packages/core/src/parserSettings/esprimaParser/nodeComparators/partialMatchTemplateLiteral.ts b/packages/core/src/parserSettings/esprimaParser/nodeComparators/partialMatchTemplateLiteral.ts
new file mode 100644
index 0000000..3579c69
--- /dev/null
+++ b/packages/core/src/parserSettings/esprimaParser/nodeComparators/partialMatchTemplateLiteral.ts
@@ -0,0 +1,4 @@
+import { createPartialMatchTemplateLiteralNodesComparator } from '../../nodeComparatorFactories/JavaScriptSpecific/partialMatchTemplateLiteral'
+
+export const partialMatchTemplateLiteralNodesComparator =
+ createPartialMatchTemplateLiteralNodesComparator()
diff --git a/packages/core/src/parserSettings/esprimaParser/nodeComparators/wildcardForAnyImport.ts b/packages/core/src/parserSettings/esprimaParser/nodeComparators/wildcardForAnyImport.ts
new file mode 100644
index 0000000..103a66d
--- /dev/null
+++ b/packages/core/src/parserSettings/esprimaParser/nodeComparators/wildcardForAnyImport.ts
@@ -0,0 +1,6 @@
+import { createWildcardForAnyImportNodesComparator } from '../../nodeComparatorFactories/JavaScriptSpecific/wildcardForAnyImport'
+import { wildcardUtils } from '../common'
+
+export const wildcardForAnyImport = createWildcardForAnyImportNodesComparator({
+ wildcardUtils,
+})
diff --git a/packages/core/src/parserSettings/esprimaParser/nodeComparators/wildcardForAssignmentPatternOrDefaultParamValues.ts b/packages/core/src/parserSettings/esprimaParser/nodeComparators/wildcardForAssignmentPatternOrDefaultParamValues.ts
new file mode 100644
index 0000000..6f1c78c
--- /dev/null
+++ b/packages/core/src/parserSettings/esprimaParser/nodeComparators/wildcardForAssignmentPatternOrDefaultParamValues.ts
@@ -0,0 +1,4 @@
+import { createWildcardForAssignmentPatternOrDefaultParamValuesNodesComparator } from '../../nodeComparatorFactories/JavaScriptSpecific/wildcardForAssignmentPatternOrDefaultParamValues'
+
+export const wildcardForAssignmentPatternOrDefaultParamValuesNodesComparator =
+ createWildcardForAssignmentPatternOrDefaultParamValuesNodesComparator()
diff --git a/packages/core/src/parserSettings/esprimaParser/settings.ts b/packages/core/src/parserSettings/esprimaParser/settings.ts
index b610495..558d15c 100644
--- a/packages/core/src/parserSettings/esprimaParser/settings.ts
+++ b/packages/core/src/parserSettings/esprimaParser/settings.ts
@@ -1,21 +1,230 @@
-import { typescriptEslintParserSettings } from '../typescriptEslintParser/settings'
-import { ParserSettings, PoorNodeType } from '../../types'
import esprima, { parseModule } from 'esprima'
-export const esprimaParserSettings: ParserSettings = {
- ...typescriptEslintParserSettings,
- parseCode: (code, filePath = '') => {
- const settings: esprima.ParseOptions = {
- jsx: true,
- range: true,
- loc: true,
- }
- const maybeWrappedJSON = /\.json$/.test(filePath) ? `(${code})` : code
+import {
+ Location,
+ NodesComparatorParameters,
+ NumericLiteralUtils,
+ ParserSettings,
+ PoorNodeType,
+ ProgramNodeAndBlockNodeUtils,
+ StringLikeLiteralUtils,
+ MatchPosition,
+} from '../../types'
+import { normalizeText, runNodesComparators } from '../../utils'
+import { supportedExtensions } from '../_common/JSFamilyCommon'
+import { afterWildcardsComparators } from './afterWildcardsComparators'
+import { beforeWildcardsComparators } from './beforeWildcardsComparators'
+import {
+ getIdentifierNodeName,
+ getNodeType,
+ identifierNodeTypes,
+ wildcardUtils,
+ setIdentifierNodeName,
+} from './common'
+
+const getProgramNodeFromRootNode = (rootNode: PoorNodeType) => rootNode // root node is program node
+
+const getProgramBodyFromRootNode = (rootNode: PoorNodeType) => {
+ return getProgramNodeFromRootNode(rootNode).body as PoorNodeType[]
+}
+
+const unwrapExpressionStatement = (node: PoorNodeType) => {
+ if (typeof node !== 'object') {
+ return node
+ }
+
+ if (node.type === 'ExpressionStatement') {
+ return node.expression as PoorNodeType
+ }
+
+ return node as PoorNodeType
+}
+
+const createBlockStatementNode = (
+ body: PoorNodeType[],
+ position: MatchPosition,
+) =>
+ ({
+ type: 'BlockStatement',
+ body,
+ loc: position.loc,
+ range: [position.start, position.end],
+ } as unknown as PoorNodeType)
+
+const isNode = (maybeNode: PoorNodeType) => {
+ return typeof maybeNode?.type === 'string'
+}
+
+const astPropsToSkip = [
+ 'loc',
+ 'range',
+ 'raw',
+ 'trailingComments',
+ 'leadingComments',
+ 'comments',
+ 'tail', // Support for partial matching of template literals
+ 'parent', // in eslint there is parent prop in node
+ { type: 'ArrowFunctionExpression', key: 'expression' }, // flag on ArrowFunctionExpression
+]
- const ast = parseModule(maybeWrappedJSON, settings)
+const parseCode = (code: string, filePath = '') => {
+ const settings: esprima.ParseOptions = {
+ jsx: true,
+ range: true,
+ loc: true,
+ }
+ const maybeWrappedJSON = /\.json$/.test(filePath) ? `(${code})` : code
- return ast as unknown as PoorNodeType
+ const ast = parseModule(maybeWrappedJSON, settings)
+
+ return ast as unknown as PoorNodeType
+}
+
+const sanitizeTemplateElementValue = ({
+ raw,
+ cooked,
+}: {
+ raw: string
+ cooked: string
+}) => {
+ return {
+ raw: normalizeText(raw),
+ cooked: normalizeText(cooked),
+ }
+}
+
+type NodeValueSanitizers = Record any>>
+
+const nodeValuesSanitizers: NodeValueSanitizers = {
+ ['JSXText']: {
+ value: normalizeText,
+ raw: normalizeText,
+ },
+ ['TemplateElement']: {
+ value: sanitizeTemplateElementValue,
},
}
+const getSanitizedNodeValue = (
+ nodeType: string,
+ valueKey: string,
+ value: unknown,
+) => {
+ const valueSanitizer = nodeValuesSanitizers?.[nodeType]?.[valueKey]
+
+ if (valueSanitizer) {
+ return valueSanitizer(value)
+ }
+
+ return value
+}
+
+const shouldCompareNode = (node: PoorNodeType) => {
+ if (node.type === 'JSXText') {
+ const value: string = getSanitizedNodeValue('JSXText', 'value', node.value)
+
+ return value.length > 0
+ }
+
+ return true
+}
+
+const compareNodesBeforeWildcardsComparison = (
+ ...nodeComparatorParams: NodesComparatorParameters
+) => {
+ return runNodesComparators(beforeWildcardsComparators, nodeComparatorParams)
+}
+
+const compareNodesAfterWildcardsComparison = (
+ ...nodeComparatorParams: NodesComparatorParameters
+) => {
+ return runNodesComparators(afterWildcardsComparators, nodeComparatorParams)
+}
+
+const isIdentifierNode = (node: PoorNodeType) =>
+ identifierNodeTypes.includes(getNodeType(node))
+
+const isFirstCharStringStart = (str: string) =>
+ str.charAt(0) === `'` || str.charAt(0) === `"`
+
+const stringLikeLiteralUtils: StringLikeLiteralUtils = {
+ isStringLikeLiteralNode: (node: PoorNodeType) =>
+ (node.type === 'Literal' && isFirstCharStringStart(node.raw as string)) ||
+ node.type === 'TemplateElement' ||
+ node.type === 'JSXText',
+ getStringLikeLiteralValue: (node: PoorNodeType) => {
+ if (node.type === 'TemplateElement') {
+ const { raw } = sanitizeTemplateElementValue(
+ node.value as { raw: string; cooked: string },
+ )
+
+ return raw
+ }
+
+ // (node.type === 'Literal' || node.type === 'JSXText'
+ return normalizeText(node.value as string)
+ },
+}
+
+const numericLiteralUtils: NumericLiteralUtils = {
+ isNumericLiteralNode: (node: PoorNodeType) =>
+ node.type === 'Literal' && !isFirstCharStringStart(node.raw as string),
+ getNumericLiteralValue: (node: PoorNodeType) => node.raw as string,
+}
+
+const programNodeAndBlockNodeUtils: ProgramNodeAndBlockNodeUtils = {
+ isProgramNode: (node: PoorNodeType) => node.type === 'Program',
+ isBlockNode: (node: PoorNodeType) => node.type === 'BlockStatement',
+ programNodeBodyKey: 'body',
+ blockNodeBodyKey: 'body',
+}
+
+const getNodePosition: ParserSettings['getNodePosition'] = (
+ node: PoorNodeType,
+) => ({
+ start: (node.range as any)[0] as number,
+ end: (node.range as any)[1] as number,
+ loc: node.loc as unknown as Location,
+})
+
+const getParseErrorLocation = (e: any) => ({
+ line: e.lineNumber ?? 0,
+ column: e.column ?? 0,
+})
+
+const alternativeNodeTypes = {
+ Identifier: identifierNodeTypes,
+ ChainExpression: ['MemberExpression'],
+ MemberExpression: ['ChainExpression'],
+ BlockStatement: ['Program'],
+}
+
+export const esprimaParserSettings: ParserSettings = {
+ supportedExtensions,
+ parseCode,
+ isNode,
+ isIdentifierNode,
+ identifierNodeTypes,
+ astPropsToSkip,
+ getProgramBodyFromRootNode,
+ getProgramNodeFromRootNode,
+ getIdentifierNodeName,
+ setIdentifierNodeName,
+ getNodeType,
+ unwrapExpressionStatement,
+ createBlockStatementNode,
+ getSanitizedNodeValue,
+ shouldCompareNode,
+ wildcardUtils,
+ compareNodesBeforeWildcardsComparison,
+ compareNodesAfterWildcardsComparison,
+ identifierTypeAnnotationFieldName: 'typeAnnotation',
+ stringLikeLiteralUtils,
+ numericLiteralUtils,
+ programNodeAndBlockNodeUtils,
+ getNodePosition,
+ getParseErrorLocation,
+ alternativeNodeTypes,
+}
+
export default esprimaParserSettings
diff --git a/packages/core/src/parserSettings/index.ts b/packages/core/src/parserSettings/index.ts
index d07c2ef..3cf8479 100644
--- a/packages/core/src/parserSettings/index.ts
+++ b/packages/core/src/parserSettings/index.ts
@@ -6,6 +6,15 @@ const resolveParserSettings = (parser: string) => () => {
export const parserSettingsMap: Record ParserSettings> = {
babel: resolveParserSettings('babelParser'),
- 'typescript-eslint': resolveParserSettings('typescriptEslintParser'),
+ 'typescript-eslint-parser': resolveParserSettings('typescriptEslintParser'),
+ espree: resolveParserSettings('espreeParser'),
esprima: resolveParserSettings('esprimaParser'),
+ 'babel-eslint-parser': resolveParserSettings('babelEslintParser'),
+ ['angular-eslint-template-parser']: resolveParserSettings(
+ 'angularEslintTemplateParser',
+ ),
+ ['css-tree']: resolveParserSettings('cssTree'),
+ ['python']: resolveParserSettings('python'),
+ ['lua']: resolveParserSettings('lua'),
+ ['csharp']: resolveParserSettings('csharp'),
}
diff --git a/packages/core/src/parserSettings/lua/common.ts b/packages/core/src/parserSettings/lua/common.ts
new file mode 100644
index 0000000..c045f63
--- /dev/null
+++ b/packages/core/src/parserSettings/lua/common.ts
@@ -0,0 +1,24 @@
+import { createWildcardUtils } from '../../wildcardUtilsFactory'
+import { PoorNodeType } from '../../types'
+
+export const identifierNodeTypes: string[] = ['identifier']
+
+const wildcardChar = '$'
+const numericWildcard = '0x0'
+
+export const getIdentifierNodeName = (node: PoorNodeType) =>
+ node.rawValue as string
+
+export const setIdentifierNodeName = (node: PoorNodeType, name: string) => {
+ node.rawValue = name
+}
+
+export const getNodeType = (node: PoorNodeType) => node.nodeType as string
+
+export const wildcardUtils = createWildcardUtils(
+ identifierNodeTypes,
+ numericWildcard,
+ wildcardChar,
+ getIdentifierNodeName,
+ getNodeType,
+)
diff --git a/packages/core/src/parserSettings/lua/parseCode.ts b/packages/core/src/parserSettings/lua/parseCode.ts
new file mode 100644
index 0000000..6b7b3c9
--- /dev/null
+++ b/packages/core/src/parserSettings/lua/parseCode.ts
@@ -0,0 +1,193 @@
+import { treeSitterParserModuleFactory } from '../../treeSitterUtils'
+import { PoorNodeType, Location } from '../../types'
+
+const defineRawValueForNodeTypes = ['identifier', 'number', 'string_content']
+
+const postProcessNodes = {
+ function_declaration: (node: PoorNodeType) => {
+ /**
+ * Global scope function declaration without name should be same as anonymous function definition passed as argument
+ */
+ if ((node.name as PoorNodeType)?.rawValue === '') {
+ node.nodeType = 'function_definition'
+ node.name = null
+
+ return node
+ }
+
+ return node
+ },
+ function_definition: (node: PoorNodeType) => {
+ /**
+ * Anonymous function definition should have null name field to be compared with `function_declaration` changed into `function_definition`
+ * We could use delete operator on `function_declaration`, but it's slow.
+ */
+ if (node.name === undefined) {
+ node.name = null
+ }
+
+ return node
+ },
+ binary_expression: (node: PoorNodeType, codeText: string) => {
+ const leftNodeLocationLoc = (node.left as PoorNodeType).loc as Location
+
+ const leftNodeLocationEndIndex = leftNodeLocationLoc.end.index as number
+
+ const rightNodeLocationLoc = (node.right as PoorNodeType).loc as Location
+
+ const rightNodeLocationStartIndex = rightNodeLocationLoc.start
+ .index as number
+
+ const operator = codeText.substring(
+ leftNodeLocationEndIndex,
+ rightNodeLocationStartIndex,
+ )
+
+ const operatorNode = {
+ nodeType: '__codeque__operator',
+ rawValue: operator.trim(),
+ loc: {
+ /**
+ * We could adjust location to be without spaces, but it does not matter actually
+ */
+ start: leftNodeLocationLoc.end,
+ end: rightNodeLocationLoc.start,
+ },
+ }
+
+ node.operator = operatorNode
+
+ return node
+ },
+ function_call: (node: PoorNodeType) => {
+ if ((node.name as PoorNodeType).rawValue === '') {
+ const actualContent = (
+ (node.arguments as PoorNodeType).children as PoorNodeType[]
+ )[0]
+
+ return {
+ nodeType: 'expression_list',
+ loc: node.loc,
+ children: [actualContent],
+ }
+ }
+
+ return node
+ },
+ parenthesized_expression: (node: PoorNodeType) => {
+ const children = node.children as PoorNodeType[]
+
+ // Remove empty identifiers from parenthesized_expression
+ if (
+ children.length === 1 &&
+ (children[0] as PoorNodeType)?.rawValue === ''
+ ) {
+ return { ...node, children: [] }
+ }
+
+ return node
+ },
+}
+
+export const parserModule = treeSitterParserModuleFactory({
+ treeSitterParserName: 'tree-sitter-lua',
+ postProcessNodes,
+ defineRawValueForNodeTypes,
+})
+
+const isRawString = (code: string) => {
+ const trimmedCode = code.trim()
+
+ return (
+ !trimmedCode.includes('\n') &&
+ ((trimmedCode.startsWith("'") && trimmedCode.endsWith("'")) ||
+ (trimmedCode.startsWith('"') && trimmedCode.endsWith('"')))
+ )
+}
+
+export function parseCode(code: string) {
+ const trimmedCode = code.trim()
+
+ if (isRawString(trimmedCode)) {
+ /**
+ * Just string literal query is strangely parsed, so we parse it manually
+ */
+ const loc = {
+ start: {
+ line: 1,
+ column: 0,
+ index: 0,
+ },
+ end: {
+ line: 1,
+ column: trimmedCode.length,
+ index: trimmedCode.length,
+ },
+ }
+
+ return {
+ nodeType: 'chunk',
+ loc,
+ children: [
+ {
+ nodeType: 'expression_list',
+ loc,
+ children: [
+ {
+ nodeType: 'string',
+ loc,
+ content: {
+ nodeType: 'string_content',
+ loc: {
+ start: {
+ line: 1,
+ column: loc.start.column + 1,
+ index: loc.start.index + 1,
+ },
+ end: {
+ line: 1,
+ column: loc.end.column - 1,
+ index: loc.end.index - 1,
+ },
+ },
+ children: [],
+ rawValue: trimmedCode.substring(1, trimmedCode.length - 1),
+ },
+ end: null,
+ start: null,
+ },
+ ],
+ },
+ ],
+ }
+ }
+
+ try {
+ return parserModule.parse(code)
+ } catch (originalCodeParserError) {
+ /**
+ * Lua does not support standalone expressions in the code.
+ *
+ * To workaround that, when parser error occurs, we create variable assignment to extract expression_list
+ *
+ * we throw original error if that extraction fails, because our changes might produce also broken code.
+ */
+
+ try {
+ const modifiedCode = `__codeque = ${trimmedCode}`
+
+ const modifiedCodeAst = parserModule.parse(modifiedCode)
+
+ const expression_list = (modifiedCodeAst as any)?.children?.[0]
+ ?.children?.[1] as PoorNodeType
+
+ return {
+ nodeType: 'chunk',
+ loc: expression_list.loc,
+ children: [expression_list],
+ }
+ } catch (e) {
+ throw originalCodeParserError
+ }
+ }
+}
diff --git a/packages/core/src/parserSettings/lua/settings.ts b/packages/core/src/parserSettings/lua/settings.ts
new file mode 100644
index 0000000..02a349c
--- /dev/null
+++ b/packages/core/src/parserSettings/lua/settings.ts
@@ -0,0 +1,197 @@
+import { traverseAst } from '../../searchStages/traverseAndMatch'
+import {
+ Location,
+ MatchPosition,
+ NumericLiteralUtils,
+ ParserSettings,
+ PoorNodeType,
+ ProgramNodeAndBlockNodeUtils,
+ StringLikeLiteralUtils,
+} from '../../types'
+
+import {
+ getIdentifierNodeName,
+ getNodeType,
+ identifierNodeTypes,
+ setIdentifierNodeName,
+ wildcardUtils,
+} from './common'
+import { parseCode, parserModule } from './parseCode'
+
+const supportedExtensions = ['lua']
+
+const getProgramNodeFromRootNode = (rootNode: PoorNodeType) => rootNode // root node is program node
+
+const getProgramBodyFromRootNode = (fileNode: PoorNodeType) => {
+ return fileNode.children as PoorNodeType[]
+}
+
+/**
+ *
+ * Lua has expression list, so there can be a tuple
+ * For single expression return it, for multiple expressions, return expression_list node, so the original node
+ */
+
+const unwrapExpressionStatement = (node: PoorNodeType) => {
+ if (node.nodeType === 'expression_list' && node.children) {
+ const children = node.children as PoorNodeType[]
+
+ if (children.length === 1) {
+ return children[0]
+ }
+ }
+
+ return node
+}
+
+const createBlockStatementNode = (
+ children: PoorNodeType[],
+ position: MatchPosition,
+) => ({
+ nodeType: 'block',
+ children,
+ ...position,
+})
+
+const isNode = (maybeNode: PoorNodeType) => {
+ return typeof maybeNode?.nodeType === 'string'
+}
+
+/* start and end is added by CQ in multiline queries */
+const astPropsToSkip = ['loc', 'start', 'end']
+
+type NodeValueSanitizers = Record any>>
+
+const nodeValuesSanitizers: NodeValueSanitizers = {}
+
+const getSanitizedNodeValue = (
+ nodeType: string,
+ valueKey: string,
+ value: unknown,
+) => {
+ const valueSanitizer = nodeValuesSanitizers?.[nodeType]?.[valueKey]
+
+ if (valueSanitizer) {
+ return valueSanitizer(value)
+ }
+
+ return value
+}
+
+const shouldCompareNode = (node: PoorNodeType) => {
+ return true
+}
+
+const isIdentifierNode = (node: PoorNodeType) =>
+ identifierNodeTypes.includes(getNodeType(node))
+
+const stringLikeLiteralUtils: StringLikeLiteralUtils = {
+ isStringLikeLiteralNode: (node: PoorNodeType) =>
+ node.nodeType === 'string_content',
+ getStringLikeLiteralValue: (node: PoorNodeType) => {
+ return node?.rawValue as string
+ },
+}
+
+const numericLiteralUtils: NumericLiteralUtils = {
+ isNumericLiteralNode: (node: PoorNodeType) => node.nodeType === 'number',
+ getNumericLiteralValue: (node: PoorNodeType) => node?.rawValue as string,
+}
+
+const programNodeAndBlockNodeUtils: ProgramNodeAndBlockNodeUtils = {
+ isProgramNode: (node: PoorNodeType) => node.nodeType === 'chunk',
+ isBlockNode: (node: PoorNodeType) => node.nodeType === 'block',
+ programNodeBodyKey: 'children',
+ blockNodeBodyKey: 'children',
+}
+
+const getNodePosition: ParserSettings['getNodePosition'] = (
+ node: PoorNodeType,
+) => ({
+ start: ((node?.loc as any)?.start?.index as number) ?? 0,
+ end: ((node?.loc as any)?.end?.index as number) ?? 0,
+ loc: node.loc as unknown as Location,
+})
+
+const getParseErrorLocation = (e: any) => ({
+ line: e.loc?.start?.line ?? 0,
+ column: e.loc?.start?.column ?? 0,
+})
+
+const alternativeNodeTypes = {
+ identifier: identifierNodeTypes,
+}
+
+const encodedIdentifierWildcardSequence = 'a_x_2_x_a'
+const encodedNodeWildcardSequence = 'a_x_3_x_a'
+
+const preprocessQueryCode = (code: string) => {
+ const queryCode = code
+ .replace(/(\$\$\$)/g, () => encodedNodeWildcardSequence)
+ .replace(/(\$\$)/g, () => encodedIdentifierWildcardSequence)
+
+ return queryCode
+}
+
+const replaceEncodedWildcards = (value: string) =>
+ value.replace(/a_x_3_x_a/g, () => '$$$').replace(/a_x_2_x_a/g, () => '$$')
+
+const postprocessQueryNode = (queryNode: PoorNodeType) => {
+ traverseAst(queryNode, isNode, getNodeType, {
+ identifier: (node) => {
+ const nodeName = node.rawValue as string
+
+ if (
+ nodeName.includes(encodedNodeWildcardSequence) ||
+ nodeName.includes(encodedIdentifierWildcardSequence)
+ ) {
+ node.rawValue = replaceEncodedWildcards(nodeName)
+ }
+ },
+ string_content: (node) => {
+ const nodeName = node.rawValue as string
+
+ if (
+ nodeName.includes(encodedNodeWildcardSequence) ||
+ nodeName.includes(encodedIdentifierWildcardSequence)
+ ) {
+ node.rawValue = replaceEncodedWildcards(nodeName)
+ }
+ },
+ })
+
+ return queryNode
+}
+
+export const pythonParser: ParserSettings = {
+ supportedExtensions,
+ parseCode,
+ isNode,
+ isIdentifierNode,
+ astPropsToSkip,
+ getProgramBodyFromRootNode,
+ getProgramNodeFromRootNode,
+ getIdentifierNodeName,
+ getNodeType,
+ unwrapExpressionStatement,
+ createBlockStatementNode,
+ getSanitizedNodeValue,
+ identifierNodeTypes,
+ setIdentifierNodeName,
+ shouldCompareNode,
+ wildcardUtils,
+ compareNodesBeforeWildcardsComparison: () => undefined,
+ compareNodesAfterWildcardsComparison: () => undefined,
+ identifierTypeAnnotationFieldName: '',
+ stringLikeLiteralUtils,
+ numericLiteralUtils,
+ programNodeAndBlockNodeUtils,
+ getNodePosition,
+ getParseErrorLocation,
+ alternativeNodeTypes,
+ preprocessQueryCode,
+ postprocessQueryNode,
+ init: parserModule.init,
+}
+
+export default pythonParser
diff --git a/packages/core/src/parserSettings/nodeComparatorFactories/JavaScriptSpecific/matchOptionalFlagInMemberExpression.ts b/packages/core/src/parserSettings/nodeComparatorFactories/JavaScriptSpecific/matchOptionalFlagInMemberExpression.ts
index 29e4a5f..189a8b6 100644
--- a/packages/core/src/parserSettings/nodeComparatorFactories/JavaScriptSpecific/matchOptionalFlagInMemberExpression.ts
+++ b/packages/core/src/parserSettings/nodeComparatorFactories/JavaScriptSpecific/matchOptionalFlagInMemberExpression.ts
@@ -16,7 +16,7 @@ import { NodesComparator, PoorNodeType } from '../../../types'
export const createMatchOptionalFlagInMemberExpressionNodesComparator =
(): NodesComparator =>
(
- { queryNode, fileNode, searchSettings },
+ { queryNode, fileNode, searchSettings, matchContext },
compareNodes,
{ fileKeysToTraverseForOtherMatches, queryKeysMapper, fileKeysMapper },
) => {
@@ -56,6 +56,7 @@ export const createMatchOptionalFlagInMemberExpressionNodesComparator =
searchSettings,
queryKeysPrefix: queryKeysMapper(''),
fileKeysPrefix: fileKeysMapper('expression'),
+ matchContext,
})
} else if (
queryNode.type === 'ChainExpression' &&
@@ -67,6 +68,7 @@ export const createMatchOptionalFlagInMemberExpressionNodesComparator =
searchSettings,
queryKeysPrefix: queryKeysMapper('expression'),
fileKeysPrefix: fileKeysMapper(''),
+ matchContext,
})
}
}
diff --git a/packages/core/src/parserSettings/nodeComparatorFactories/JavaScriptSpecific/wildcardForAssignmentPatternOrDefaultParamValues.ts b/packages/core/src/parserSettings/nodeComparatorFactories/JavaScriptSpecific/wildcardForAssignmentPatternOrDefaultParamValues.ts
index 901e038..fafc2b0 100644
--- a/packages/core/src/parserSettings/nodeComparatorFactories/JavaScriptSpecific/wildcardForAssignmentPatternOrDefaultParamValues.ts
+++ b/packages/core/src/parserSettings/nodeComparatorFactories/JavaScriptSpecific/wildcardForAssignmentPatternOrDefaultParamValues.ts
@@ -13,7 +13,7 @@ export const createWildcardForAssignmentPatternOrDefaultParamValuesNodesComparat
(): NodesComparator =>
(
- { fileNode, queryNode, searchSettings },
+ { fileNode, queryNode, searchSettings, matchContext },
compareNodes,
{ queryKeysMapper, fileKeysMapper },
) => {
@@ -36,6 +36,7 @@ export const createWildcardForAssignmentPatternOrDefaultParamValuesNodesComparat
searchSettings,
queryKeysPrefix: queryKeysMapper(''),
fileKeysPrefix: fileKeysMapper('left'),
+ matchContext,
})
}
}
diff --git a/packages/core/src/parserSettings/nodeComparatorFactories/JsxSpecific/matchJsxElementRegardlessClosingTag.ts b/packages/core/src/parserSettings/nodeComparatorFactories/JsxSpecific/matchJsxElementRegardlessClosingTag.ts
index 6feba32..282ac9b 100644
--- a/packages/core/src/parserSettings/nodeComparatorFactories/JsxSpecific/matchJsxElementRegardlessClosingTag.ts
+++ b/packages/core/src/parserSettings/nodeComparatorFactories/JsxSpecific/matchJsxElementRegardlessClosingTag.ts
@@ -27,6 +27,8 @@ export const createMatchJsxElementRegardlessClosingTagNodesComparator =
(queryNode.children as []).length === 0
) {
measureCompare()
+
+ // To skip matching closing element
const keysToTraverse = ['openingElement']
return {
diff --git a/packages/core/src/parserSettings/nodeComparatorFactories/Other/matchWildcardsInPropValueNodes.ts b/packages/core/src/parserSettings/nodeComparatorFactories/Other/matchWildcardsInPropValueNodes.ts
new file mode 100644
index 0000000..9a23dc9
--- /dev/null
+++ b/packages/core/src/parserSettings/nodeComparatorFactories/Other/matchWildcardsInPropValueNodes.ts
@@ -0,0 +1,68 @@
+import { NodesComparator } from '../../../types'
+import { matchStringOrIdentifierAliases } from '../../../searchStages/matchStringOrIdentifierAliases'
+
+type Settings = {
+ nodeType: string
+ keysWithWildcards: string[]
+ keysToTraverse: string[]
+}
+/*
+ * Supports matching string or identifier wildcards in nodes that contains prop and value in the same node.
+ * eg. TextAttribute in HTML which is { prop: 'propName', value: 'value', ...otherKeys }
+ */
+export const createMatchWildcardsInPropValueNodesComparator =
+ ({
+ nodeType,
+ keysWithWildcards,
+ keysToTraverse,
+ }: Settings): NodesComparator =>
+ (
+ { queryNode, fileNode, searchSettings, matchContext },
+ _,
+ { fileKeysToTraverseForOtherMatches, log },
+ ) => {
+ if (queryNode?.type === nodeType && fileNode?.type === nodeType) {
+ log('Compare PropValue Node', nodeType)
+ const { wildcardUtils } = searchSettings.parserSettings
+ const { caseInsensitive } = searchSettings
+
+ let levelMatch = true
+
+ keysWithWildcards.forEach((key) => {
+ const queryNodeStringContent = queryNode[key] as string
+
+ const fileNodeStringContent = fileNode[key] as string
+
+ const wildcardsMeta = wildcardUtils.getStringWildcardsFromString(
+ queryNodeStringContent,
+ )
+
+ if (wildcardsMeta.length > 0) {
+ levelMatch =
+ levelMatch &&
+ matchStringOrIdentifierAliases({
+ queryValue: queryNodeStringContent,
+ fileValue: fileNodeStringContent,
+ wildcardsMeta,
+ matchContext,
+ wildcardUtils,
+ caseInsensitive,
+ })
+ } else {
+ /**
+ * If there are no wildcards in given prop, compare prop values directly
+ */
+ levelMatch =
+ levelMatch && queryNodeStringContent === fileNodeStringContent
+ }
+ })
+
+ // We always want to return here, otherwise generic string wildcard matching would take over and match incorrectly
+ return {
+ levelMatch,
+ queryKeysToTraverseForValidatingMatch: keysToTraverse,
+ fileKeysToTraverseForValidatingMatch: keysToTraverse,
+ fileKeysToTraverseForOtherMatches,
+ }
+ }
+ }
diff --git a/packages/core/src/parserSettings/nodeComparatorFactories/TypeScriptSpecific/wildcardForAnyTypeAnnotation.ts b/packages/core/src/parserSettings/nodeComparatorFactories/TypeScriptSpecific/wildcardForAnyTypeAnnotation.ts
index 672d7dd..27d30e8 100644
--- a/packages/core/src/parserSettings/nodeComparatorFactories/TypeScriptSpecific/wildcardForAnyTypeAnnotation.ts
+++ b/packages/core/src/parserSettings/nodeComparatorFactories/TypeScriptSpecific/wildcardForAnyTypeAnnotation.ts
@@ -11,7 +11,7 @@ export const createWildcardForAnyTypeAnnotationNodesComparator =
if (queryNode) {
if (
(queryNode.type as string) === 'TSTypeReference' &&
- wildcardUtils.removeIdentifierRefFromWildcard(
+ wildcardUtils.removeWildcardAliasesFromIdentifierName(
(queryNode.typeName as PoorNodeType).name as string,
) === wildcardUtils.nodesTreeWildcard
) {
diff --git a/packages/core/src/parserSettings/python/common.ts b/packages/core/src/parserSettings/python/common.ts
new file mode 100644
index 0000000..c045f63
--- /dev/null
+++ b/packages/core/src/parserSettings/python/common.ts
@@ -0,0 +1,24 @@
+import { createWildcardUtils } from '../../wildcardUtilsFactory'
+import { PoorNodeType } from '../../types'
+
+export const identifierNodeTypes: string[] = ['identifier']
+
+const wildcardChar = '$'
+const numericWildcard = '0x0'
+
+export const getIdentifierNodeName = (node: PoorNodeType) =>
+ node.rawValue as string
+
+export const setIdentifierNodeName = (node: PoorNodeType, name: string) => {
+ node.rawValue = name
+}
+
+export const getNodeType = (node: PoorNodeType) => node.nodeType as string
+
+export const wildcardUtils = createWildcardUtils(
+ identifierNodeTypes,
+ numericWildcard,
+ wildcardChar,
+ getIdentifierNodeName,
+ getNodeType,
+)
diff --git a/packages/core/src/parserSettings/python/parseCode.ts b/packages/core/src/parserSettings/python/parseCode.ts
new file mode 100644
index 0000000..3c398b3
--- /dev/null
+++ b/packages/core/src/parserSettings/python/parseCode.ts
@@ -0,0 +1,17 @@
+import { treeSitterParserModuleFactory } from '../../treeSitterUtils'
+
+const defineRawValueForNodeTypes = [
+ 'identifier',
+ 'integer',
+ 'string_content',
+ 'float',
+]
+
+export const parserModule = treeSitterParserModuleFactory({
+ treeSitterParserName: 'tree-sitter-python',
+ defineRawValueForNodeTypes,
+})
+
+export function parseCode(code: string) {
+ return parserModule.parse(code)
+}
diff --git a/packages/core/src/parserSettings/python/settings.ts b/packages/core/src/parserSettings/python/settings.ts
new file mode 100644
index 0000000..e2fd6cc
--- /dev/null
+++ b/packages/core/src/parserSettings/python/settings.ts
@@ -0,0 +1,186 @@
+import { traverseAst } from '../../searchStages/traverseAndMatch'
+import {
+ Location,
+ MatchPosition,
+ NumericLiteralUtils,
+ ParserSettings,
+ PoorNodeType,
+ ProgramNodeAndBlockNodeUtils,
+ StringLikeLiteralUtils,
+} from '../../types'
+
+import {
+ getIdentifierNodeName,
+ getNodeType,
+ identifierNodeTypes,
+ setIdentifierNodeName,
+ wildcardUtils,
+} from './common'
+import { parseCode, parserModule } from './parseCode'
+
+const supportedExtensions = ['py']
+
+const getProgramNodeFromRootNode = (rootNode: PoorNodeType) => rootNode // root node is program node
+
+const getProgramBodyFromRootNode = (fileNode: PoorNodeType) => {
+ return fileNode.children as PoorNodeType[]
+}
+
+const unwrapExpressionStatement = (node: PoorNodeType) => {
+ return node.nodeType === 'expression_statement' && node.children
+ ? ((node.children as PoorNodeType[])[0] as PoorNodeType)
+ : node
+}
+
+const createBlockStatementNode = (
+ children: PoorNodeType[],
+ position: MatchPosition,
+) => ({
+ nodeType: 'block',
+ children,
+ ...position,
+})
+
+const isNode = (maybeNode: PoorNodeType) => {
+ return typeof maybeNode?.nodeType === 'string'
+}
+
+/* start and end is added by CQ in multiline queries */
+const astPropsToSkip = ['loc', 'start', 'end']
+
+type NodeValueSanitizers = Record any>>
+
+const nodeValuesSanitizers: NodeValueSanitizers = {}
+
+const getSanitizedNodeValue = (
+ nodeType: string,
+ valueKey: string,
+ value: unknown,
+) => {
+ const valueSanitizer = nodeValuesSanitizers?.[nodeType]?.[valueKey]
+
+ if (valueSanitizer) {
+ return valueSanitizer(value)
+ }
+
+ return value
+}
+
+const shouldCompareNode = (node: PoorNodeType) => {
+ return true
+}
+
+const isIdentifierNode = (node: PoorNodeType) =>
+ identifierNodeTypes.includes(getNodeType(node))
+
+const stringLikeLiteralUtils: StringLikeLiteralUtils = {
+ isStringLikeLiteralNode: (node: PoorNodeType) =>
+ node.nodeType === 'string_content',
+ getStringLikeLiteralValue: (node: PoorNodeType) => {
+ return node?.rawValue as string
+ },
+}
+
+const numericLiteralUtils: NumericLiteralUtils = {
+ isNumericLiteralNode: (node: PoorNodeType) =>
+ node.nodeType === 'integer' || node.nodeType === 'float',
+ getNumericLiteralValue: (node: PoorNodeType) => node?.rawValue as string,
+}
+
+const programNodeAndBlockNodeUtils: ProgramNodeAndBlockNodeUtils = {
+ isProgramNode: (node: PoorNodeType) => node.nodeType === 'module',
+ isBlockNode: (node: PoorNodeType) => node.nodeType === 'block',
+ programNodeBodyKey: 'children',
+ blockNodeBodyKey: 'children',
+}
+
+const getNodePosition: ParserSettings['getNodePosition'] = (
+ node: PoorNodeType,
+) => ({
+ start: ((node?.loc as any)?.start?.index as number) ?? 0,
+ end: ((node?.loc as any)?.end?.index as number) ?? 0,
+ loc: node.loc as unknown as Location,
+})
+
+const getParseErrorLocation = (e: any) => ({
+ line: e.loc?.start?.line ?? 0,
+ column: e.loc?.start?.column ?? 0,
+})
+
+const alternativeNodeTypes = {
+ identifier: identifierNodeTypes,
+}
+
+const encodedIdentifierWildcardSequence = 'a_x_2_x_a'
+const encodedNodeWildcardSequence = 'a_x_3_x_a'
+
+const preprocessQueryCode = (code: string) => {
+ const queryCode = code
+ .replace(/(\$\$\$)/g, () => encodedNodeWildcardSequence)
+ .replace(/(\$\$)/g, () => encodedIdentifierWildcardSequence)
+
+ return queryCode
+}
+
+const replaceEncodedWildcards = (value: string) =>
+ value.replace(/a_x_3_x_a/g, () => '$$$').replace(/a_x_2_x_a/g, () => '$$')
+
+const postprocessQueryNode = (queryNode: PoorNodeType) => {
+ traverseAst(queryNode, isNode, getNodeType, {
+ identifier: (node) => {
+ const nodeName = node.rawValue as string
+
+ if (
+ nodeName.includes(encodedNodeWildcardSequence) ||
+ nodeName.includes(encodedIdentifierWildcardSequence)
+ ) {
+ node.rawValue = replaceEncodedWildcards(nodeName)
+ }
+ },
+ string_content: (node) => {
+ const nodeName = node.rawValue as string
+
+ if (
+ nodeName.includes(encodedNodeWildcardSequence) ||
+ nodeName.includes(encodedIdentifierWildcardSequence)
+ ) {
+ node.rawValue = replaceEncodedWildcards(nodeName)
+ }
+ },
+ })
+
+ return queryNode
+}
+
+export const pythonParser: ParserSettings = {
+ supportedExtensions,
+ parseCode,
+ isNode,
+ isIdentifierNode,
+ astPropsToSkip,
+ getProgramBodyFromRootNode,
+ getProgramNodeFromRootNode,
+ getIdentifierNodeName,
+ getNodeType,
+ unwrapExpressionStatement,
+ createBlockStatementNode,
+ getSanitizedNodeValue,
+ identifierNodeTypes,
+ setIdentifierNodeName,
+ shouldCompareNode,
+ wildcardUtils,
+ compareNodesBeforeWildcardsComparison: () => undefined,
+ compareNodesAfterWildcardsComparison: () => undefined,
+ identifierTypeAnnotationFieldName: '',
+ stringLikeLiteralUtils,
+ numericLiteralUtils,
+ programNodeAndBlockNodeUtils,
+ getNodePosition,
+ getParseErrorLocation,
+ alternativeNodeTypes,
+ preprocessQueryCode,
+ postprocessQueryNode,
+ init: parserModule.init,
+}
+
+export default pythonParser
diff --git a/packages/core/src/parserSettings/typescriptEslintParser/common.ts b/packages/core/src/parserSettings/typescriptEslintParser/common.ts
index de4f612..f9ac9bc 100644
--- a/packages/core/src/parserSettings/typescriptEslintParser/common.ts
+++ b/packages/core/src/parserSettings/typescriptEslintParser/common.ts
@@ -1,9 +1,18 @@
import { numericWildcard, wildcardChar } from '../_common/JSFamilyCommon'
import { createWildcardUtils } from '../../wildcardUtilsFactory'
+import { PoorNodeType } from '../../types'
export const identifierNodeTypes = ['Identifier', 'JSXIdentifier']
+export const getIdentifierNodeName = (node: PoorNodeType) => node.name as string
+export const setIdentifierNodeName = (node: PoorNodeType, name: string) => {
+ node.name = name
+}
+
+export const getNodeType = (node: PoorNodeType) => node.type as string
export const wildcardUtils = createWildcardUtils(
identifierNodeTypes,
numericWildcard,
wildcardChar,
+ getIdentifierNodeName,
+ getNodeType,
)
diff --git a/packages/core/src/parserSettings/typescriptEslintParser/nodeComparators/wildcardForAnyTypeParameter.ts b/packages/core/src/parserSettings/typescriptEslintParser/nodeComparators/wildcardForAnyTypeParameter.ts
index 53e82ef..1ed2a24 100644
--- a/packages/core/src/parserSettings/typescriptEslintParser/nodeComparators/wildcardForAnyTypeParameter.ts
+++ b/packages/core/src/parserSettings/typescriptEslintParser/nodeComparators/wildcardForAnyTypeParameter.ts
@@ -8,7 +8,7 @@ export const wildcardForAnyTypeParameter: NodesComparator = (
if (queryNode) {
if (
(queryNode.type as string) === 'TSTypeParameter' &&
- wildcardUtils.removeIdentifierRefFromWildcard(
+ wildcardUtils.removeWildcardAliasesFromIdentifierName(
(queryNode.name as PoorNodeType).name as string,
) === wildcardUtils.nodesTreeWildcard
) {
diff --git a/packages/core/src/parserSettings/typescriptEslintParser/settings.ts b/packages/core/src/parserSettings/typescriptEslintParser/settings.ts
index 2e637c5..0f6b7ae 100644
--- a/packages/core/src/parserSettings/typescriptEslintParser/settings.ts
+++ b/packages/core/src/parserSettings/typescriptEslintParser/settings.ts
@@ -1,19 +1,25 @@
import { parse, ParserOptions } from '@typescript-eslint/parser'
import {
Location,
- Match,
NodesComparatorParameters,
NumericLiteralUtils,
ParserSettings,
PoorNodeType,
ProgramNodeAndBlockNodeUtils,
StringLikeLiteralUtils,
+ MatchPosition,
} from '../../types'
import { normalizeText, runNodesComparators } from '../../utils'
import { supportedExtensions } from '../_common/JSFamilyCommon'
import { afterWildcardsComparators } from './afterWildcardsComparators'
import { beforeWildcardsComparators } from './beforeWildcardsComparators'
-import { identifierNodeTypes, wildcardUtils } from './common'
+import {
+ getIdentifierNodeName,
+ getNodeType,
+ identifierNodeTypes,
+ wildcardUtils,
+ setIdentifierNodeName,
+} from './common'
const getProgramNodeFromRootNode = (rootNode: PoorNodeType) => rootNode // root node is program node
@@ -35,7 +41,7 @@ const unwrapExpressionStatement = (node: PoorNodeType) => {
const createBlockStatementNode = (
body: PoorNodeType[],
- position: Omit,
+ position: MatchPosition,
) =>
({
type: 'BlockStatement',
@@ -48,11 +54,6 @@ const isNode = (maybeNode: PoorNodeType) => {
return typeof maybeNode?.type === 'string'
}
-const isNodeFieldOptional = (nodeType: string, nodeFieldKey: string) => {
- // Eslint-typescript is about to remove optionality of properties https://github.com/typescript-eslint/typescript-eslint/pull/6274
- return true
-}
-
const astPropsToSkip = [
'loc',
'range',
@@ -83,37 +84,50 @@ const parseCode = (code: string, filePath = '') => {
return parse(maybeWrappedJSON, parseOptions) as unknown as PoorNodeType
}
-const generateCode = (node: PoorNodeType, options?: unknown) => {
- return 'Not supported'
+const sanitizeTemplateElementValue = ({
+ raw,
+ cooked,
+}: {
+ raw: string
+ cooked: string
+}) => {
+ return {
+ raw: normalizeText(raw),
+ cooked: normalizeText(cooked),
+ }
}
-const sanitizeJSXText = (node: PoorNodeType) => {
- //@ts-ignore
- node.value = normalizeText(node.value)
- //@ts-ignore
- node.raw = normalizeText(node.raw)
-}
+type NodeValueSanitizers = Record any>>
-const sanitizeTemplateElement = (node: PoorNodeType) => {
- //@ts-ignore
- node.value.raw = normalizeText(node.value.raw)
- //@ts-ignore
- node.value.cooked = normalizeText(node.value.cooked)
+const nodeValuesSanitizers: NodeValueSanitizers = {
+ ['JSXText']: {
+ value: normalizeText,
+ raw: normalizeText,
+ },
+ ['TemplateElement']: {
+ value: sanitizeTemplateElementValue,
+ },
}
-const sanitizeNode = (node: PoorNodeType) => {
- if (node?.type === 'TemplateElement') {
- sanitizeTemplateElement(node)
- } else if (node?.type === 'JSXText') {
- sanitizeJSXText(node)
+const getSanitizedNodeValue = (
+ nodeType: string,
+ valueKey: string,
+ value: unknown,
+) => {
+ const valueSanitizer = nodeValuesSanitizers?.[nodeType]?.[valueKey]
+
+ if (valueSanitizer) {
+ return valueSanitizer(value)
}
+
+ return value
}
const shouldCompareNode = (node: PoorNodeType) => {
if (node.type === 'JSXText') {
- sanitizeJSXText(node)
+ const value: string = getSanitizedNodeValue('JSXText', 'value', node.value)
- return (node.value as string).length > 0
+ return value.length > 0
}
return true
@@ -131,9 +145,6 @@ const compareNodesAfterWildcardsComparison = (
return runNodesComparators(afterWildcardsComparators, nodeComparatorParams)
}
-const getIdentifierNodeName = (node: PoorNodeType) => node.name as string
-const getNodeType = (node: PoorNodeType) => node.type as string
-
const isIdentifierNode = (node: PoorNodeType) =>
identifierNodeTypes.includes(getNodeType(node))
@@ -146,7 +157,16 @@ const stringLikeLiteralUtils: StringLikeLiteralUtils = {
node.type === 'TemplateElement' ||
node.type === 'JSXText',
getStringLikeLiteralValue: (node: PoorNodeType) => {
- return ((node.value as any)?.raw as string) ?? (node?.value as string)
+ if (node.type === 'TemplateElement') {
+ const { raw } = sanitizeTemplateElementValue(
+ node.value as { raw: string; cooked: string },
+ )
+
+ return raw
+ }
+
+ // (node.type === 'Literal' || node.type === 'JSXText'
+ return normalizeText(node.value as string)
},
}
@@ -188,15 +208,16 @@ export const typescriptEslintParserSettings: ParserSettings = {
parseCode,
isNode,
isIdentifierNode,
+ identifierNodeTypes,
astPropsToSkip,
- isNodeFieldOptional,
getProgramBodyFromRootNode,
getProgramNodeFromRootNode,
getIdentifierNodeName,
+ setIdentifierNodeName,
getNodeType,
unwrapExpressionStatement,
createBlockStatementNode,
- sanitizeNode,
+ getSanitizedNodeValue,
shouldCompareNode,
wildcardUtils,
compareNodesBeforeWildcardsComparison,
diff --git a/packages/core/src/searchInFs.ts b/packages/core/src/searchInFs.ts
index d80348c..8dff29f 100644
--- a/packages/core/src/searchInFs.ts
+++ b/packages/core/src/searchInFs.ts
@@ -9,12 +9,10 @@ import {
SearchResults,
NotNullParsedQuery,
SearchSettings,
- ParserType,
} from './types'
import { textSearch } from './textSearch'
import { parserSettingsMap } from './parserSettings/index'
-
-const testParserTypeOverride = process?.env?.TEST_PARSER_TYPE as ParserType
+import { testParserTypeOverride } from './testOnlyConfig'
export const searchInFileSystem = ({
mode,
@@ -37,7 +35,7 @@ export const searchInFileSystem = ({
getFileContent,
filePaths,
mode,
- queryCodes,
+ queryCodes: queryCodes ?? [],
caseInsensitive,
onPartialResult,
maxResultsLimit,
@@ -65,10 +63,14 @@ export const searchInFileSystem = ({
)
if (!parseOk) {
+ log('Parse query failed')
+
+ const errors = queries.filter((queryResult) => queryResult.error)
+
return {
matches: [],
hints: queries.map(({ hints }) => hints),
- errors: queries.filter((queryResult) => queryResult.error),
+ errors,
}
}
@@ -101,7 +103,7 @@ export const searchInFileSystem = ({
fileContent,
...settings,
})
- const dedupedFileMatches = dedupMatches(fileMatches, log, debug)
+ const dedupedFileMatches = dedupMatches(fileMatches)
if (onPartialResult && dedupedFileMatches.length > 0) {
onPartialResult(dedupedFileMatches)
@@ -130,7 +132,9 @@ export const searchInFileSystem = ({
}
}
- logMetrics()
+ if (debug) {
+ logMetrics()
+ }
return {
matches: allMatches,
diff --git a/packages/core/src/searchInStrings.ts b/packages/core/src/searchInStrings.ts
index 007c59f..b9371ca 100644
--- a/packages/core/src/searchInStrings.ts
+++ b/packages/core/src/searchInStrings.ts
@@ -9,11 +9,9 @@ import {
SearchResults,
NotNullParsedQuery,
SearchSettings,
- ParserType,
} from './types'
import { parserSettingsMap } from './parserSettings/index'
-
-const testParserTypeOverride = process?.env?.TEST_PARSER_TYPE as ParserType
+import { testParserTypeOverride } from './testOnlyConfig'
type StringsSearchArgs = Omit & {
files: {
@@ -66,6 +64,8 @@ export const searchInStrings = ({
)
if (!parseOk) {
+ log('Parse query failed')
+
return {
matches: [],
errors: queries.filter((queryResult) => queryResult.error),
@@ -112,7 +112,7 @@ export const searchInStrings = ({
}
return {
- matches: dedupMatches(allMatches, log, debug),
+ matches: dedupMatches(allMatches),
errors: searchErrors,
hints: queries.map(({ hints }) => hints),
}
diff --git a/packages/core/src/searchMultiThread.ts b/packages/core/src/searchMultiThread.ts
index 2f3103b..37bac5c 100644
--- a/packages/core/src/searchMultiThread.ts
+++ b/packages/core/src/searchMultiThread.ts
@@ -9,6 +9,7 @@ import {
} from './types'
import { measureStart, logMetrics } from './utils'
import { searchInFileSystem } from './searchInFs'
+import { parserSettingsMap } from './parserSettings'
const coresCount = Math.round(cpus().length / 2)
const singleThreadFilesCountLimitStructuralDefault = 350
@@ -21,6 +22,7 @@ export const searchMultiThread = async ({
maxResultsLimit,
singleThreadFilesCountLimitStructural = singleThreadFilesCountLimitStructuralDefault,
singleThreadFilesCountLimitText = singleThreadFilesCountLimitTextDefault,
+ debug,
...params
}: FileSystemSearchArgs & {
hardStopFlag?: HardStopFlag
@@ -82,13 +84,28 @@ export const searchMultiThread = async ({
/**
* Timeout to not block starting other searches
*/
- setTimeout(() => {
- const results = searchInFileSystem({
- ...searchParams,
- onPartialResult,
- hardStopFlag,
- })
- resolve(results)
+ setTimeout(async () => {
+ try {
+ if (params.parser) {
+ await parserSettingsMap[params.parser]().init?.(
+ params.parserFilesBasePath,
+ )
+ }
+
+ const results = searchInFileSystem({
+ ...searchParams,
+ onPartialResult,
+ hardStopFlag,
+ })
+ resolve(results)
+ } catch (e) {
+ const error = new Error(
+ 'Search on main thread failed with error ' + (e as Error).message,
+ )
+ error.stack = (e as Error)?.stack
+
+ reject(error)
+ }
}, 0)
} else {
const measureWorkerReturnResult = measureStart('WorkerReturnResult')
@@ -147,7 +164,9 @@ export const searchMultiThread = async ({
},
)
- logMetrics()
+ if (debug) {
+ logMetrics()
+ }
return mergedResults
}
diff --git a/packages/core/src/searchStages/compareNodes.ts b/packages/core/src/searchStages/compareNodes.ts
index 574107c..0db7618 100644
--- a/packages/core/src/searchStages/compareNodes.ts
+++ b/packages/core/src/searchStages/compareNodes.ts
@@ -1,14 +1,16 @@
import {
+ compareAst,
getKeysWithNodes,
getSetsOfKeysToCompare,
isNodeArray,
} from '../astUtils'
import {
- PoorNodeType,
CompareNodesParams,
CompareNodesReturnType,
+ PoorNodeType,
} from '../types'
import { measureStart, regExpTest } from '../utils'
+import { matchStringOrIdentifierAliases } from './matchStringOrIdentifierAliases'
const keyWithPrefix = (prefix: string) => (key: string) =>
prefix ? `${prefix}.${key}` : key
@@ -20,6 +22,7 @@ export const compareNodes = (
fileNode,
queryNode,
searchSettings,
+ matchContext,
/** Params used to support comparing nodes which are not on the same level */
queryKeysPrefix = '',
fileKeysPrefix = '',
@@ -30,8 +33,11 @@ export const compareNodes = (
caseInsensitive,
logger: { log, logStepEnd, logStepStart },
parserSettings,
+ getCodeForNode = () => 'getCodeForNode not provided',
} = searchSettings
+ const { getNodeType } = parserSettings
+
const queryKeysMapper = keyWithPrefix(queryKeysPrefix)
const fileKeysMapper = keyWithPrefix(fileKeysPrefix)
@@ -59,14 +65,14 @@ export const compareNodes = (
queryNode,
isExact,
parserSettings.astPropsToSkip,
- parserSettings.isNodeFieldOptional,
+ parserSettings.getNodeType,
)
log(
'compare: query node type',
- queryNode.type,
+ getNodeType(queryNode),
'file node type',
- fileNode.type,
+ getNodeType(fileNode),
)
log('compare: queryKeys', queryKeys)
@@ -88,11 +94,9 @@ export const compareNodes = (
fileKeysMapper,
fileKeysToTraverseForOtherMatches,
measureCompare,
+ log,
}
- parserSettings.sanitizeNode(fileNode)
- parserSettings.sanitizeNode(queryNode)
-
const maybeCompareResult =
parserSettings.compareNodesBeforeWildcardsComparison(
compareParams,
@@ -113,9 +117,9 @@ export const compareNodes = (
programNodeAndBlockNodeUtils,
getIdentifierNodeName,
wildcardUtils: {
- getWildcardFromNode,
+ getIdentifierWildcardsFromNode,
+ getStringWildcardsFromString,
anyStringWildcardRegExp,
- patternToRegExp,
numericWildcard,
},
} = parserSettings
@@ -129,21 +133,71 @@ export const compareNodes = (
* Support for wildcards in all nodes
*/
if (isIdentifierNode(queryNode)) {
- const wildcardMeta = getWildcardFromNode(queryNode)
+ const wildcardsMeta = getIdentifierWildcardsFromNode(queryNode)
- if (wildcardMeta !== null) {
+ if (wildcardsMeta.length > 0) {
log('comparing wildcard')
- const { wildcardType, wildcardWithoutRef } = wildcardMeta
- let levelMatch
- if (wildcardType === 'nodeTree') {
+ const firstWildcard = wildcardsMeta[0]
+
+ const isNodesTreeWildcard = firstWildcard.wildcardType === 'nodeTree'
+
+ let levelMatch: boolean
+
+ log('First Wildcard type', firstWildcard.wildcardType)
+ log('wildcardWithoutAlias', firstWildcard.wildcardWithoutAlias)
+ log('MatchContext aliases', matchContext.getAllAliases())
+
+ if (isNodesTreeWildcard) {
levelMatch = true
+
+ const { wildcardAlias, wildcardWithAlias } = firstWildcard
+
+ /**
+ * Check if alias has been already found
+ */
+ const existingAlias = wildcardAlias
+ ? matchContext.getNodesTreeAlias(wildcardAlias)
+ : null
+
+ const matchedNode = fileNode
+
+ if (existingAlias !== null) {
+ /**
+ * If alias exist, compare file nodes tree with matched alias nodes tree
+ */
+ const aliasMatches = compareAst(
+ matchedNode,
+ existingAlias.aliasNode,
+ parserSettings,
+ )
+
+ levelMatch = levelMatch && aliasMatches
+ } else if (wildcardAlias !== null) {
+ /**
+ * If alias not exist, add alias to match context
+ */
+ matchContext.addNodesTreeAlias({
+ alias: wildcardAlias,
+ wildcard: wildcardWithAlias,
+ aliasNode: matchedNode,
+ aliasValue: getCodeForNode(matchedNode, 'file'),
+ })
+ }
} else {
- const regex = patternToRegExp(wildcardWithoutRef, caseInsensitive)
+ const queryValue = getIdentifierNodeName(queryNode)
+ const fileValue = getIdentifierNodeName(fileNode)
levelMatch =
isIdentifierNode(fileNode) &&
- regExpTest(regex, getIdentifierNodeName(fileNode))
+ matchStringOrIdentifierAliases({
+ queryValue,
+ fileValue,
+ wildcardsMeta,
+ matchContext,
+ wildcardUtils: parserSettings.wildcardUtils,
+ caseInsensitive,
+ })
if (isExact && identifierTypeAnnotationFieldName) {
levelMatch =
@@ -162,8 +216,9 @@ export const compareNodes = (
)
})
- const queryKeysToTraverseForValidatingMatch =
- wildcardType !== 'nodeTree' ? queryKeysWithNodes : []
+ const queryKeysToTraverseForValidatingMatch = isNodesTreeWildcard
+ ? []
+ : queryKeysWithNodes
measureCompare()
@@ -181,7 +236,7 @@ export const compareNodes = (
const isStringWithWildcard =
stringLikeLiteralUtils.isStringLikeLiteralNode(queryNode) &&
stringLikeLiteralUtils.isStringLikeLiteralNode(fileNode) &&
- queryNode.type === fileNode.type && // todo possibility to match string literals in other places (for include mode)
+ getNodeType(queryNode) === getNodeType(fileNode) && // todo possibility to match string literals in other places (for include mode)
regExpTest(
anyStringWildcardRegExp,
stringLikeLiteralUtils.getStringLikeLiteralValue(queryNode),
@@ -196,18 +251,27 @@ export const compareNodes = (
* Q: "some$$$string"; C: "someBLABLAstring"; // required wildcard
* */
if (isStringWithWildcard) {
- const regex = patternToRegExp(
- stringLikeLiteralUtils.getStringLikeLiteralValue(queryNode),
+ const queryNodeStringContent =
+ stringLikeLiteralUtils.getStringLikeLiteralValue(queryNode)
+
+ const fileNodeStringContent =
+ stringLikeLiteralUtils.getStringLikeLiteralValue(fileNode)
+
+ const wildcardsMeta = getStringWildcardsFromString(queryNodeStringContent)
+
+ const levelMatch = matchStringOrIdentifierAliases({
+ queryValue: queryNodeStringContent,
+ fileValue: fileNodeStringContent,
+ wildcardsMeta,
+ matchContext,
+ wildcardUtils: parserSettings.wildcardUtils,
caseInsensitive,
- )
- const levelMatch = regExpTest(
- regex,
- stringLikeLiteralUtils.getStringLikeLiteralValue(fileNode),
- )
+ })
+
measureCompare()
return {
- levelMatch: levelMatch,
+ levelMatch,
fileKeysToTraverseForValidatingMatch: [],
queryKeysToTraverseForValidatingMatch: [],
fileKeysToTraverseForOtherMatches,
@@ -276,7 +340,7 @@ export const compareNodes = (
if (
queryKeys.length !== fileKeys.length ||
- fileNode.type !== queryNode.type
+ getNodeType(fileNode) !== getNodeType(queryNode)
) {
measureCompare()
@@ -305,17 +369,32 @@ export const compareNodes = (
} else {
primitivePropsCount++
+ const sanitizedQueryValue = parserSettings.getSanitizedNodeValue(
+ getNodeType(queryNode),
+ key,
+ queryValue,
+ )
+ const sanitizedFileValue = parserSettings.getSanitizedNodeValue(
+ getNodeType(fileNode),
+ key,
+ fileValue,
+ )
+
if (
- typeof queryValue === 'string' &&
- typeof fileValue === 'string' &&
+ typeof sanitizedQueryValue === 'string' &&
+ typeof sanitizedFileValue === 'string' &&
caseInsensitive
) {
- if (queryValue.toLocaleLowerCase() === fileValue.toLocaleLowerCase()) {
+ if (
+ sanitizedQueryValue.toLocaleLowerCase() ===
+ sanitizedFileValue.toLocaleLowerCase()
+ ) {
matchingPrimitivePropsCount++
}
} else if (
- queryValue === fileValue ||
- JSON.stringify(queryValue) === JSON.stringify(fileValue)
+ sanitizedQueryValue === sanitizedFileValue ||
+ JSON.stringify(sanitizedQueryValue) ===
+ JSON.stringify(sanitizedFileValue)
) {
matchingPrimitivePropsCount++
}
diff --git a/packages/core/src/searchStages/getLocationOfMultilineMatch.ts b/packages/core/src/searchStages/getLocationOfMultilineMatch.ts
index 2bdb7c3..d79d286 100644
--- a/packages/core/src/searchStages/getLocationOfMultilineMatch.ts
+++ b/packages/core/src/searchStages/getLocationOfMultilineMatch.ts
@@ -12,7 +12,11 @@ export const getLocationOfMultilineMatch = (
const statements = queryNode[blockNodeBodyKey] as PoorNodeType[]
- const alreadyPickedStatementNodes: PoorNodeType[] = []
+ /**
+ * We initialise already picked statements with the top-level match node to filter it out in results.
+ * For some parses, like angular-eslint, top-level node can be matched by query statement node.
+ */
+ const alreadyPickedStatementNodes: PoorNodeType[] = [match.node]
const subMatches = statements
.map((statement) => {
@@ -39,12 +43,16 @@ export const getLocationOfMultilineMatch = (
const firstSubMatch = subMatches[0]
const lastSubMatch = subMatches[subMatches.length - 1]
- return {
+ const resultMatch: Match = {
start: firstSubMatch.start,
end: lastSubMatch.end,
loc: {
start: firstSubMatch.loc.start,
end: lastSubMatch.loc.end,
},
- } as Match
+ aliases: match.aliases,
+ node: match.node,
+ }
+
+ return resultMatch
}
diff --git a/packages/core/src/searchStages/matchStringOrIdentifierAliases.ts b/packages/core/src/searchStages/matchStringOrIdentifierAliases.ts
new file mode 100644
index 0000000..d41f681
--- /dev/null
+++ b/packages/core/src/searchStages/matchStringOrIdentifierAliases.ts
@@ -0,0 +1,144 @@
+import { WildcardUtils, WildcardMeta } from '../types'
+import { regExpTest } from '../utils'
+import { MatchContext } from '../matchContext'
+
+export const matchStringOrIdentifierAliases = ({
+ queryValue,
+ fileValue,
+ matchContext,
+ wildcardsMeta,
+ wildcardUtils,
+ caseInsensitive,
+}: {
+ queryValue: string
+ fileValue: string
+ wildcardsMeta: WildcardMeta[]
+ matchContext: MatchContext
+ wildcardUtils: WildcardUtils
+ caseInsensitive: boolean
+}): boolean => {
+ const { patternToRegExp, removeWildcardAliasesFromIdentifierName } =
+ wildcardUtils
+
+ const identifierNameWithWildcardsWithoutAliases =
+ removeWildcardAliasesFromIdentifierName(queryValue)
+ const regex = patternToRegExp(
+ identifierNameWithWildcardsWithoutAliases,
+ caseInsensitive,
+ )
+ /**
+ * Check initial match of wildcards pattern
+ */
+
+ const wildcardMatch = regExpTest(regex, fileValue)
+
+ let levelMatch = wildcardMatch
+
+ if (wildcardMatch && wildcardsMeta.length > 0) {
+ /**
+ * If there are aliased wildcards, look for aliased values and match or assign new values
+ */
+ const queryNodeIdentifierNameWithWildcard = queryValue
+
+ const fileNodeIdentifierName = fileValue
+
+ /**
+ * Creates named capturing group for alias, where alias is group name
+ */
+ const createAliasedIdentifierWildcardRegExp = (alias: string) =>
+ `(?<${alias}>(\\w|-)*)`
+
+ const createAliasedStringWildcardRegExp = (alias: string) =>
+ `(?<${alias}>(.)*)`
+
+ const identifierWildcardRegExp = '(\\w|-)*'
+ const stringWildcardRegExp = '(.)*'
+
+ /**
+ * Compose regex that represents identifier name with aliased and non aliased wildcards
+ */
+ let wildcardValuesExtractionRegexText = queryNodeIdentifierNameWithWildcard
+
+ wildcardsMeta.forEach(
+ ({ wildcardAlias, wildcardWithAlias, wildcardType }) => {
+ let regExpPart = identifierWildcardRegExp
+
+ if (wildcardType === 'identifier' && wildcardAlias) {
+ regExpPart = createAliasedIdentifierWildcardRegExp(wildcardAlias)
+ } else if (wildcardType === 'string' && !wildcardAlias) {
+ regExpPart = stringWildcardRegExp
+ } else if (wildcardType === 'string' && wildcardAlias) {
+ regExpPart = createAliasedStringWildcardRegExp(wildcardAlias)
+ }
+
+ wildcardValuesExtractionRegexText =
+ wildcardValuesExtractionRegexText.replace(
+ wildcardWithAlias,
+ regExpPart,
+ )
+ },
+ )
+
+ const wildcardValuesExtractionRegex = new RegExp(
+ wildcardValuesExtractionRegexText,
+ caseInsensitive ? 'i' : undefined,
+ )
+
+ /**
+ * Match file node content with wildcards regexp, so we can extract aliases values later
+ */
+ const wildcardValuesExtractionMatch = fileNodeIdentifierName.match(
+ wildcardValuesExtractionRegex,
+ )
+
+ if (wildcardValuesExtractionMatch === null) {
+ throw new Error(
+ 'Wildcard alias extraction RegExp did not match, thus it was build incorrectly.',
+ )
+ }
+
+ /**
+ * Compare wildcard aliases with values extracted from file node
+ * - If alias value exist in match context, compare with value from file node
+ * - If alias value does not exist, add it's value to match context
+ */
+ wildcardsMeta.forEach((wildcardMeta) => {
+ const { wildcardAlias, wildcardWithAlias, wildcardType } = wildcardMeta
+
+ if (wildcardAlias !== null) {
+ const existingAlias = wildcardAlias
+ ? matchContext.getIdentifierAlias(wildcardAlias) ||
+ matchContext.getStringAlias(wildcardAlias)
+ : null
+
+ const aliasValue =
+ wildcardValuesExtractionMatch?.groups?.[wildcardAlias] ?? ''
+
+ if (existingAlias !== null) {
+ const aliasMatches = caseInsensitive
+ ? existingAlias.aliasValue.toLocaleLowerCase() ===
+ aliasValue.toLocaleLowerCase()
+ : existingAlias.aliasValue === aliasValue
+
+ levelMatch = levelMatch && aliasMatches
+ } else {
+ if (wildcardType === 'identifier') {
+ matchContext.addIdentifierAlias({
+ alias: wildcardAlias,
+ wildcard: wildcardWithAlias,
+ aliasValue: aliasValue,
+ })
+ } else if (wildcardType === 'string') {
+ matchContext.addStringAlias({
+ alias: wildcardAlias,
+ wildcard: wildcardWithAlias,
+ aliasValue: aliasValue,
+ })
+ }
+ }
+ }
+ })
+ }
+
+ return levelMatch
+}
diff --git a/packages/core/src/searchStages/searchAst.ts b/packages/core/src/searchStages/searchAst.ts
index f1372a2..7bb5ab5 100644
--- a/packages/core/src/searchStages/searchAst.ts
+++ b/packages/core/src/searchStages/searchAst.ts
@@ -8,21 +8,25 @@ import {
traverseAndMatch,
test_traverseAndMatchWithVisitors,
} from './traverseAndMatch'
-import { useTraverseApproachTestOnly } from '../config'
+import { useTraverseApproachTestOnly } from '../testOnlyConfig'
import { getLocationOfMultilineMatch } from './getLocationOfMultilineMatch'
+import { MatchContextAliases } from '../matchContext'
export type SearchAstSettings = SearchSettings & {
queries: NotNullParsedQuery[]
- getCodeForFileNode?: (node: PoorNodeType) => string
+ getCodeForFileNode: (node: PoorNodeType) => string
}
export const searchAst = (
fileNode: PoorNodeType,
{ queries, getCodeForFileNode, ...settings }: SearchAstSettings,
+ unwrapFileNode = true,
+ initialContext?: MatchContextAliases,
) => {
const allMatches: { query: NotNullParsedQuery; matches: Match[] }[] = []
- const programNode =
- settings.parserSettings.getProgramNodeFromRootNode(fileNode)
+ const nodeToSearch = unwrapFileNode
+ ? settings.parserSettings.getProgramNodeFromRootNode(fileNode)
+ : fileNode
for (const query of queries) {
const { queryNode, isMultistatement, queryCode } = query
@@ -41,7 +45,7 @@ export const searchAst = (
return queryCode.substring(pos.start, pos.end)
} catch {
- console.log('Failed getting position for node', node)
+ console.error('Failed getting position for node', node)
}
return ''
@@ -56,23 +60,26 @@ export const searchAst = (
? test_traverseAndMatchWithVisitors
: traverseAndMatch
- const matches = traverseAndMatchFn(programNode, queryNode, newSettings).map(
- (match) => {
- if (!isMultistatement) {
- return match
- }
+ const matches = traverseAndMatchFn(
+ nodeToSearch,
+ queryNode,
+ newSettings,
+ initialContext,
+ ).map((match) => {
+ if (!isMultistatement) {
+ return match
+ }
- /**
- * For multi-statement queries we search where exactly statements are located within parent node
- */
- return getLocationOfMultilineMatch(
- match,
- queryNode,
- newSettings,
- traverseAndMatchFn,
- )
- },
- )
+ /**
+ * For multi-statement queries we search where exactly statements are located within parent node
+ */
+ return getLocationOfMultilineMatch(
+ match,
+ queryNode,
+ newSettings,
+ traverseAndMatchFn,
+ )
+ })
allMatches.push({
query,
diff --git a/packages/core/src/searchStages/searchFileContent.ts b/packages/core/src/searchStages/searchFileContent.ts
index 1edfda6..1a560eb 100644
--- a/packages/core/src/searchStages/searchFileContent.ts
+++ b/packages/core/src/searchStages/searchFileContent.ts
@@ -37,6 +37,10 @@ export const searchFileContent = ({
if (shallowSearchPassed) {
const measureParseFile = measureStart('parseFile')
+ /**
+ *
+ * Used for debugging
+ */
const getCodeForFileNode = (node: PoorNodeType) => {
const pos = settings.parserSettings.getNodePosition(node)
@@ -56,8 +60,11 @@ export const searchFileContent = ({
allMatches = results
.map(({ query, matches }) => {
- return matches.map((match) => {
- const code = prepareCodeResult({ fileContent, ...match })
+ return matches.map(({ node, ...match }) => {
+ const { code, indentationBase } = prepareCodeResult({
+ fileContent,
+ ...match,
+ })
const [extendedCodeFrame, newStartLine] = getExtendedCodeFrame(
match,
@@ -73,6 +80,7 @@ export const searchFileContent = ({
code: extendedCodeFrame,
startLine: match.loc.start.line + newStartLine,
},
+ indentationBase,
}
})
})
@@ -81,7 +89,5 @@ export const searchFileContent = ({
measureSearch()
}
- // console.log('all matches', allMatches)
-
return allMatches
}
diff --git a/packages/core/src/searchStages/traverseAndMatch.ts b/packages/core/src/searchStages/traverseAndMatch.ts
index f1be5e5..92edb12 100644
--- a/packages/core/src/searchStages/traverseAndMatch.ts
+++ b/packages/core/src/searchStages/traverseAndMatch.ts
@@ -4,8 +4,9 @@ import {
PoorNodeType,
SearchSettings,
SearchSettingsWithOptionalLogger,
+ ParserSettings,
} from '../types'
-import { measureStart, noopLogger } from '../utils'
+import { measureStart, noopLogger, uniqueItems } from '../utils'
import { compareNodes } from './compareNodes'
import { validateMatch } from './validateMatch'
import {
@@ -13,6 +14,11 @@ import {
getVisitorKeysForQueryNodeType,
getKeysWithNodes,
} from '../astUtils'
+import {
+ MatchContext,
+ createMatchContext,
+ MatchContextAliases,
+} from '../matchContext'
/**
*
@@ -23,55 +29,121 @@ import {
* VisitorKeys is a set of keys containing other nodes for each node type
*/
-const test_traverse_ast = (
+type ParentMeta = {
+ node: PoorNodeType
+ key: string
+ index?: number
+}
+
+export const traverseAst = (
fileNode: PoorNodeType,
- settings: SearchSettingsWithOptionalLogger,
+ isNode: ParserSettings['isNode'],
+ getNodeType: ParserSettings['getNodeType'],
visitors: Record void>,
+ onNode?: (node: PoorNodeType, parentMeta?: ParentMeta) => void,
+ parentMeta?: {
+ node: PoorNodeType
+ key: string
+ index?: number
+ },
) => {
- const visitor = visitors[fileNode.type as string]
+ const visitor = visitors[getNodeType(fileNode)]
visitor?.(fileNode)
+ onNode?.(fileNode, parentMeta)
const keysWithNodes: string[] = getKeysWithNodes(
fileNode,
Object.keys(fileNode),
- settings.parserSettings.isNode,
+ isNode,
)
- keysWithNodes.forEach((key) => {
+ for (let i = 0; i < keysWithNodes.length; i++) {
+ const key = keysWithNodes[i]
+
if (fileNode[key] !== undefined) {
- if (settings.parserSettings.isNode(fileNode[key] as PoorNodeType)) {
- test_traverse_ast(fileNode[key] as PoorNodeType, settings, visitors)
+ if (isNode(fileNode[key] as PoorNodeType)) {
+ const parentMeta = {
+ node: fileNode,
+ key,
+ }
+
+ traverseAst(
+ fileNode[key] as PoorNodeType,
+ isNode,
+ getNodeType,
+ visitors,
+ onNode,
+ parentMeta,
+ )
} else {
const nestedNodesArray = fileNode[key] as PoorNodeType[]
- nestedNodesArray.forEach((node) =>
- test_traverse_ast(node, settings, visitors),
- )
+ for (let j = 0; j < nestedNodesArray.length; j++) {
+ const parentMeta = {
+ node: fileNode,
+ key,
+ index: j,
+ }
+ const nestedNode = nestedNodesArray[j]
+
+ traverseAst(
+ nestedNode,
+ isNode,
+ getNodeType,
+ visitors,
+ onNode,
+ parentMeta,
+ )
+ }
}
}
- })
+ }
}
export const test_traverseAndMatchWithVisitors = (
fileNode: PoorNodeType,
queryNode: PoorNodeType,
settings: SearchSettingsWithOptionalLogger,
+ initialMatchContext?: MatchContextAliases,
) => {
const matches: Match[] = []
const searchInPath = (node: PoorNodeType) => {
- const match = validateMatch(node, queryNode, settings)
+ const matchContext = createMatchContext(initialMatchContext)
+
+ const { match, matchContext: extendedMatchContext } = validateMatch(
+ node,
+ queryNode,
+ settings,
+ matchContext,
+ )
if (match) {
- const matchData = getMatchFromNode(node, settings.parserSettings)
+ const matchData = getMatchFromNode(
+ node,
+ settings.parserSettings,
+ extendedMatchContext.getAllAliases(),
+ )
matches.push(matchData)
}
}
- const visitorsMap = getVisitorKeysForQueryNodeType(
- queryNode.type as string,
- settings.parserSettings,
+ const visitorKeysForAliasedTreeWildcards =
+ initialMatchContext?.nodesTreeAliasesMap
+ ? Object.values(initialMatchContext?.nodesTreeAliasesMap).map((alias) =>
+ settings.parserSettings.getNodeType(alias.aliasNode),
+ )
+ : []
+
+ const visitorsMap = uniqueItems(
+ getVisitorKeysForQueryNodeType(
+ settings.parserSettings.getNodeType(queryNode),
+ settings.parserSettings,
+ ),
+ ...visitorKeysForAliasedTreeWildcards.map((nodeType) =>
+ getVisitorKeysForQueryNodeType(nodeType, settings.parserSettings),
+ ),
).reduce(
(map, visitorKey) => ({
...map,
@@ -80,7 +152,12 @@ export const test_traverseAndMatchWithVisitors = (
{},
)
- test_traverse_ast(fileNode, settings, visitorsMap)
+ traverseAst(
+ fileNode,
+ settings.parserSettings.isNode,
+ settings.parserSettings.getNodeType,
+ visitorsMap,
+ )
return matches
}
@@ -89,6 +166,7 @@ export const traverseAndMatch = (
fileNode: PoorNodeType,
queryNode: PoorNodeType,
settings: SearchSettingsWithOptionalLogger & GetCodeForNode,
+ initialMatchContext?: MatchContextAliases,
) => {
const settingsWithLogger: SearchSettings & GetCodeForNode = {
...settings,
@@ -97,12 +175,14 @@ export const traverseAndMatch = (
const {
logger: { log, logStepEnd, logStepStart },
parserSettings,
- getCodeForNode = () => '',
+ getCodeForNode = () => 'getCodeForNode not provided',
} = settingsWithLogger
logStepStart('traverse')
const matches = []
+ const localMatchContext = createMatchContext(initialMatchContext)
+
/**
* LOOK FOR MATCH START
*/
@@ -110,6 +190,8 @@ export const traverseAndMatch = (
fileNode,
queryNode,
searchSettings: settingsWithLogger,
+ // To not bind ref in case rest of match is incorrect
+ matchContext: createMatchContext(initialMatchContext),
})
const foundMatchStart = levelMatch
@@ -122,18 +204,31 @@ export const traverseAndMatch = (
// We keep logs in IIFE to get the whole logic removed during build
log(
'foundMatchStart:\n',
- getCodeForNode(fileNode, 'file'),
- '\n',
getCodeForNode(queryNode, 'query'),
+ '\n',
+ getCodeForNode(fileNode, 'file'),
'\n'.padEnd(10, '_'),
)
const measureValidate = measureStart('validate')
- const match = validateMatch(fileNode, queryNode, settings)
+ const { match, matchContext: extendedMatchContext } = validateMatch(
+ fileNode,
+ queryNode,
+ settings,
+ localMatchContext,
+ )
measureValidate()
if (match) {
- matches.push(getMatchFromNode(fileNode, parserSettings))
+ matches.push(
+ getMatchFromNode(
+ fileNode,
+ parserSettings,
+ extendedMatchContext.getAllAliases(),
+ ),
+ )
+ } else {
+ log('match not validated')
}
}
@@ -149,10 +244,11 @@ export const traverseAndMatch = (
fileNode[key] as PoorNodeType,
queryNode,
settings,
+ initialMatchContext,
)
} else {
return (fileNode[key] as PoorNodeType[]).map((node) =>
- traverseAndMatch(node, queryNode, settings),
+ traverseAndMatch(node, queryNode, settings, initialMatchContext),
)
}
}
diff --git a/packages/core/src/searchStages/validateMatch.ts b/packages/core/src/searchStages/validateMatch.ts
index 56fb93b..db958fc 100644
--- a/packages/core/src/searchStages/validateMatch.ts
+++ b/packages/core/src/searchStages/validateMatch.ts
@@ -5,16 +5,19 @@ import {
PoorNodeType,
SearchSettings,
SearchSettingsWithOptionalLogger,
+ ValidateMatchReturnType,
} from '../types'
import { getKeyFromObject, noopLogger } from '../utils'
import { compareNodes } from './compareNodes'
-import { Logger } from '../logger'
+import { MatchContext, createMatchContext } from '../matchContext'
export const validateMatch = (
fileNode: PoorNodeType,
queryNode: PoorNodeType,
settings: SearchSettingsWithOptionalLogger & GetCodeForNode,
-) => {
+ matchContext: MatchContext,
+): ValidateMatchReturnType => {
+ const localMatchContext = createMatchContext(matchContext.getAllAliases())
const settingsWithLogger: SearchSettings & GetCodeForNode = {
...settings,
logger: settings.logger ?? noopLogger,
@@ -22,7 +25,7 @@ export const validateMatch = (
const {
mode,
parserSettings,
- getCodeForNode = () => '',
+ getCodeForNode = () => 'getCodeForNode not provided',
logger: { log, logStepStart },
} = settingsWithLogger
@@ -41,6 +44,7 @@ export const validateMatch = (
fileNode: fileNode,
queryNode: queryNode,
searchSettings: settingsWithLogger,
+ matchContext: localMatchContext,
})
if (
@@ -48,7 +52,11 @@ export const validateMatch = (
queryKeysToTraverseForValidatingMatch.length
) {
throw new Error(
- `Count of keys to validate in query and file does not match for nodes ${fileNode.type}:${fileNode?.name} ${queryNode.type}:${queryNode?.name}, [${fileKeysToTraverseForValidatingMatch}] [${queryKeysToTraverseForValidatingMatch}]`,
+ `Count of keys to validate in query and file does not match for nodes ${parserSettings.getNodeType(
+ fileNode,
+ )}:${fileNode?.name} ${parserSettings.getNodeType(queryNode)}:${
+ queryNode?.name
+ }, [${fileKeysToTraverseForValidatingMatch}] [${queryKeysToTraverseForValidatingMatch}]`,
)
}
@@ -81,7 +89,7 @@ export const validateMatch = (
log('nodes incompat:\n\n', 'invalid code')
}
- return false
+ return { match: false, matchContext: localMatchContext }
} else {
if (queryKeysToTraverseForValidatingMatch.length > 0) {
for (let i = 0; i < queryKeysToTraverseForValidatingMatch.length; i++) {
@@ -97,9 +105,12 @@ export const validateMatch = (
log('validate: query val', queryValue)
log('validate: file val', fileValue)
- if (Array.isArray(fileValue as PoorNodeType[])) {
+ if (
+ Array.isArray(fileValue as PoorNodeType[]) &&
+ Array.isArray(queryValue as PoorNodeType[])
+ ) {
log('validate: is array')
- const nodesArr = (fileValue as PoorNodeType[]).filter(
+ const fileNodesArr = (fileValue as PoorNodeType[]).filter(
parserSettings.shouldCompareNode,
)
const queryNodesArr = (queryValue as PoorNodeType[]).filter(
@@ -107,75 +118,118 @@ export const validateMatch = (
)
if (isExact) {
- if (nodesArr.length !== queryNodesArr.length) {
- return false
+ if (fileNodesArr.length !== queryNodesArr.length) {
+ return { match: false, matchContext: localMatchContext }
}
- for (let i = 0; i < nodesArr.length; i++) {
- const newCurrentNode = nodesArr[i]
+ for (let i = 0; i < fileNodesArr.length; i++) {
+ const newCurrentNode = fileNodesArr[i]
const newCurrentQueryNode = queryNodesArr[i]
- if (
- !newCurrentNode ||
- !newCurrentQueryNode ||
- !validateMatch(newCurrentNode, newCurrentQueryNode, settings)
- ) {
- return false
+ if (!newCurrentNode || !newCurrentQueryNode) {
+ return { match: false, matchContext: localMatchContext }
}
+
+ const validateMatchResult = validateMatch(
+ newCurrentNode,
+ newCurrentQueryNode,
+ settings,
+ localMatchContext,
+ )
+
+ if (!validateMatchResult.match) {
+ return { match: false, matchContext: localMatchContext }
+ }
+
+ localMatchContext.merge(
+ validateMatchResult.matchContext.getAllAliases(),
+ )
}
} else {
- if (queryNodesArr.length > nodesArr.length) {
- return false
+ if (queryNodesArr.length > fileNodesArr.length) {
+ log('validate: more query nodes than array nodes')
+
+ return { match: false, matchContext: localMatchContext }
}
- const matchedIndexes: number[] = []
+ if (mode === 'include') {
+ const matchedIndexes: number[] = []
+
+ const queryNodesArrSorted = [...queryNodesArr].sort((a, b) =>
+ sortByLeastIdentifierStrength(
+ a,
+ b,
+ parserSettings.wildcardUtils,
+ parserSettings.getIdentifierNodeName,
+ ),
+ )
- const queryNodesArrSorted = [...queryNodesArr].sort((a, b) =>
- sortByLeastIdentifierStrength(a, b, parserSettings.wildcardUtils),
- )
+ for (let i = 0; i < queryNodesArrSorted.length; i++) {
+ const newQueryNode = queryNodesArrSorted[i]
- for (let i = 0; i < queryNodesArrSorted.length; i++) {
- const newQueryNode = queryNodesArrSorted[i]
+ for (let j = 0; j < fileNodesArr.length; j++) {
+ const newFileNode = fileNodesArr[j]
- for (let j = 0; j < nodesArr.length; j++) {
- const newFileNode = nodesArr[j]
+ if (!matchedIndexes.includes(j)) {
+ const validateMatchResult = validateMatch(
+ newFileNode,
+ newQueryNode,
+ settings,
+ localMatchContext,
+ )
- if (!matchedIndexes.includes(j)) {
- if (validateMatch(newFileNode, newQueryNode, settings)) {
- matchedIndexes.push(j)
- break
+ if (validateMatchResult.match) {
+ matchedIndexes.push(j)
+
+ localMatchContext.merge(
+ validateMatchResult.matchContext.getAllAliases(),
+ )
+
+ break
+ }
}
}
+
+ if (matchedIndexes.length !== i + 1) {
+ return { match: false, matchContext: localMatchContext }
+ }
}
- if (matchedIndexes.length !== i + 1) {
- return false
+ if (matchedIndexes.length !== queryNodesArr.length) {
+ return { match: false, matchContext: localMatchContext }
}
- }
+ } else {
+ // mode is include-with-order
- if (mode === ('include-with-order' as Mode)) {
- const propsFoundInOrder = matchedIndexes.every(
- (val, idx, arr) => {
- if (idx + 1 === arr.length) {
- return true
- } else {
- return val < arr[idx + 1]
- }
- },
- )
+ let queryNodeIndexToMatch = 0
+
+ for (let j = 0; j < fileNodesArr.length; j++) {
+ const newFileNode = fileNodesArr[j]
+ const newQueryNode = queryNodesArr[queryNodeIndexToMatch]
+
+ const validateMatchResult = validateMatch(
+ newFileNode,
+ newQueryNode,
+ settings,
+ localMatchContext,
+ )
- if (
- !propsFoundInOrder ||
- matchedIndexes.length !== queryNodesArr.length
- ) {
- return false
+ if (validateMatchResult.match) {
+ queryNodeIndexToMatch++
+
+ localMatchContext.merge(
+ validateMatchResult.matchContext.getAllAliases(),
+ )
+ }
}
- } else {
- if (matchedIndexes.length !== queryNodesArr.length) {
- return false
+
+ if (queryNodeIndexToMatch !== queryNodesArr.length) {
+ return { match: false, matchContext: localMatchContext }
}
}
}
+
+ log('validate: non boolean return result for comparing nodes array')
} else {
log('validate: is Node')
@@ -184,19 +238,36 @@ export const validateMatch = (
log('validate: newFileNode', newFileNode)
log('validate: newQueryNode', newQueryNode)
- if (
- !newFileNode ||
- !newQueryNode ||
- !validateMatch(newFileNode, newQueryNode, settings)
- ) {
- return false
+ if (!newFileNode || !newQueryNode) {
+ return { match: false, matchContext: localMatchContext }
}
+
+ const validateMatchResult = validateMatch(
+ newFileNode,
+ newQueryNode,
+ settings,
+ localMatchContext,
+ )
+
+ if (!validateMatchResult.match) {
+ return { match: false, matchContext: localMatchContext }
+ }
+
+ localMatchContext.merge(
+ validateMatchResult.matchContext.getAllAliases(),
+ )
}
}
- return true
+ return {
+ match: true,
+ matchContext: localMatchContext,
+ }
} else {
- return true
+ return {
+ match: true,
+ matchContext: localMatchContext,
+ }
}
}
}
diff --git a/packages/core/src/searchWorker.ts b/packages/core/src/searchWorker.ts
index 83e466d..19ccdf4 100644
--- a/packages/core/src/searchWorker.ts
+++ b/packages/core/src/searchWorker.ts
@@ -1,12 +1,18 @@
import { parentPort, workerData as _workerData } from 'worker_threads'
+import { parserSettingsMap } from './parserSettings'
import { searchInFileSystem } from './searchInFs'
import { Matches, SearchWorkerData, WorkerOutboundMessage } from './types'
-//
-;(async () => {
+const searchWorkerRuntime = async () => {
const workerData = _workerData as SearchWorkerData
+ const parser = workerData.parser
+ const parserFilesBasePath = workerData.parserFilesBasePath
+
+ if (parser) {
+ await parserSettingsMap[parser]().init?.(parserFilesBasePath)
+ }
const onPartialResult = workerData.reportEachMatch
? (partialResult: Matches) => {
@@ -26,4 +32,6 @@ import { Matches, SearchWorkerData, WorkerOutboundMessage } from './types'
type: 'ALL_RESULTS',
data: results,
} as WorkerOutboundMessage)
-})()
+}
+
+searchWorkerRuntime()
diff --git a/packages/core/src/testOnlyConfig.ts b/packages/core/src/testOnlyConfig.ts
new file mode 100644
index 0000000..3c6e925
--- /dev/null
+++ b/packages/core/src/testOnlyConfig.ts
@@ -0,0 +1,13 @@
+import { ParserType } from './types'
+type TestSettings = {
+ parserType: ParserType
+ isTraversal: boolean
+}
+
+declare global {
+ //eslint-disable-next-line no-var
+ var testSettings: TestSettings | undefined
+}
+
+export const useTraverseApproachTestOnly = global?.testSettings?.isTraversal
+export const testParserTypeOverride = global?.testSettings?.parserType
diff --git a/packages/core/src/textSearch.ts b/packages/core/src/textSearch.ts
index b3162a3..deb4a68 100644
--- a/packages/core/src/textSearch.ts
+++ b/packages/core/src/textSearch.ts
@@ -281,6 +281,12 @@ export function textSearch({
},
query: query.toString(),
filePath,
+ // TODO: improve text search types, they do not provide aliases
+ aliases: {
+ identifierAliasesMap: {},
+ nodesTreeAliasesMap: {},
+ stringAliasesMap: {},
+ },
}
})
diff --git a/packages/core/src/treeSitterUtils.ts b/packages/core/src/treeSitterUtils.ts
new file mode 100644
index 0000000..2a5e919
--- /dev/null
+++ b/packages/core/src/treeSitterUtils.ts
@@ -0,0 +1,295 @@
+import type { SyntaxNode, Tree } from 'web-tree-sitter'
+import Parser from 'web-tree-sitter'
+import { PoorNodeType, TreeSitterNodeFieldsMeta } from './types'
+
+export type PostProcessNodes = Record<
+ string,
+ (node: PoorNodeType, codeText: string) => PoorNodeType
+>
+
+export function collectAstFromTree({
+ tree,
+ codeText,
+ defineRawValueForNodeTypes,
+ nodeFieldsMeta,
+ postProcessNodes,
+}: {
+ tree: Tree
+ codeText: string
+ defineRawValueForNodeTypes: string[]
+ nodeFieldsMeta: TreeSitterNodeFieldsMeta
+ postProcessNodes?: PostProcessNodes
+}) {
+ const getPosition = (node: SyntaxNode) => {
+ const startPosition = node.startPosition
+ const endPosition = node.endPosition
+ const startIndex = node.startIndex
+ const endIndex = node.endIndex
+
+ return {
+ start: {
+ line: startPosition.row + 1,
+ column: startPosition.column,
+ index: startIndex,
+ },
+ end: {
+ line: endPosition.row + 1,
+ column: endPosition.column,
+ index: endIndex,
+ },
+ }
+ }
+
+ function collectAstFromTreeInner(
+ node: SyntaxNode,
+ level = 0,
+ nodeTypeFromParent?: string,
+ ) {
+ /**
+ * Receiving node type from parent is performance optimization for slow access to WASM memory
+ */
+ const nodeType = nodeTypeFromParent ?? node.type
+
+ if (nodeType === 'ERROR') {
+ const errorLocation = getPosition(node)
+ const error = Error(
+ `Parse error at ${errorLocation.start.line}:${errorLocation.start.column}-${errorLocation.end.line}:${errorLocation.end.column}`,
+ )
+
+ //@ts-ignore
+ error.loc = errorLocation
+
+ throw error
+ }
+
+ const nodeMeta = nodeFieldsMeta[nodeType]
+
+ if (!nodeMeta) {
+ /**
+ * We don't care about node types that are not in meta mapping
+ */
+ return null
+ }
+
+ const fields = Object.fromEntries([
+ ...nodeMeta.multipleOrChildrenFieldNames.map((fieldName) => [
+ fieldName,
+ [],
+ ]),
+ ...nodeMeta.singleFieldNames.map((fieldName) => [fieldName, null]),
+ ])
+
+ const fieldNodes: SyntaxNode[] = []
+
+ nodeMeta.singleFieldNames.forEach((fieldName) => {
+ const childForName = node.childForFieldName(fieldName)
+
+ if (childForName) {
+ fieldNodes.push(childForName)
+
+ fields[fieldName] = collectAstFromTreeInner(childForName, level + 1)
+ }
+ })
+
+ const childCount = node.childCount
+
+ for (let i = 0; i < childCount; i++) {
+ const childNode = node.child(i)
+
+ if (
+ childNode &&
+ !fieldNodes.some((fieldNode) => fieldNode.equals(childNode))
+ ) {
+ const collectedNodeType = childNode.type as string
+
+ if (collectedNodeType === 'ERROR') {
+ collectAstFromTreeInner(childNode, level + 1, collectedNodeType)
+ }
+
+ /**
+ * We ignore nodes with types that are not in mapping
+ */
+ if (nodeFieldsMeta[collectedNodeType]) {
+ const collectedNode = collectAstFromTreeInner(
+ childNode,
+ level + 1,
+ collectedNodeType,
+ )
+
+ if (collectedNode) {
+ const field =
+ nodeMeta.nodeTypeToMultipleFieldName[collectedNodeType]
+
+ if (field) {
+ if (fields[field]) {
+ fields[field].push(collectedNode)
+ } else {
+ console.error(`No field "${field}" for ${collectedNodeType}`)
+ }
+ }
+
+ /**
+ * When node field was not found in mapping, it most likely mean that node was some language keyword that can be skipped
+ */
+ }
+ }
+ }
+ }
+
+ const rawNode = {
+ nodeType: nodeType,
+ loc: getPosition(node),
+ ...fields,
+ } as PoorNodeType
+
+ const isLeaf =
+ nodeMeta.multipleOrChildrenFieldNames.length === 0 &&
+ nodeMeta.singleFieldNames.length === 0
+
+ // Temporary disable check for leaf node, perhaps it's not needed. Now breaks stuff for string_content, which itself needs more adjustments to work properly
+ if (/*isLeaf && */ defineRawValueForNodeTypes.includes(nodeType)) {
+ rawNode.rawValue = codeText.substring(
+ //@ts-ignore
+ rawNode.loc.start.index,
+ //@ts-ignore
+ rawNode.loc.end.index,
+ )
+ }
+
+ if (postProcessNodes?.[nodeType]) {
+ return postProcessNodes[nodeType](rawNode, codeText)
+ }
+
+ return rawNode
+ }
+
+ return collectAstFromTreeInner(tree.rootNode)
+}
+
+export const getFilePaths = (parserName: string) => {
+ return {
+ treeSitterWasm: `dist-tree-sitter/tree-sitter.wasm`,
+ parserWasm: `dist-tree-sitter/${parserName}/parser.wasm`,
+ fieldsMeta: `dist-tree-sitter/${parserName}/fields-meta.json`,
+ }
+}
+
+export const getFieldsMeta = async (
+ basePath: string,
+ path: string,
+): Promise => {
+ if (typeof window !== 'undefined') {
+ return (await fetch(basePath + '/' + path)).json()
+ }
+
+ return JSON.parse(
+ require('fs')
+ .readFileSync(sanitizeFsPath(basePath + '/' + path))
+ .toString(),
+ )
+}
+
+export const getTreeSitterWasmPath = (
+ basePath: string,
+ parserPath: string,
+): string => {
+ if (typeof window !== 'undefined') {
+ return basePath + '/' + parserPath
+ }
+
+ return sanitizeFsPath(basePath + '/' + parserPath)
+}
+
+export const sanitizeFsPath = (fsPath: string) => {
+ const isWindows = process?.platform.includes('win32')
+
+ // For some reason vscode return lowercased drive letters on windows :/
+ if (isWindows) {
+ return fsPath.replace(/\//g, '\\')
+ }
+
+ return fsPath.replace(/\\/g, '/')
+}
+
+const getDefaultBasePath = () => {
+ return typeof process?.cwd !== 'undefined' ? process.cwd() : '/'
+}
+
+export const treeSitterParserModuleFactory = ({
+ treeSitterParserName,
+ defineRawValueForNodeTypes,
+ postProcessNodes,
+}: {
+ treeSitterParserName: string
+ defineRawValueForNodeTypes: string[]
+ postProcessNodes?: PostProcessNodes
+}) => {
+ let parser: Parser | null = null
+ let parserInitError: Error | null = null
+ let fieldsMeta: TreeSitterNodeFieldsMeta | null = null
+
+ const filePaths = getFilePaths(treeSitterParserName)
+
+ const init = async (basePathOption?: string | undefined) => {
+ if (parser) {
+ return
+ }
+
+ const basePath = basePathOption ?? getDefaultBasePath()
+
+ return Parser.init({
+ locateFile: () =>
+ getTreeSitterWasmPath(basePath, filePaths.treeSitterWasm),
+ })
+ .then(async () => {
+ fieldsMeta = await getFieldsMeta(basePath, filePaths.fieldsMeta)
+ const Python = await Parser.Language.load(
+ getTreeSitterWasmPath(basePath, filePaths.parserWasm),
+ )
+
+ const localParser = new Parser()
+
+ localParser.setLanguage(Python)
+ parser = localParser
+ })
+ .catch((error) => {
+ console.error('Parser init error', error)
+ parser = null
+ parserInitError = error
+ })
+ }
+
+ const parse = (code: string) => {
+ if (parserInitError !== null) {
+ throw parserInitError
+ }
+
+ if (parser === null) {
+ throw new Error('Parser not ready')
+ }
+
+ if (fieldsMeta === null) {
+ throw new Error("Couldn't load fields meta")
+ }
+
+ if (parserInitError) {
+ throw parserInitError
+ }
+
+ const tree = parser.parse(code, undefined)
+
+ const ast = collectAstFromTree({
+ tree,
+ codeText: code,
+ defineRawValueForNodeTypes,
+ nodeFieldsMeta: fieldsMeta,
+ postProcessNodes,
+ })
+
+ tree.delete()
+
+ return ast ?? { nodeType: 'empty' } // this is to make TS happy, won't happen in real life.
+ }
+
+ return { init, parse }
+}
diff --git a/packages/core/src/types.ts b/packages/core/src/types.ts
index 8e5b155..87e3d22 100644
--- a/packages/core/src/types.ts
+++ b/packages/core/src/types.ts
@@ -1,9 +1,11 @@
import { Logger } from './logger'
+import { MatchContext, MatchContextAliases } from './matchContext'
export type Mode = 'exact' | 'include' | 'include-with-order' | 'text'
export type Position = {
line: number
column: number
+ index?: number
}
export type Location = {
@@ -11,11 +13,15 @@ export type Location = {
end: Position
}
-export type Match = {
+export type MatchPosition = {
start: number
end: number
loc: Location
+}
+
+export type Match = MatchPosition & {
node: PoorNodeType
+ aliases: MatchContextAliases
}
export type ExtendedCodeFrame = {
@@ -28,6 +34,7 @@ export type MatchWithFileInfo = Omit & {
code: string
filePath: string
extendedCodeFrame: ExtendedCodeFrame
+ indentationBase?: number
}
export type AstMatch = Omit & {
@@ -37,8 +44,22 @@ export type AstMatch = Omit & {
export type Matches = Array
export type AstMatches = Array
+export type PoorNodeTypeParentData = {
+ node: PoorNodeType
+ key: string
+ index?: number
+}
+
export type PoorNodeType = {
- [key: string]: string | number | boolean | PoorNodeType[] | PoorNodeType
+ [key: string]:
+ | string
+ | number
+ | boolean
+ | null
+ | PoorNodeType[]
+ | PoorNodeType
+} & {
+ __parent?: PoorNodeTypeParentData
}
export type HardStopFlag = {
@@ -47,7 +68,17 @@ export type HardStopFlag = {
destroy: () => void
}
-export type ParserType = 'babel' | 'typescript-eslint' | 'esprima'
+export type ParserType =
+ | 'babel'
+ | 'typescript-eslint-parser'
+ | 'espree'
+ | 'esprima'
+ | 'babel-eslint-parser'
+ | 'angular-eslint-template-parser'
+ | 'css-tree'
+ | 'python'
+ | 'lua'
+ | 'csharp'
export type FileSystemSearchArgs = {
filePaths: string[]
@@ -59,6 +90,8 @@ export type FileSystemSearchArgs = {
maxResultsLimit?: number
hardStopFlag?: HardStopFlag
parser?: ParserType
+ returnMatchedNodes?: boolean
+ parserFilesBasePath?: string
}
export type ParseError = {
@@ -112,10 +145,10 @@ export type SearchWorkerData = FileSystemSearchArgs & {
}
export type SearchSettings = {
+ parserSettings: ParserSettings
logger: Logger
caseInsensitive: boolean
mode: Mode
- parserSettings: ParserSettings
}
export type SearchSettingsWithOptionalLogger = Omit<
@@ -130,16 +163,17 @@ export type GetCodeForNode = {
}
export type WildcardMeta = {
- wildcardType: 'identifier' | 'nodeTree'
- wildcardWithRef: string
- wildcardWithoutRef: string
- wildcardRef: string | null
+ wildcardType: 'identifier' | 'nodeTree' | 'string'
+ wildcardWithAlias: string
+ wildcardWithoutAlias: string
+ wildcardAlias: string | null
}
export type CompareNodesParams = {
fileNode: PoorNodeType | null
queryNode: PoorNodeType | null
- searchSettings: SearchSettings
+ searchSettings: SearchSettings & GetCodeForNode
+ matchContext: MatchContext
/** Params used to support comparing nodes which are not on the same level */
queryKeysPrefix?: string
fileKeysPrefix?: string
@@ -160,6 +194,7 @@ export type NodesComparator = (
fileKeysMapper: (key: string) => string
fileKeysToTraverseForOtherMatches: string[]
measureCompare: () => void
+ log: (...text: string[]) => void
},
) => CompareNodesReturnType | undefined
@@ -174,10 +209,12 @@ export type WildcardUtils = {
numericWildcard: string
disallowedWildcardSequence: string
disallowedWildcardRegExp: RegExp
- removeIdentifierRefFromWildcard: (identifier: string) => string
- getWildcardRefFromIdentifierName: (name: string) => string | null
- getWildcardFromString: (name: string) => WildcardMeta | null
- getWildcardFromNode: (node: PoorNodeType) => WildcardMeta | null
+ removeWildcardAliasesFromIdentifierName: (identifier: string) => string
+ removeWildcardAliasesFromStringLiteral: (str: string) => string
+ getWildcardAliasFromWildcard: (name: string) => string | null
+ getIdentifierWildcardsFromString: (name: string) => WildcardMeta[]
+ getIdentifierWildcardsFromNode: (node: PoorNodeType) => WildcardMeta[]
+ getStringWildcardsFromString: (content: string) => WildcardMeta[]
patternToRegExp: (string: string, caseInsensitive: boolean) => RegExp
}
@@ -198,28 +235,36 @@ export type ProgramNodeAndBlockNodeUtils = {
blockNodeBodyKey: string
}
+export type GetUniqueTokensFromStringOrIdentifierNode = (arg: {
+ queryNode: PoorNodeType
+ caseInsensitive: boolean
+ parserSettings: Pick<
+ ParserSettings,
+ | 'isIdentifierNode'
+ | 'stringLikeLiteralUtils'
+ | 'getIdentifierNodeName'
+ | 'wildcardUtils'
+ >
+}) => string[]
+
export type ParserSettings = {
supportedExtensions: string[]
parseCode: (code: string, filePath?: string) => PoorNodeType
isNode: (maybeNode: PoorNodeType) => boolean
+ identifierNodeTypes: string[]
isIdentifierNode: (node: PoorNodeType) => boolean
astPropsToSkip: (string | { type: string; key: string })[]
- /**
- * This one is tricky, we use it to remove `null` or `undefined` properties from file node that are not present in query node
- * Even if we use proper mapping for babel, we can also just `return true` to make it work
- * Keeping this for now, but perhaps in future it could be removed, because we use it only in include mode, where everything should be optional
- */
- isNodeFieldOptional: (nodeType: string, nodeFieldKey: string) => boolean
getProgramBodyFromRootNode: (node: PoorNodeType) => PoorNodeType[]
getProgramNodeFromRootNode: (node: PoorNodeType) => PoorNodeType
getNodeType: (node: PoorNodeType) => string
getIdentifierNodeName: (node: PoorNodeType) => string
+ setIdentifierNodeName: (node: PoorNodeType, name: string) => void
unwrapExpressionStatement: (node: PoorNodeType) => PoorNodeType
createBlockStatementNode: (
body: PoorNodeType[],
- position: Omit,
+ position: MatchPosition,
) => PoorNodeType
- sanitizeNode: (node: PoorNodeType) => void
+ getSanitizedNodeValue: (type: string, key: string, value: T) => T
shouldCompareNode: (node: PoorNodeType) => void
wildcardUtils: WildcardUtils
compareNodesBeforeWildcardsComparison: NodesComparator
@@ -228,11 +273,30 @@ export type ParserSettings = {
stringLikeLiteralUtils: StringLikeLiteralUtils
numericLiteralUtils: NumericLiteralUtils
programNodeAndBlockNodeUtils: ProgramNodeAndBlockNodeUtils
- getNodePosition: (node: PoorNodeType) => Omit
+ getNodePosition: (node: PoorNodeType) => MatchPosition
getParseErrorLocation: (error: Error) => { line: number; column: number }
/**
* Alternative node types used to match while in traversal mode
* eg. wildcard Identifier matcher should look in JSXIdentifier visitor
*/
alternativeNodeTypes: Record
+ preprocessQueryCode?: (code: string) => string
+ postprocessQueryNode?: (queryNode: PoorNodeType) => PoorNodeType
+ getUniqueTokensFromStringOrIdentifierNode?: GetUniqueTokensFromStringOrIdentifierNode
+ init?: (basePath?: string) => Promise
+}
+
+export type TreeSitterNodeFieldsMeta = Record<
+ string,
+ {
+ type: string
+ singleFieldNames: string[]
+ nodeTypeToMultipleFieldName: Record
+ multipleOrChildrenFieldNames: string[]
+ }
+>
+
+export type ValidateMatchReturnType = {
+ match: boolean
+ matchContext: MatchContext
}
diff --git a/packages/core/src/utils.ts b/packages/core/src/utils.ts
index 8f98e2f..99bd7a3 100644
--- a/packages/core/src/utils.ts
+++ b/packages/core/src/utils.ts
@@ -9,6 +9,7 @@ import {
Mode,
NodesComparator,
NodesComparatorParameters,
+ MatchPosition,
} from './types'
export const getMode = (mode: Mode = 'include') => {
@@ -154,10 +155,8 @@ export const nonIdentifierOrKeywordGlobal = new RegExp(
'g',
)
-export const dedupMatches = (
+export const dedupMatches = (
matches: M[],
- log: (...args: any[]) => void,
- debug = false,
): M[] => {
const deduped: M[] = []
@@ -188,7 +187,7 @@ export const prepareCodeResult = ({
start,
end,
loc,
-}: { fileContent: string } & Omit) => {
+}: { fileContent: string } & MatchPosition) => {
const frame = fileContent.substring(start - loc.start.column, end)
const firstLineWhiteCharsCountRegExp = new RegExp(`^\\s*`)
@@ -201,10 +200,12 @@ export const prepareCodeResult = ({
const replaceRegex = new RegExp(`^\\s{0,${firstLineWhiteCharsCount}}`)
if (firstLineWhiteCharsCount > 0) {
- return lines.map((line) => line.replace(replaceRegex, '')).join('\n')
+ const code = lines.map((line) => line.replace(replaceRegex, '')).join('\n')
+
+ return { code, indentationBase: firstLineWhiteCharsCount }
}
- return lines.join('\n')
+ return { code: lines.join('\n'), indentationBase: 0 }
}
export const isNullOrUndef = (val: any) => val === null || val === undefined
@@ -232,3 +233,23 @@ export const noopLogger: Logger = {
logStepEnd: () => undefined,
logStepStart: () => undefined,
}
+
+export const groupBy = >(
+ arr: T[],
+ key: K,
+) => {
+ return Object.values(
+ arr.reduce((grouped, duplicate) => {
+ const maybeExistingGroup = grouped[duplicate[key]] ?? []
+ grouped[duplicate[key]] = [...maybeExistingGroup, duplicate]
+
+ return grouped
+ }, {} as Record),
+ )
+}
+
+export const decomposeString = (str: string, splitter: RegExp) =>
+ str
+ .split(splitter)
+ .map((part) => normalizeText(part).split(SPACE_CHAR))
+ .flat(1)
diff --git a/packages/core/src/wildcardUtilsFactory.ts b/packages/core/src/wildcardUtilsFactory.ts
index ecea612..d35945d 100644
--- a/packages/core/src/wildcardUtilsFactory.ts
+++ b/packages/core/src/wildcardUtilsFactory.ts
@@ -1,86 +1,170 @@
import { PoorNodeType, WildcardMeta, WildcardUtils } from './types'
-import { nonIdentifierOrKeywordGlobal } from './utils'
+import { nonIdentifierOrKeywordGlobal, regExpTest } from './utils'
export const createWildcardUtils = (
identifierNodeTypes: string[],
numericWildcard: string,
identifierWildcardBase: string,
+ getIdentifierNodeName: (node: PoorNodeType) => string,
+ getNodeType: (node: PoorNodeType) => string,
stringWildcardBase = identifierWildcardBase,
): WildcardUtils => {
const identifierWildcard = identifierWildcardBase.repeat(2)
const nodesTreeWildcard = identifierWildcardBase.repeat(3)
- const removeIdentifierRefFromWildcard = (name: string) => {
- const containsWildcardRegExp = new RegExp(`^\\${identifierWildcardBase}`)
- const removeIdRefRegExp = new RegExp(
- `(?<=(\\${identifierWildcardBase}){2,3})_(\\w)+$`,
- )
+ const createRemoveWildcardAliasesFromIdentifierName =
+ (wildcardBase: string) => (name: string) => {
+ const containsWildcardWithInvalidRefRegExp = new RegExp(
+ `(\\${wildcardBase}){2,3}([a-zA-Z0-9])+_(\\${wildcardBase}){2,3}`,
+ )
+
+ const containsWildcardWithInvalidRefRegExp2 = new RegExp(
+ `(\\${wildcardBase}){2,3}_([a-zA-Z0-9])+(\\${wildcardBase}){2,3}`,
+ )
+
+ const containsWildcardWithInvalidRefRegExp3 = new RegExp(
+ `(\\${wildcardBase}){2,3}_([a-zA-Z0-9])+_(\\${wildcardBase}){2,3}`,
+ )
+
+ const removeIdRefRegExp = new RegExp(
+ `(?<=(\\${wildcardBase}){2,3})_([a-zA-Z0-9])+(_)?`,
+ )
+
+ let nameWithRemovedWildcardsAliases = name
+
+ while (
+ regExpTest(removeIdRefRegExp, nameWithRemovedWildcardsAliases) &&
+ !regExpTest(
+ containsWildcardWithInvalidRefRegExp,
+ nameWithRemovedWildcardsAliases,
+ ) &&
+ !regExpTest(
+ containsWildcardWithInvalidRefRegExp2,
+ nameWithRemovedWildcardsAliases,
+ ) &&
+ !regExpTest(
+ containsWildcardWithInvalidRefRegExp3,
+ nameWithRemovedWildcardsAliases,
+ )
+ ) {
+ nameWithRemovedWildcardsAliases =
+ nameWithRemovedWildcardsAliases.replace(removeIdRefRegExp, '')
+ }
- if (containsWildcardRegExp.test(name)) {
- return name.replace(removeIdRefRegExp, '')
+ return nameWithRemovedWildcardsAliases
}
- return name
- }
+ const removeWildcardAliasesFromIdentifierName =
+ createRemoveWildcardAliasesFromIdentifierName(identifierWildcardBase)
- const getWildcardRefFromIdentifierName = (name: string) => {
+ const removeWildcardAliasesFromStringLiteral =
+ createRemoveWildcardAliasesFromIdentifierName(stringWildcardBase)
+
+ const getWildcardAliasFromWildcard = (name: string) => {
const getRefRegExp = new RegExp(
- `(?<=(\\${identifierWildcardBase}){2,3}_)(\\w)+$`,
+ `(?<=(\\${identifierWildcardBase}){2,3})_([a-zA-Z0-9])+(?=(_?))`,
'g',
)
const matchedRef = name.match(getRefRegExp)
- return matchedRef?.[0] || null
+ return matchedRef?.[0]?.replace(/_/g, '') || null
}
- const getWildcardFromString = (
- maybeWildcardString: string,
- ): null | WildcardMeta => {
+ const getWildcardWithAliasFromIdentifierName = (name: string) => {
+ const getRefRegExp = new RegExp(
+ `((\\${identifierWildcardBase}){2,3}_([a-zA-Z0-9])+(_)?)|((\\${identifierWildcardBase}){2,3})`,
+ 'g',
+ )
+
+ const matchedWildcard = name.match(getRefRegExp)
+
+ return matchedWildcard?.[0] as string
+ }
+
+ const hasWildcard = (maybeWildcardString: string) => {
const hasIdentifierWildcard =
maybeWildcardString.includes(identifierWildcard)
const hasNodeTreeWildcard = maybeWildcardString.includes(nodesTreeWildcard)
- const hasWildcard = hasIdentifierWildcard || hasNodeTreeWildcard
- if (hasWildcard) {
- const wildcardWithoutRef =
- removeIdentifierRefFromWildcard(maybeWildcardString)
+ return hasIdentifierWildcard || hasNodeTreeWildcard
+ }
+
+ const getIdentifierWildcardsFromString = (
+ maybeWildcardString: string,
+ ): WildcardMeta[] => {
+ let maybeWildcardStringToDecompose = maybeWildcardString
+ const wildcardsMeta: WildcardMeta[] = []
- return {
+ while (hasWildcard(maybeWildcardStringToDecompose)) {
+ const hasNodeTreeWildcard =
+ maybeWildcardStringToDecompose.includes(nodesTreeWildcard)
+
+ const wildcardWithAlias = getWildcardWithAliasFromIdentifierName(
+ maybeWildcardStringToDecompose,
+ )
+
+ const wildcardAlias = getWildcardAliasFromWildcard(wildcardWithAlias)
+
+ const wildcardWithoutAlias =
+ removeWildcardAliasesFromIdentifierName(wildcardWithAlias)
+
+ wildcardsMeta.push({
wildcardType: hasNodeTreeWildcard ? 'nodeTree' : 'identifier',
- wildcardWithRef: maybeWildcardString,
- wildcardWithoutRef,
- wildcardRef: getWildcardRefFromIdentifierName(maybeWildcardString),
- }
+ wildcardWithAlias,
+ wildcardWithoutAlias,
+ wildcardAlias,
+ })
+
+ const wildcardEndIdx =
+ maybeWildcardStringToDecompose.indexOf(wildcardWithAlias) +
+ wildcardWithAlias.length
+
+ maybeWildcardStringToDecompose =
+ maybeWildcardStringToDecompose.substring(wildcardEndIdx)
}
- return null
+ return wildcardsMeta
}
- const getWildcardFromNode = (node: PoorNodeType): null | WildcardMeta => {
- if (typeof node.type !== 'string') {
- return null
+ const getIdentifierWildcardsFromNode = (
+ node: PoorNodeType,
+ ): WildcardMeta[] => {
+ const nodeType = getNodeType(node)
+
+ if (typeof nodeType !== 'string') {
+ return []
}
const isIdentifierNode =
- typeof node.type === 'string' && identifierNodeTypes.includes(node.type)
+ typeof nodeType === 'string' && identifierNodeTypes.includes(nodeType)
- if (isIdentifierNode && typeof node.name === 'string') {
- return getWildcardFromString(node.name)
+ if (isIdentifierNode && typeof getIdentifierNodeName(node) === 'string') {
+ return getIdentifierWildcardsFromString(getIdentifierNodeName(node))
}
- const isTypeReferenceNode = node.type === 'TSTypeReference'
+ /**
+ * TODO: make it generic
+ */
+ const isTypeReferenceNode = nodeType === 'TSTypeReference'
if (isTypeReferenceNode) {
const maybeWildcardString = (node?.typeName as unknown as PoorNodeType)
?.name as string | undefined
if (typeof maybeWildcardString === 'string') {
- return getWildcardFromString(maybeWildcardString)
+ return getIdentifierWildcardsFromString(maybeWildcardString)
}
}
- return null
+ return []
+ }
+
+ const getStringWildcardsFromString = (content: string): WildcardMeta[] => {
+ // Might need to have separate implementation for some other programming langs, good for now
+ return getIdentifierWildcardsFromString(content).map(
+ ({ wildcardType, ...rest }) => ({ wildcardType: 'string', ...rest }),
+ )
}
const optionalStringWildcardRegExp = new RegExp(
@@ -92,6 +176,11 @@ export const createWildcardUtils = (
'g',
)
+ const anyStringWildcardRegExp = new RegExp(
+ `(\\${stringWildcardBase}){2,3}`,
+ 'g',
+ )
+
const disallowedWildcardRegExp = new RegExp(
`(\\${identifierWildcardBase}){4,}(?!\\{)`,
)
@@ -128,16 +217,18 @@ export const createWildcardUtils = (
return {
optionalStringWildcardRegExp,
requiredStringWildcardRegExp,
- anyStringWildcardRegExp: new RegExp(`(\\${stringWildcardBase}){2,3}`, 'g'),
+ anyStringWildcardRegExp,
identifierWildcard,
nodesTreeWildcard,
numericWildcard,
disallowedWildcardSequence: identifierWildcardBase.repeat(4),
disallowedWildcardRegExp,
- removeIdentifierRefFromWildcard,
- getWildcardRefFromIdentifierName,
- getWildcardFromString,
- getWildcardFromNode,
+ removeWildcardAliasesFromIdentifierName,
+ removeWildcardAliasesFromStringLiteral,
+ getWildcardAliasFromWildcard,
+ getIdentifierWildcardsFromString,
+ getIdentifierWildcardsFromNode,
+ getStringWildcardsFromString,
patternToRegExp,
}
}
diff --git a/packages/core/tools/babel.plugins.js b/packages/core/tools/babel.plugins.js
index 4959e3d..2a8dbcb 100644
--- a/packages/core/tools/babel.plugins.js
+++ b/packages/core/tools/babel.plugins.js
@@ -1,6 +1,5 @@
module.exports = function plugin() {
const babelEnv = process.env.BABEL_ENV
- console.log('BABEL_ENV', babelEnv)
if (babelEnv !== 'production' && babelEnv !== 'test') {
return {}
diff --git a/packages/core/tools/getAstJson/index.js b/packages/core/tools/getAstJson/index.js
new file mode 100644
index 0000000..9cfcb1a
--- /dev/null
+++ b/packages/core/tools/getAstJson/index.js
@@ -0,0 +1,45 @@
+const fs = require('fs')
+
+const { __internal } = require('../../dist/index')
+
+const print = console.log
+
+const defaultParser = 'python'
+const userParser = process.argv[2]
+
+if (userParser === undefined) {
+ print('Using default parser:', defaultParser)
+} else {
+ print('Using parser:', userParser)
+}
+
+const parserName = userParser ?? defaultParser
+
+const parserSettings = __internal.parserSettingsMap[parserName]()
+
+const runtime = async () => {
+ await parserSettings?.init()
+ print('Parser loaded')
+
+ const filePathWithSourceCode = `${__dirname}/code.txt`
+ const jsonOutputFilePath = `${__dirname}/${parserName}.json`
+
+ const parseFile = () => {
+ const content = fs.readFileSync(filePathWithSourceCode).toString()
+
+ try {
+ const ast = parserSettings.parseCode(content)
+
+ fs.writeFileSync(jsonOutputFilePath, JSON.stringify(ast, null, 2))
+ print('Parsed correctly')
+ } catch (e) {
+ console.error('Parse error', e)
+ }
+ }
+
+ fs.watchFile(filePathWithSourceCode, { interval: 500 }, parseFile)
+
+ parseFile()
+}
+
+runtime()
diff --git a/packages/core/tsconfig.build.json b/packages/core/tsconfig.build.json
index e15ccef..e0f99b7 100644
--- a/packages/core/tsconfig.build.json
+++ b/packages/core/tsconfig.build.json
@@ -1,11 +1,11 @@
{
"extends": "./tsconfig.json",
- "include": ["src"],
+ "include": ["src", "./declarations.d.ts"],
"compilerOptions": {
"paths": {},
"declaration": true,
"outDir": "dist",
"noEmit": false,
"emitDeclarationOnly": true
- },
-}
\ No newline at end of file
+ }
+}
diff --git a/packages/core/tsconfig.json b/packages/core/tsconfig.json
index 4e5ba5f..d4888f7 100644
--- a/packages/core/tsconfig.json
+++ b/packages/core/tsconfig.json
@@ -3,19 +3,18 @@
"compilerOptions": {
"baseUrl": "./",
"paths": {
- "/*": [
- "src/*"
- ]
+ "/*": ["src/*"]
},
"skipLibCheck": true,
"declaration": false,
- "noEmit": true
+ "noEmit": true,
+ "resolveJsonModule": true
},
"exclude": [
- "__tests__/**/__fixtures__",
- "__tests__/**/__fixturesOther__",
+ "__tests__/__fixtures__",
+ "__tests__/__fixturesOther__",
"dist",
"node_modules",
"tools/*.js"
]
-}
\ No newline at end of file
+}
diff --git a/packages/eslint/README.md b/packages/eslint/README.md
index 192149a..cd5e365 100644
--- a/packages/eslint/README.md
+++ b/packages/eslint/README.md
@@ -1,34 +1,77 @@
+
+
-
-
+
+
- Home Page |
- Docs |
- Roadmap |
- Mission |
- Playground
+ Website •
+ Docs •
+ Roadmap •
+ Mission •
+ Playground
-# CodeQue - structural search engine for JavaScript and TypeScript
+Find and lint complex code patterns effortlessly
+
+---
+
+# What is CodeQue?
+
+CodeQue is semantic code search engine that understands the code syntax.
+
+It matches code structurally which makes it excellent for more complex queries.
+
+Query language offers wildcards, partial matching and ignores code formatting.
+
+Structural code search is available for JavaScript, TypesScript, HTML, CSS, Python, Lua, C# and more soon.
+
+Text code search with handy wildcards is available for **every language** and covers common regex search use cases.
+
+Give it a try in
+ playground
+
+Just paste code snippet to start searching, no installation needed!
+
+**Integrations**
+
+CodeQue is available as:
+
+- [VSCode extension](https://marketplace.visualstudio.com/items?itemName=CodeQue.codeque) for delightful code search and navigation experience.
+- [ESLint integration](https://www.npmjs.com/package/@codeque/eslint-plugin) for creating custom linting rules in zero time.
+- [CLI tool](https://www.npmjs.com/package/@codeque/cli) for searching code and more including headless environments.
+
+All CodeQue tools work offline hence code never leaves your local environment.
+
+**Coming soon**
+
+CodeQue will be soon available as:
+
+- Duplicated code identification
+- Batch code refactoring
+- Advanced ESLint rule creator
+
+🔔 Get notified about updates 🔔
-CodeQue is code search engine that understands the code syntax.
+
-It matches structure rather than plain text, which makes it very effective for complex queries.
+
-It's available as [CLI](https://www.npmjs.com/package/@codeque/cli), [Visual Studio Code Extension](https://codeque.co/r/vsc), and ESLint plugin.
+
-## ESLint plugin
+## ESLint integration 💅
Using CodeQue ESLint plugin you can create your own custom linting rules in zero time.
Custom ESLint rules can help execute on long-term refactors or prevent introducing codebase specific bugs or bad patterns.
-Rules can replace your decision log and help standardizing coding conventions across the project.
+Rules can replace your decision log and help standardizing coding conventions across the project or organization.
-CodeQue is a no-brainier for any team willing to improve their codebase quality.
+CodeQue ESLint integration is a no-brainier for any team willing to improve their codebase quality.
+
+
## Installation
@@ -36,54 +79,65 @@ CodeQue is a no-brainier for any team willing to improve their codebase quality.
yarn add --dev @codeque/eslint-plugin
```
-> `@codeque/eslint-plugin` is now in `beta` and only supports `@typescript-eslint/parser` parser. `@babel/eslint-parser` and `Esprima` will be supported soon.
+CodeQue supports all parsers officially supported by ESLint
+
+- [Espree](https://github.com/eslint/espree)
+- [Esprima](https://www.npmjs.com/package/esprima)
+- [@babel/eslint-parser](https://www.npmjs.com/package/@babel/eslint-parser)
+- [@typescript-eslint/parser](https://www.npmjs.com/package/@typescript-eslint/parser)
-> `@codeque/eslint-plugin` was tested with `ESLint` in versions `7.x` and `8.x`.
+👉 Open GitHub issue to [request parser support](https://github.com/codeque-co/codeque/issues)
## Configuration
-Add `@codeque` plugin to plugins list in your `.eslintrc`
+Add `@codeque` plugin to plugins list in your `.eslintrc`.
-```js
-{
- plugins: ["@codeque"]
-}
-```
+And then add a definition for one of the rules:
-And add a definition for one of the rules: `@codeque/error` or `@codeque/warning`.
+- `@codeque/error`
+- `@codeque/warning`
There are two rules, so you can configure them to report errors or warnings.
Each rule should be provided with a list of rule config objects with CodeQue queries.
-Learn mode about writing queries from [CodeQue docs](https://codeque.co/docs)
+Learn more about writing queries from [CodeQue docs](https://codeque.co/docs)
-```js
+```json
{
- rules: [
- "@codeque/error": ["error", [
- {
- "query": "throw new Error()",
- mode: "include",
- message: "Use only project defined error classes.",
- },
- ]],
- "@codeque/warning": ["warn", [
- {
- "query": "import $$$ from 'lodash';",
- mode: "include",
- message: "Prefer to import lodash functions from separate packages like 'lodash.debounce'",
- },
- ]]
- ]
+ "plugins": ["@codeque"],
+ "rules": {
+ "@codeque/error": [
+ "error",
+ [
+ {
+ "query": "fetchData()",
+ "mode": "exact",
+ "message": "Using fetchData() without parameters causes app crash!"
+ }
+ ]
+ ],
+ "@codeque/warning": [
+ "warn",
+ [
+ {
+ "query": "import $$$ from 'lodash';",
+ "mode": "include",
+ "message": "Prefer to import lodash functions from separate packages like 'lodash.debounce'"
+ }
+ ]
+ ]
+ }
}
```
+The above configuration
+
+- rises an error when `fetchData()` function is called without parameters
+- reports a warning when utility is imported from main `lodash` package
+
-
-
-
-
+
> If your config seems too big, feel free to extract your set of rules to a separate file. Change your `.eslintrc` to JS file and import rules from a separate file.
@@ -93,12 +147,13 @@ Learn mode about writing queries from [CodeQue docs](https://codeque.co/docs)
Minimal rule config object should contain just `query` key
```js
-({
- query: "someCode"
+;({
+ query: 'someCode',
})
```
The default settings are:
+
- `mode` - `include`
- `message` - `Restricted code pattern`
- `caseInsensitive` - `true`
@@ -111,19 +166,281 @@ All configuration options
type RuleConfig = {
query: string // Content of the query
mode: 'exact' | 'include' | 'include-with-order' // CodeQue search mode
- message: string // Error message to display
+ message: string // Error message to display
caseInsensitive: boolean // Whether query should perform matches case insensitively
includeFiles: string[] | undefined // list of glob patterns to indicate files against which given rule should be executed
excludeFiles: string[] // list of glob patterns to indicate files against which given rule should not be executed
}
```
-## Debugging performance
+## Rule examples
+
+CodeQue is general purpose code search tool. The examples list could be endless. Here are some of them for you to get a glimpse of what's possible. Those are relatively simple, you will definitely find some more complex during day to day work.
+
+> Don't know how to write a query? [Open an issue on GitHub](https://github.com/codeque-co/codeque/issues) !
+
+### All usages of `console` object
+
+Searching for console logs, warnings, errors is quite simple use-case and can be achieved using traditional tools, but It's for you to warm up 😁
+
+This rule warns about all places in the code that can output some (usually unwanted) logs.
+
+
+Show configuration
+
+```json
+{
+ "rules": {
+ "@codeque/warning": [
+ "warn",
+ [
+ {
+ "query": "console.$$()",
+ "mode": "include",
+ "message": "Prefer to use 'Logger' util."
+ }
+ ]
+ ]
+ }
+}
+```
+
+
+
+
+
+
+
+### Library specific issues
+
+Third party code not always work as expected. Whenever you spot a problem, add custom eslint rule to spread that knowledge across your team.
+
+The rule warns against using `disabled` property on `SomeLibComponent`, and suggest using not documented `isDisabled` prop instead.
+
+
+Show configuration
+
+```json
+{
+ "rules": {
+ "@codeque/warning": [
+ "warn",
+ [
+ {
+ "query": " ",
+ "mode": "include",
+ "message": "'disabled' property does not work as expected. Use 'isDisabled' instead",
+ "includeFiles": ["**/*.tsx"]
+ }
+ ]
+ ]
+ }
+}
+```
+
+
+
+
+
+
+
+### Unstable hook reference
+
+Some 3rd party hooks are not implemented correctly and return non-memoized variables.
+
+In this rule we rise an error when `confirm` callback from `useAsyncDialog` is used as an item of `useCallback` dependency array.
+
+This is interesting example that links together two statements in the same code block, that does not necessarily have to directly follow each other.
+
+
+Show configuration
+
+```json
+{
+ "rules": {
+ "@codeque/error": [
+ "error",
+ [
+ {
+ "query": "const { confirm } = useAsyncDialog(); const $$ = useCallback($$$, [confirm]);",
+ "mode": "include",
+ "message": "'confirm' is known to be unstable. Using it in hook dependency array can cause render loop"
+ }
+ ]
+ ]
+ }
+}
+```
+
+
+
+
+
+
+
+### React bad patterns
+
+First rule restricts usage of object literal as a prop. Object literal could be extracted to variable in upper scope or memoized to avoid performance issues.
+
+Second rule restricts places where a given array is mapped directly in JSX. It could be memoized to make the array reference stable and reduce re-renders.
+
+
+Show configuration
+
+```json
+{
+ "rules": {
+ "@codeque/error": [
+ "error",
+ [
+ {
+ "query": "<$$ $$={{}} />",
+ "mode": "include",
+ "message": "Don't use object literal in JSX props",
+ "includeFiles": ["**/*.tsx"]
+ },
+ {
+ "query": "<$$ $$={$$$.map(() => ($$$))} />",
+ "mode": "include",
+ "message": "Don't use map directly in JSX, memoize map result instead",
+ "includeFiles": ["**/*.tsx"]
+ }
+ ]
+ ]
+ }
+}
+```
+
+
+
+
+
+
+
+## What about performance?
+
+Usually rules works very fast unless they are too generic.
+
+CodeQue performs shallow matching based on strings in query, so it can filter out most of the source files before AST comparison even starts.
+
+Query that contains wildcards only, eg. `$$.$$()` will be looked for in every file, as query does not include any specific characters sequence.
+
+However query `console.$$()` would match only on files that contains `console` string somewhere within it's contents.
+
+Remember to be as specific as possible and use file filtering options eg. to not run JSX rules on `*.js` files.
+
+CodeQue will run faster for more specific patterns that occurs rarely in the codebase. If pattern is very common, it would have to do more comparisons, hence would run longer.
+
+### Debugging performance
You can check performance of your CodeQue ESLint rules by running
```sh
-TIMING=1 CODEQUE_DEBUG=true yarn YOUR_LINT_SCRIPT
+TIMING=ALL CODEQUE_DEBUG=true yarn YOUR_LINT_SCRIPT
+```
+
+All the tests below were run on Typescript codebase with ~4000 source files.
+
+It's not a benchmark, it's an example to give a reference. Results were not averaged.
+
+#### Linting specific code patterns
+
+Linting code pattern specific to your code base is what CodeQue eslint integration is build for.
+
+Rule from examples section that captures issue with unstable hook reference occurs rare in the codebase, but can prevent various important bugs.
+
+```
+const { confirm } = useAsyncDialog();
+const $$ = useCallback($$$, [confirm]);
+```
+
+For 12 occurrences it runs only ~60ms
+
+```sh
+✖ 12 problems (0 errors, 12 warnings)
+
+Rule | Time (ms) | Relative
+:----------------|----------:|--------:
+@codeque/warning | 64.425 | 100.0%
+```
+
+You should strive to eliminate that pattern, so assuming you've fixed all places, the rule takes ~30ms
+
+```sh
+0 problems (0 errors, 0 warnings)
+
+Rule | Time (ms) | Relative
+:----------------|----------:|--------:
+@codeque/warning | 28.286 | 100.0%
+```
+
+And for new introduction of the pattern while you code, it will be captures in ~30ms
+
+```sh
+✖ 1 problems (0 errors, 1 warning)
+
+Rule | Time (ms) | Relative
+:----------------|----------:|--------:
+@codeque/warning | 30.553 | 100.0%
+```
+
+It's not much comparing to the value it gives.
+
+Consider how much time it would take to implement such rule with standard approach. No one has budget for that and instead time will be spend on fixing bugs.
+
+#### Capturing restricted imports
+
+Here is the comparison of `no-restricted-imports` ESLint rule with CodeQue rule.
+
+Both restricts importing `useCallback` from `react`.
+
+CodeQue query is using `include` mode.
+
+```ts
+import { useCallback } from 'react'
```
-> Use TIMING=all to list all ESLint rules.
\ No newline at end of file
+Execution takes similar amount of time for both approaches.
+
+```sh
+✖ 648 problems (0 errors, 648 warnings)
+
+Rule | Time (ms) | Relative
+:---------------------|----------:|--------:
+@codeque/warning | 38.700 | 56.1%
+no-restricted-imports | 30.239 | 43.9%
+```
+
+#### Restricting console usage
+
+The performance result of ESLint `no-console` rule comparing to CodeQue `console.$$()` query on TypeScript codebase with ~4000 source files.
+
+CodeQue is 4 times slower for this use case, but it's still only ~80ms for ~4000 source files!
+
+```sh
+✖ 404 problems (0 errors, 404 warnings)
+
+Rule | Time (ms) | Relative
+:----------------|----------:|--------:
+@codeque/warning | 81.267 | 79.1%
+no-console | 21.482 | 20.9%
+```
+
+## Telemetry
+
+Plugin collects completely anonymous telemetry that helps me get insights about usage.
+
+It's implemented using `applicationinsights` and you can easily opt-out.
+
+Learn more about [telemetry](https://codeque.co/docs/telemetry#es-lint-plugin)
+
+
+
+## Support and feedback
+
+Feel free to use [Github Issues](https://github.com/codeque-co/codeque/issues)
+to
+
+- ask for help with writing a query
+- report a bug or doubt
+- suggest feature or improvement
diff --git a/packages/eslint/__tests__/JavaScript/javaScriptParsers.test.ts b/packages/eslint/__tests__/JavaScript/javaScriptParsers.test.ts
new file mode 100644
index 0000000..04c581a
--- /dev/null
+++ b/packages/eslint/__tests__/JavaScript/javaScriptParsers.test.ts
@@ -0,0 +1,436 @@
+import { rules } from '../../src/index'
+import { RuleOption } from '../../src/types'
+
+const codeWithoutMatches = `
+ // Different order of keys
+ const obj = {
+ prop10: 'World',
+ prop8: [
+ { value: 'C', id: 3 },
+ { id: 4, value: 'D' },
+ ],
+ }
+
+ {
+ const a = 1 === 0
+ class A {}
+ }
+
+ const Comp = () => (not-test
);
+
+ \`pre-not\${value}
+
+ post\`
+`
+
+const codeWithMatches = `
+ const obj = {
+ prop1: 'Hello',
+ prop2: 42,
+ prop3: true,
+ prop4: [
+ { name: 'John', age: 30 },
+ { name: 'Jane', age: 25 },
+ ],
+ prop5: {
+ prop6: [
+ { id: 1, value: 'A' },
+ { id: 2, value: 'B' },
+ ],
+ prop7: {
+ prop8: [
+ { id: 3, value: 'C' },
+ { id: 4, value: 'D' },
+ ],
+ prop10: 'World',
+ },
+ },
+ }
+
+ {
+ const a = 1 === 0
+ fn(obj)
+ fn(newobj)
+ class A {}
+ }
+
+ const result = obj.key.fn()
+
+ functionCall(obj.key.fn())
+
+ obj.prop1.prop2.prop3
+
+ const Comp = () => (test
);
+
+ \`pre\${value}
+
+ post\`
+
+`
+
+describe('JavaScript code samples', () => {
+ describe('nested exact query', () => {
+ const options: [Array] = [
+ [
+ {
+ query: `({
+ prop8: [
+ { id: 3, value: 'C' },
+ { id: 4, value: 'D' },
+ ],
+ prop10: 'World',
+ })`,
+ mode: 'exact',
+ },
+ ],
+ ]
+
+ global.ruleTester.run('@codeque', rules.error, {
+ valid: [
+ {
+ code: codeWithoutMatches,
+ options,
+ },
+ ],
+ invalid: [
+ {
+ code: codeWithMatches,
+ options,
+ errors: [
+ {
+ message: 'Restricted code pattern',
+ line: 15,
+ column: 14,
+ endLine: 21,
+ endColumn: 8,
+ },
+ ],
+ },
+ ],
+ })
+ })
+
+ describe('nested include query', () => {
+ const options: [Array] = [
+ [
+ {
+ query: `({
+ prop3: true,
+ prop4: [
+ { age: 25 },
+ ],
+ prop5: {
+ prop7: {
+ prop8: [
+ { id: 3, },
+ ],
+ },
+ },
+ })`,
+ mode: 'include',
+ },
+ ],
+ ]
+
+ global.ruleTester.run('@codeque', rules.error, {
+ valid: [
+ {
+ code: codeWithoutMatches,
+ options,
+ },
+ ],
+ invalid: [
+ {
+ code: codeWithMatches,
+ options,
+ errors: [
+ {
+ message: 'Restricted code pattern',
+ line: 2,
+ column: 15,
+ endLine: 23,
+ endColumn: 4,
+ },
+ ],
+ },
+ ],
+ })
+ })
+
+ describe('nested include-with-order query', () => {
+ const options: [Array] = [
+ [
+ {
+ query: `({
+ prop8: [
+ { id: 3, value: 'C' },
+ { id: 4 },
+ ],
+ prop10: 'World',
+ })`,
+ mode: 'include-with-order',
+ },
+ ],
+ ]
+
+ global.ruleTester.run('@codeque', rules.error, {
+ valid: [
+ {
+ code: codeWithoutMatches,
+ options,
+ },
+ ],
+ invalid: [
+ {
+ code: codeWithMatches,
+ options,
+ errors: [
+ {
+ message: 'Restricted code pattern',
+ line: 15,
+ column: 14,
+ endLine: 21,
+ endColumn: 8,
+ },
+ ],
+ },
+ ],
+ })
+ })
+
+ describe('multiline include query', () => {
+ const options: [Array] = [
+ [
+ {
+ query: `
+ const obj = {}
+
+ {
+ fn(obj)
+ }
+ `,
+ mode: 'include',
+ },
+ ],
+ ]
+
+ global.ruleTester.run('@codeque', rules.error, {
+ valid: [
+ {
+ code: codeWithoutMatches,
+ options,
+ },
+ ],
+ invalid: [
+ {
+ code: codeWithMatches,
+ options,
+ errors: [
+ {
+ message: 'Restricted code pattern',
+ line: 2,
+ column: 3,
+ endLine: 30,
+ endColumn: 4,
+ },
+ ],
+ },
+ ],
+ })
+ })
+
+ describe('multiline include query with identifier alias', () => {
+ const options: [Array] = [
+ [
+ {
+ query: `
+ const $$_ref1 = {}
+
+ {
+ fn(new$$_ref1_)
+ }
+ `,
+ mode: 'include',
+ },
+ ],
+ ]
+
+ global.ruleTester.run('@codeque', rules.error, {
+ valid: [
+ {
+ code: codeWithoutMatches,
+ options,
+ },
+ ],
+ invalid: [
+ {
+ code: codeWithMatches,
+ options,
+ errors: [
+ {
+ message: 'Restricted code pattern',
+ line: 2,
+ column: 3,
+ endLine: 30,
+ endColumn: 4,
+ },
+ ],
+ },
+ ],
+ })
+ })
+
+ describe('multiline include query with nodes tree wildcard alias', () => {
+ const options: [Array] = [
+ [
+ {
+ query: `
+ const result = $$$_chainExp
+
+ functionCall($$$_chainExp)
+ `,
+ mode: 'include',
+ },
+ ],
+ ]
+
+ global.ruleTester.run('@codeque', rules.error, {
+ valid: [
+ {
+ code: codeWithoutMatches,
+ options,
+ },
+ ],
+ invalid: [
+ {
+ code: codeWithMatches,
+ options,
+ errors: [
+ {
+ message: 'Restricted code pattern',
+ line: 32,
+ column: 3,
+ endLine: 34,
+ endColumn: 29,
+ },
+ ],
+ },
+ ],
+ })
+ })
+
+ describe('query with JSX', () => {
+ const options: [Array] = [
+ [
+ {
+ query: `
+ const Comp = () => test
+ `,
+ mode: 'include',
+ },
+ ],
+ ]
+
+ global.ruleTester.run('@codeque', rules.error, {
+ valid: [
+ {
+ code: codeWithoutMatches,
+ options,
+ },
+ ],
+ invalid: [
+ {
+ code: codeWithMatches,
+ options,
+ errors: [
+ {
+ message: 'Restricted code pattern',
+ line: 38,
+ column: 3,
+ endLine: 38,
+ endColumn: 40,
+ },
+ ],
+ },
+ ],
+ })
+ })
+
+ describe('query with multiline template string', () => {
+ const options: [Array] = [
+ [
+ {
+ query: `\`pre
+ \${value}
+
+ post\`
+ `,
+ mode: 'include',
+ },
+ ],
+ ]
+
+ global.ruleTester.run('@codeque', rules.error, {
+ valid: [
+ {
+ code: codeWithoutMatches,
+ options,
+ },
+ ],
+ invalid: [
+ {
+ code: codeWithMatches,
+ options,
+ errors: [
+ {
+ message: 'Restricted code pattern',
+ line: 40,
+ column: 3,
+ endLine: 42,
+ endColumn: 8,
+ },
+ ],
+ },
+ ],
+ })
+ })
+
+ if (!(global.ruleTester as any).testerConfig.parser.includes('esprima')) {
+ describe('optional chaining query that matches normal chaining', () => {
+ const options: [Array] = [
+ [
+ {
+ query: `
+ obj?.prop1?.prop2?.prop3
+ `,
+ mode: 'include',
+ },
+ ],
+ ]
+
+ global.ruleTester.run('@codeque', rules.error, {
+ valid: [
+ {
+ code: codeWithoutMatches,
+ options,
+ },
+ ],
+ invalid: [
+ {
+ code: codeWithMatches,
+ options,
+ errors: [
+ {
+ message: 'Restricted code pattern',
+ line: 36,
+ column: 3,
+ endLine: 36,
+ endColumn: 24,
+ },
+ ],
+ },
+ ],
+ })
+ })
+ }
+})
diff --git a/packages/eslint/__tests__/TypeScript/typeScriptParsers.test.ts b/packages/eslint/__tests__/TypeScript/typeScriptParsers.test.ts
new file mode 100644
index 0000000..e6226da
--- /dev/null
+++ b/packages/eslint/__tests__/TypeScript/typeScriptParsers.test.ts
@@ -0,0 +1,156 @@
+import { rules } from '../../src/index'
+import { RuleOption } from '../../src/types'
+
+const codeWithoutMatches = `
+
+`
+
+const codeWithMatches = `
+ const a: SomeType = '';
+ let b: SomeType = '';
+ let c: OtherType & { key: SomeType } = '';
+
+ interface B {
+ key: string;
+ key_2?: number;
+ }
+
+ const getInitialValues = (
+ assignment: AssignmentPopulated,
+ ): AssignmentFormValues => {
+ if (!assignment) {
+ return undefined;
+ }
+ };
+`
+
+describe('TypeScript code samples', () => {
+ describe('should match optional interface filed in include mode with query without optional interface', () => {
+ const options: [Array] = [
+ [
+ {
+ query: `
+ interface B {
+ key_2: number;
+ }
+ `,
+ mode: 'include',
+ },
+ ],
+ ]
+
+ global.ruleTester.run('@codeque', rules.error, {
+ valid: [
+ {
+ code: codeWithoutMatches,
+ options,
+ },
+ ],
+ invalid: [
+ {
+ code: codeWithMatches,
+ options,
+ errors: [
+ {
+ message: 'Restricted code pattern',
+ line: 6,
+ column: 3,
+ endLine: 9,
+ endColumn: 4,
+ },
+ ],
+ },
+ ],
+ })
+ })
+
+ describe('Should match type in variable type annotation', () => {
+ const options: [Array] = [
+ [
+ {
+ query: `SomeType`,
+ mode: 'include',
+ },
+ ],
+ ]
+
+ global.ruleTester.run('@codeque', rules.error, {
+ valid: [
+ {
+ code: codeWithoutMatches,
+ options,
+ },
+ ],
+ invalid: [
+ {
+ code: codeWithMatches,
+ options,
+ errors: [
+ {
+ message: 'Restricted code pattern',
+ line: 2,
+ column: 12,
+ endLine: 2,
+ endColumn: 20,
+ },
+ {
+ message: 'Restricted code pattern',
+ line: 3,
+ column: 10,
+ endLine: 3,
+ endColumn: 18,
+ },
+ {
+ message: 'Restricted code pattern',
+ line: 4,
+ column: 29,
+ endLine: 4,
+ endColumn: 37,
+ },
+ ],
+ },
+ ],
+ })
+ })
+
+ describe('should match function declaration with types by query without types', () => {
+ const options: [Array] = [
+ [
+ {
+ query: `
+ const getInitialValues = (
+ assignment,
+ ) => {
+
+ };
+ `,
+ mode: 'include',
+ },
+ ],
+ ]
+
+ global.ruleTester.run('@codeque', rules.error, {
+ valid: [
+ {
+ code: codeWithoutMatches,
+ options,
+ },
+ ],
+ invalid: [
+ {
+ code: codeWithMatches,
+ options,
+ errors: [
+ {
+ message: 'Restricted code pattern',
+ line: 11,
+ column: 3,
+ endLine: 17,
+ endColumn: 5,
+ },
+ ],
+ },
+ ],
+ })
+ })
+})
diff --git a/packages/eslint/__tests__/common/options.test.ts b/packages/eslint/__tests__/common/options.test.ts
new file mode 100644
index 0000000..a04cb12
--- /dev/null
+++ b/packages/eslint/__tests__/common/options.test.ts
@@ -0,0 +1,332 @@
+import { rules } from '../../src/index'
+import { RuleOption } from '../../src/types'
+
+describe('Rule options tests', () => {
+ const rootPath = process.cwd()
+
+ describe('should run config with default error messages', () => {
+ const options: [Array] = [[{ query: `invalidIdentifier` }]]
+
+ global.ruleTester.run('@codeque', rules.error, {
+ valid: [{ code: 'validIdentifier', options }],
+ invalid: [
+ {
+ code: 'invalidIdentifier',
+ options,
+ errors: ['Restricted code pattern'],
+ },
+ ],
+ })
+ })
+
+ describe('should run config with multiple queries', () => {
+ const options: [Array] = [
+ [{ query: `invalidIdentifier` }, { query: 'otherInvalidIdentifier' }],
+ ]
+
+ global.ruleTester.run('@codeque', rules.error, {
+ valid: [{ code: 'validIdentifier', options }],
+ invalid: [
+ {
+ code: 'invalidIdentifier;otherInvalidIdentifier',
+ options,
+ errors: ['Restricted code pattern', 'Restricted code pattern'],
+ },
+ ],
+ })
+ })
+
+ describe('should run config with custom error messages', () => {
+ const options: [Array] = [
+ [
+ { query: `invalidIdentifier` },
+ { query: 'otherInvalidIdentifier', message: "Don't use this code" },
+ ],
+ ]
+
+ global.ruleTester.run('@codeque', rules.error, {
+ valid: [{ code: 'validIdentifier', options }],
+ invalid: [
+ {
+ code: 'invalidIdentifier;otherInvalidIdentifier',
+ options,
+ errors: ['Restricted code pattern', "Don't use this code"],
+ },
+ ],
+ })
+ })
+
+ describe('should run config with include file paths filter', () => {
+ const options: [Array] = [
+ [{ query: `invalidIdentifier`, includeFiles: ['**/includeDir/file.*'] }],
+ ]
+
+ global.ruleTester.run('@codeque', rules.error, {
+ valid: [
+ {
+ code: 'invalidIdentifier',
+ filename: rootPath + '/path/to/dir/file.js',
+ options,
+ },
+ ],
+ invalid: [
+ {
+ code: 'invalidIdentifier',
+ filename: rootPath + '/path/to/includeDir/file.js',
+ options,
+ errors: ['Restricted code pattern'],
+ },
+ ],
+ })
+ })
+
+ describe('should run config with exclude file paths filter', () => {
+ const options: [Array] = [
+ [{ query: `invalidIdentifier`, excludeFiles: ['**/excludeDir/file.*'] }],
+ ]
+
+ global.ruleTester.run('@codeque', rules.error, {
+ valid: [
+ {
+ code: 'invalidIdentifier',
+ filename: rootPath + '/path/to/excludeDir/file.js',
+ options,
+ },
+ ],
+ invalid: [
+ {
+ code: 'invalidIdentifier',
+ filename: rootPath + '/path/to/dir/file.js',
+ options,
+ errors: ['Restricted code pattern'],
+ },
+ ],
+ })
+ })
+
+ describe('should run config with include and exclude file paths filter', () => {
+ const options: [Array] = [
+ [
+ {
+ query: `invalidIdentifier`,
+ excludeFiles: ['**/excludeDir/**/file.*'],
+ includeFiles: ['**/includeDir/**/file.*'],
+ },
+ ],
+ ]
+
+ global.ruleTester.run('@codeque', rules.error, {
+ valid: [
+ {
+ code: 'invalidIdentifier',
+ filename: rootPath + '/includeDir/excludeDir/file.js',
+ options,
+ },
+ {
+ code: 'invalidIdentifier',
+ filename: rootPath + '/otherDir/excludeDir/file.js',
+ options,
+ },
+ ],
+ invalid: [
+ {
+ code: 'invalidIdentifier',
+ filename: rootPath + '/includeDir/otherDir/file.js',
+ options,
+ errors: ['Restricted code pattern'],
+ },
+ ],
+ })
+ })
+
+ describe('should run config with queries with different search modes', () => {
+ describe('include mode', () => {
+ const options: [Array] = [
+ [
+ {
+ query: `({ key: 'value' })`,
+ mode: 'include',
+ },
+ {
+ query: `({ key: 'value' })`,
+ // assert default include mode
+ },
+ ],
+ ]
+
+ global.ruleTester.run('@codeque', rules.error, {
+ valid: [
+ {
+ code: `const obj = { kkk: 'value' }`,
+ options,
+ },
+ ],
+ invalid: [
+ {
+ code: `const obj = { key: 'value', key2: 0 }`,
+ options,
+ errors: ['Restricted code pattern', 'Restricted code pattern'],
+ },
+ ],
+ })
+ })
+
+ describe('exact mode', () => {
+ const options: [Array] = [
+ [
+ {
+ query: `({ key: 'value' })`,
+ mode: 'exact',
+ },
+ ],
+ ]
+
+ global.ruleTester.run('@codeque', rules.error, {
+ valid: [
+ {
+ code: `const obj = { kkk: 'value' }`,
+ options,
+ },
+ {
+ code: `const obj = { key: 'value', key2: 0 }`,
+ options,
+ },
+ ],
+ invalid: [
+ {
+ code: `const obj = { key: 'value' }`,
+ options,
+ errors: ['Restricted code pattern'],
+ },
+ ],
+ })
+ })
+
+ describe('include-with-order mode', () => {
+ const options: [Array] = [
+ [
+ {
+ query: `({ key1: 'value', key2: 'value2' })`,
+ mode: 'include-with-order',
+ },
+ ],
+ ]
+
+ global.ruleTester.run('@codeque', rules.error, {
+ valid: [
+ {
+ code: `const obj = { key1: 'value' }`,
+ options,
+ },
+ {
+ code: `const obj = { key2: 'value2', key1: 'value' }`,
+ options,
+ },
+ ],
+ invalid: [
+ {
+ code: `const obj = { key1: 'value', key2: 'value2' }`,
+ options,
+ errors: ['Restricted code pattern'],
+ },
+ ],
+ })
+ })
+
+ describe('text (unsupported)', () => {
+ const options: [Array] = [
+ [
+ {
+ query: `key1: 'value'`,
+ mode: 'text',
+ },
+ ],
+ ]
+
+ expect(() => {
+ // @ts-ignore we don't need all props for this test
+ rules.error.create({
+ options: options,
+ // @ts-ignore we don't need all props for this test
+ getSourceCode: jest.fn(() => ({ text: '' })),
+ getPhysicalFilename: jest.fn(),
+ getCwd: jest.fn(),
+ parserPath:
+ 'project/node_modules/@typescript-eslint/parser/dist/index.js',
+ })
+ }).toThrowError('"Text" search mode is not supported.')
+ })
+ })
+
+ describe('should run config with case sensitive and insensitive queries', () => {
+ describe('case sensitive', () => {
+ const options: [Array] = [
+ [
+ {
+ query: `invalidIdentifier`,
+ mode: 'include',
+ caseInsensitive: false,
+ },
+ ],
+ ]
+
+ global.ruleTester.run('@codeque', rules.error, {
+ valid: [
+ {
+ code: `validIdentifier`,
+ options,
+ },
+ {
+ code: `invalididentifier`,
+ options,
+ },
+ ],
+ invalid: [
+ {
+ code: `invalidIdentifier`,
+ options,
+ errors: ['Restricted code pattern'],
+ },
+ ],
+ })
+ })
+
+ describe('case insensitive', () => {
+ const options: [Array] = [
+ [
+ {
+ query: `invalidIdentifier`,
+ mode: 'include',
+ caseInsensitive: true,
+ },
+ {
+ query: `invalidIdentifier`,
+ mode: 'include',
+ // assert default case insensitive
+ },
+ ],
+ ]
+
+ global.ruleTester.run('@codeque', rules.error, {
+ valid: [
+ {
+ code: `validIdentifier`,
+ options,
+ },
+ ],
+ invalid: [
+ {
+ code: `invalididentifier`,
+ options,
+ errors: ['Restricted code pattern', 'Restricted code pattern'],
+ },
+ {
+ code: `invalidIdentifier`,
+ options,
+ errors: ['Restricted code pattern', 'Restricted code pattern'],
+ },
+ ],
+ })
+ })
+ })
+})
diff --git a/packages/eslint/__tests__/utils.test.ts b/packages/eslint/__tests__/common/utils.test.ts
similarity index 88%
rename from packages/eslint/__tests__/utils.test.ts
rename to packages/eslint/__tests__/common/utils.test.ts
index f335825..a37c714 100644
--- a/packages/eslint/__tests__/utils.test.ts
+++ b/packages/eslint/__tests__/common/utils.test.ts
@@ -1,4 +1,4 @@
-import { extractParserNameFromResolvedPath } from '../src/utils'
+import { extractParserNameFromResolvedPath } from '../../src/utils'
it('should extract parser name from file path', () => {
const parserWithOrg = '@typescript-eslint/parser'
diff --git a/packages/eslint/declarations.d.ts b/packages/eslint/declarations.d.ts
new file mode 100644
index 0000000..b1d2b07
--- /dev/null
+++ b/packages/eslint/declarations.d.ts
@@ -0,0 +1,7 @@
+import { RuleTester } from 'eslint'
+declare global {
+ //eslint-disable-next-line no-var
+ var ruleTester: RuleTester
+}
+
+declare module 'is-ci'
diff --git a/packages/eslint/jest.config.js b/packages/eslint/jest.config.js
index 58ef380..8a6f932 100644
--- a/packages/eslint/jest.config.js
+++ b/packages/eslint/jest.config.js
@@ -1,25 +1,74 @@
-const { pathsToModuleNameMapper } = require('ts-jest')
-const fs = require('fs')
-
-const tsConfig = JSON.parse(
- fs
- .readFileSync(__dirname + '/tsconfig.json')
- .toString()
- .replace(/^(\s)*\/\//gm, '')
- .replace(/\/\*.+?\*\//gm, ''),
-)
-
-module.exports = {
+const sharedConfig = {
preset: 'ts-jest',
testEnvironment: 'node',
- moduleNameMapper: pathsToModuleNameMapper(tsConfig.compilerOptions.paths, {
- prefix: '',
- }),
+ setupFiles: ['/jest/jest.shared.setup.ts'],
+}
+
+module.exports = {
testPathIgnorePatterns: [
'__fixtures__',
'__fixturesOther__',
'ts-dist',
'utils.ts',
],
- setupFiles: ['./jest.setup.js'],
+ projects: [
+ {
+ displayName: { name: 'common', color: 'white' },
+ ...sharedConfig,
+ setupFiles: [
+ ...sharedConfig.setupFiles,
+ '/jest/jest.common.setup.ts',
+ ],
+ testMatch: ['/__tests__/common/**/*.test.ts'],
+ },
+ {
+ displayName: { name: 'typescript-eslint-parser', color: 'magenta' },
+ ...sharedConfig,
+ setupFiles: [
+ ...sharedConfig.setupFiles,
+ '/jest/jest.typescript-eslint-parser.setup.ts',
+ ],
+ testMatch: [
+ '/__tests__/JavaScript/**/*.test.ts',
+ '/__tests__/TypeScript/**/*.test.ts',
+ '/__tests__/common/options.test.ts',
+ ],
+ },
+ {
+ displayName: { name: 'babel-eslint-parser', color: 'yellow' },
+ ...sharedConfig,
+ setupFiles: [
+ ...sharedConfig.setupFiles,
+ '/jest/jest.babel-eslint-parser.setup.ts',
+ ],
+ testMatch: [
+ '/__tests__/JavaScript/**/*.test.ts',
+ '/__tests__/common/options.test.ts',
+ ],
+ },
+ {
+ displayName: { name: 'esprima', color: 'gray' },
+ ...sharedConfig,
+ setupFiles: [
+ ...sharedConfig.setupFiles,
+ '/jest/jest.esprima.setup.ts',
+ ],
+ testMatch: [
+ '/__tests__/JavaScript/**/*.test.ts',
+ '/__tests__/common/options.test.ts',
+ ],
+ },
+ {
+ displayName: { name: 'espree', color: 'blue' },
+ ...sharedConfig,
+ setupFiles: [
+ ...sharedConfig.setupFiles,
+ '/jest/jest.espree.setup.ts',
+ ],
+ testMatch: [
+ '/__tests__/JavaScript/**/*.test.ts',
+ '/__tests__/common/options.test.ts',
+ ],
+ },
+ ],
}
diff --git a/packages/eslint/jest.setup.js b/packages/eslint/jest.setup.js
deleted file mode 100644
index b1e2bd6..0000000
--- a/packages/eslint/jest.setup.js
+++ /dev/null
@@ -1 +0,0 @@
-process.env.NODE_ENV = 'test'
diff --git a/packages/eslint/jest/jest.babel-eslint-parser.setup.ts b/packages/eslint/jest/jest.babel-eslint-parser.setup.ts
new file mode 100644
index 0000000..3b62c93
--- /dev/null
+++ b/packages/eslint/jest/jest.babel-eslint-parser.setup.ts
@@ -0,0 +1,17 @@
+import { RuleTester } from 'eslint'
+
+global.ruleTester = new RuleTester({
+ parser: require.resolve('@babel/eslint-parser'),
+ plugins: ['@codeque'],
+ parserOptions: {
+ requireConfigFile: false,
+ allowImportExportEverywhere: true,
+ babelOptions: {
+ babelrc: false,
+ configFile: false,
+ parserOpts: {
+ plugins: ['jsx'],
+ },
+ },
+ },
+})
diff --git a/packages/eslint/jest/jest.common.setup.ts b/packages/eslint/jest/jest.common.setup.ts
new file mode 100644
index 0000000..c2f3b6e
--- /dev/null
+++ b/packages/eslint/jest/jest.common.setup.ts
@@ -0,0 +1,10 @@
+import { RuleTester } from 'eslint'
+
+global.ruleTester = new RuleTester({
+ parser: require.resolve('@typescript-eslint/parser'),
+ plugins: ['@codeque'],
+ parserOptions: {
+ ecmaVersion: 2020,
+ sourceType: 'module',
+ },
+})
diff --git a/packages/eslint/jest/jest.espree.setup.ts b/packages/eslint/jest/jest.espree.setup.ts
new file mode 100644
index 0000000..379d237
--- /dev/null
+++ b/packages/eslint/jest/jest.espree.setup.ts
@@ -0,0 +1,14 @@
+import { RuleTester } from 'eslint'
+
+global.ruleTester = new RuleTester({
+ parser: require.resolve('espree'),
+ plugins: ['@codeque'],
+ parserOptions: {
+ ecmaVersion: 'latest',
+ ecmaFeatures: {
+ jsx: true,
+ globalReturn: true,
+ impliedStrict: false,
+ },
+ },
+})
diff --git a/packages/eslint/jest/jest.esprima.setup.ts b/packages/eslint/jest/jest.esprima.setup.ts
new file mode 100644
index 0000000..15efa8c
--- /dev/null
+++ b/packages/eslint/jest/jest.esprima.setup.ts
@@ -0,0 +1,9 @@
+import { RuleTester } from 'eslint'
+
+global.ruleTester = new RuleTester({
+ parser: require.resolve('esprima'),
+ plugins: ['@codeque'],
+ parserOptions: {
+ jsx: true,
+ },
+})
diff --git a/packages/eslint/jest/jest.shared.setup.ts b/packages/eslint/jest/jest.shared.setup.ts
new file mode 100644
index 0000000..d95e487
--- /dev/null
+++ b/packages/eslint/jest/jest.shared.setup.ts
@@ -0,0 +1,16 @@
+process.env.NODE_ENV = 'test'
+
+global.performance = {
+ now: jest.fn().mockReturnValue(1),
+} as unknown as Performance
+
+global.console = {
+ ...console,
+ warn: (...inputs) => {
+ if (typeof inputs[0] === 'string' && inputs[0].includes('Browserslist')) {
+ return
+ } else {
+ return console.log('console.warn', ...inputs)
+ }
+ },
+}
diff --git a/packages/eslint/jest/jest.typescript-eslint-parser.setup.ts b/packages/eslint/jest/jest.typescript-eslint-parser.setup.ts
new file mode 100644
index 0000000..5f4794b
--- /dev/null
+++ b/packages/eslint/jest/jest.typescript-eslint-parser.setup.ts
@@ -0,0 +1,14 @@
+import { RuleTester } from 'eslint'
+
+global.ruleTester = new RuleTester({
+ parser: require.resolve('@typescript-eslint/parser'),
+ plugins: ['@codeque'],
+ parserOptions: {
+ ecmaVersion: 2020,
+ sourceType: 'module',
+ ecmaFeatures: {
+ globalReturn: true,
+ jsx: true,
+ },
+ },
+})
diff --git a/packages/eslint/package.json b/packages/eslint/package.json
index 4f9c7ae..1a2bacc 100644
--- a/packages/eslint/package.json
+++ b/packages/eslint/package.json
@@ -1,7 +1,7 @@
{
"name": "@codeque/eslint-plugin",
- "version": "0.0.0-beta.0",
- "description": "Create custom ESLint rules based on code sample(s). Utilizing CodeQue - structural code search engine.",
+ "version": "0.1.2",
+ "description": "Create custom ESLint rules based on code samples. Utilizing CodeQue - structural code search engine.",
"author": "Jakub Mazurek (@jayu) ",
"license": "Sustainable Use License",
"engines": {
@@ -21,14 +21,21 @@
"url": "https://github.com/codeque-co/codeque"
},
"devDependencies": {
+ "@babel/eslint-parser": "^7.21.8",
"@types/jest": "^27.0.3",
+ "@typescript-eslint/parser": "^5.53.0",
"eslint": "^8.34.0",
+ "espree": "^9.5.2",
+ "esprima": "^4.0.1",
"jest": "^27.4.4",
"release-it": "^15.0.0",
"ts-jest": "^27.1.1"
},
"dependencies": {
- "@codeque/core": "^0.4.0"
+ "@codeque/core": "^0.6.1",
+ "applicationinsights": "^2.7.0",
+ "is-ci": "^3.0.1",
+ "node-machine-id": "^1.1.12"
},
"peerDependencies": {
"eslint": "^8.34.0"
@@ -42,7 +49,8 @@
"lint": "eslint --ext .js,.ts src",
"lint:fix": "yarn lint --fix",
"checks": "yarn lint && yarn typecheck && yarn test:circular && yarn test",
- "release": "release-it"
+ "release": "release-it",
+ "postinstall": "node ./dist/scripts/postinstall.js"
},
"keywords": [
"typescript",
diff --git a/packages/eslint/readme-media/console-log.gif b/packages/eslint/readme-media/console-log.gif
new file mode 100644
index 0000000..8cab2f2
Binary files /dev/null and b/packages/eslint/readme-media/console-log.gif differ
diff --git a/packages/eslint/readme-media/disabled-prop.gif b/packages/eslint/readme-media/disabled-prop.gif
new file mode 100644
index 0000000..832d2cf
Binary files /dev/null and b/packages/eslint/readme-media/disabled-prop.gif differ
diff --git a/packages/eslint/readme-media/error-example.png b/packages/eslint/readme-media/error-example.png
deleted file mode 100644
index eec7d50..0000000
Binary files a/packages/eslint/readme-media/error-example.png and /dev/null differ
diff --git a/packages/eslint/readme-media/getting-started.gif b/packages/eslint/readme-media/getting-started.gif
new file mode 100644
index 0000000..d13a08f
Binary files /dev/null and b/packages/eslint/readme-media/getting-started.gif differ
diff --git a/packages/eslint/readme-media/object-literals.gif b/packages/eslint/readme-media/object-literals.gif
new file mode 100644
index 0000000..2d67661
Binary files /dev/null and b/packages/eslint/readme-media/object-literals.gif differ
diff --git a/packages/eslint/readme-media/unstable-hook.gif b/packages/eslint/readme-media/unstable-hook.gif
new file mode 100644
index 0000000..3333671
Binary files /dev/null and b/packages/eslint/readme-media/unstable-hook.gif differ
diff --git a/packages/eslint/readme-media/warning-example.png b/packages/eslint/readme-media/warning-example.png
deleted file mode 100644
index adebe3d..0000000
Binary files a/packages/eslint/readme-media/warning-example.png and /dev/null differ
diff --git a/packages/eslint/src/index.ts b/packages/eslint/src/index.ts
index 4bfd65b..0a4b9be 100644
--- a/packages/eslint/src/index.ts
+++ b/packages/eslint/src/index.ts
@@ -1,6 +1,6 @@
import { createLintCode } from './lintCode'
-const rules = {
+export const rules = {
error: createLintCode('problem'),
warning: createLintCode('suggestion'),
}
diff --git a/packages/eslint/src/lintCode.ts b/packages/eslint/src/lintCode.ts
index a3d75bc..9cb4385 100644
--- a/packages/eslint/src/lintCode.ts
+++ b/packages/eslint/src/lintCode.ts
@@ -1,6 +1,5 @@
import { Rule } from 'eslint'
import {
- Mode,
parseQueries,
__internal,
NotNullParsedQuery,
@@ -13,13 +12,16 @@ import {
ParsedQueryWithSettings,
VisitorsSearchArrayMap,
VisitorsSearchMap,
+ RuleOption,
} from './types'
+
import {
formatQueryParseErrors,
createMultipleSearchFunctionsExecutor,
assertCompatibleParser,
parserNamesMappingsToCodeQueInternal,
} from './utils'
+import { telemetryDisabled, createTelemetryInstance } from './telemetry'
const queriesCache = {} as Record
@@ -31,27 +33,37 @@ let filteringFilePathsTime = 0
const searchTimeForQueries = {} as Record
process.on('beforeExit', () => {
+ const print = console.log
const shouldPrintMetric = process.env.CODEQUE_DEBUG === 'true'
if (shouldPrintMetric) {
- console.log('\nCodeQue debug metrics:\n')
- console.log('preparationTime', preparationTime)
- console.log('shallowSearchTime', shallowSearchTime)
- console.log('preparingVisitorsTime', preparingVisitorsTime)
- console.log('preparingQueriesTime', preparingQueriesTime)
- console.log('filteringFilePathsTime', filteringFilePathsTime)
- console.log('searchTimeForQueries', searchTimeForQueries)
- console.log('')
+ print('\nCodeQue debug metrics:\n')
+ print('preparationTime', preparationTime)
+ print('shallowSearchTime', shallowSearchTime)
+ print('preparingVisitorsTime', preparingVisitorsTime)
+ print('preparingQueriesTime', preparingQueriesTime)
+ print('filteringFilePathsTime', filteringFilePathsTime)
+ print('searchTimeForQueries', searchTimeForQueries)
+ print('')
+ print('Telemetry is', telemetryDisabled ? 'disabled' : 'enabled')
}
})
-export const createLintCode = (type: Rule.RuleMetaData['type']) => ({
+const telemetryReported = {
+ problem: false,
+ suggestion: false,
+ layout: false,
+}
+
+export const createLintCode = (
+ type: NonNullable,
+) => ({
meta: {
type: type,
docs: {
description: 'Lint anything based on code sample(s).',
},
- fixable: 'code',
+ fixable: 'code' as const,
schema: [
{
type: 'array',
@@ -88,19 +100,11 @@ export const createLintCode = (type: Rule.RuleMetaData['type']) => ({
],
},
create: function (context: Rule.RuleContext) {
+ const telemetry = createTelemetryInstance()
const prepStart = performance.now()
const parser = assertCompatibleParser(context.parserPath)
- const settings = context.options[0] as
- | Array<{
- mode?: Mode
- query?: string
- message?: string
- caseInsensitive?: boolean
- includeFiles?: string[]
- excludeFiles?: string[]
- }>
- | undefined
+ const settings = context.options[0] as Array | undefined
if (!settings || settings.length === 0) {
return {}
@@ -112,11 +116,16 @@ export const createLintCode = (type: Rule.RuleMetaData['type']) => ({
const defaultCaseInsensitive = true
const queryCodes = settings.map(({ query }) => query)
+ const searchModes = settings.map(({ mode }) => mode).filter(Boolean)
if (queryCodes.includes(undefined) || queryCodes.includes(null as any)) {
throw new Error('Each setting has to have at least query defined.')
}
+ if (searchModes.includes('text')) {
+ throw new Error('"Text" search mode is not supported.')
+ }
+
const parserSettings =
__internal.parserSettingsMap[
parserNamesMappingsToCodeQueInternal[parser]
@@ -168,6 +177,7 @@ export const createLintCode = (type: Rule.RuleMetaData['type']) => ({
})) as ParsedQueryWithSettings[]
preparingQueriesTime += performance.now() - startPreparingQueries
+
const startFilteringFilePaths = performance.now()
const queriesWithSettingsMatchedFilePath = parsedQueriesWithSettings.filter(
({ includeFiles, excludeFiles }) => {
@@ -232,14 +242,20 @@ export const createLintCode = (type: Rule.RuleMetaData['type']) => ({
searchTimeForQueries[queryCode] = 0
}
- const match = __internal.validateMatch(
+ const matchContext = __internal.createMatchContext()
+ const { match } = __internal.validateMatch(
node,
queryWithSettings.parsedQuery.queryNode,
searchOptions,
+ matchContext,
)
if (match) {
- let matchData = __internal.getMatchFromNode(node, parserSettings)
+ let matchData = __internal.getMatchFromNode(
+ node,
+ parserSettings,
+ matchContext.getAllAliases(),
+ )
if (isMultistatement) {
/**
@@ -310,6 +326,26 @@ export const createLintCode = (type: Rule.RuleMetaData['type']) => ({
preparingVisitorsTime += performance.now() - preparingVisitorsStart
preparationTime += performance.now() - prepStart
- return visitors
+ if (!telemetryReported[type]) {
+ telemetry.reportConfig({
+ ruleType: type === 'problem' ? 'error' : 'warning',
+ queriesCount: queryCodes.length,
+ mode_include:
+ searchModes.includes('include') ||
+ settings.some(({ mode }) => mode === undefined),
+ mode_exact: searchModes.includes('exact'),
+ mode_include_w_order: searchModes.includes('include-with-order'),
+ fileFilters_include: settings.some(
+ ({ includeFiles }) => includeFiles !== undefined,
+ ),
+ fileFilters_exclude: settings.some(
+ ({ excludeFiles }) => excludeFiles !== undefined,
+ ),
+ })
+
+ telemetryReported[type] = true
+ }
+
+ return visitors as unknown as Record void>
},
})
diff --git a/packages/eslint/src/scripts/postinstall.ts b/packages/eslint/src/scripts/postinstall.ts
new file mode 100644
index 0000000..6cb40b2
--- /dev/null
+++ b/packages/eslint/src/scripts/postinstall.ts
@@ -0,0 +1,7 @@
+import { createTelemetryInstance } from '../telemetry'
+
+const isCodeQueRepo = process.cwd().match(/packages(\/|\\)eslint$/g) !== null
+
+if (!isCodeQueRepo) {
+ createTelemetryInstance().reportInstall()
+}
diff --git a/packages/eslint/src/telemetry.ts b/packages/eslint/src/telemetry.ts
new file mode 100644
index 0000000..e3c75e0
--- /dev/null
+++ b/packages/eslint/src/telemetry.ts
@@ -0,0 +1,118 @@
+import { machineIdSync } from 'node-machine-id'
+import fs from 'fs'
+import { createHash } from 'crypto'
+import { defaultClient, setup, dispose } from 'applicationinsights'
+//@ts-ignore
+import isCI from 'is-ci'
+
+type TelemetryModule = {
+ reportConfig: (param: {
+ ruleType: 'error' | 'warning'
+ queriesCount: number
+ mode_include: boolean
+ mode_exact: boolean
+ mode_include_w_order: boolean
+ fileFilters_include: boolean
+ fileFilters_exclude: boolean
+ }) => void
+ reportInstall: () => void
+}
+
+const disabledTelemetryInstance: TelemetryModule = {
+ reportConfig: () => undefined,
+ reportInstall: () => undefined,
+}
+
+function hash(guid: string): string {
+ return createHash('sha256').update(guid).digest('hex')
+}
+
+const getProjectId = () => {
+ const path = process.cwd() + '/package.json'
+
+ try {
+ const packageJSON = fs.readFileSync(path).toString()
+
+ const parsedPackageJSON = JSON.parse(packageJSON)
+
+ return hash(parsedPackageJSON.name)
+ } catch (e) {
+ return null
+ }
+}
+
+export const telemetryDisabled =
+ process.env.CQ_ESLINT_TELEMETRY_DISABLE === 'true' ||
+ process.env.NODE_ENV === 'test'
+
+export const createTelemetryInstance = (): TelemetryModule => {
+ if (telemetryDisabled) {
+ return disabledTelemetryInstance
+ }
+
+ setup(
+ 'InstrumentationKey=8f838c47-7173-4f6c-851a-b012d45d9ad8;IngestionEndpoint=https://eastus-8.in.applicationinsights.azure.com/;LiveEndpoint=https://eastus.livediagnostics.monitor.azure.com/',
+ )
+ .setAutoDependencyCorrelation(false)
+ .setAutoCollectRequests(false)
+ .setAutoCollectPerformance(false, false)
+ .setAutoCollectExceptions(false)
+ .setAutoCollectDependencies(false)
+ .setAutoCollectConsole(false, false)
+ .setUseDiskRetryCaching(false)
+ .setAutoCollectPreAggregatedMetrics(false)
+ .setSendLiveMetrics(false)
+ .setAutoCollectHeartbeat(false)
+ .setAutoCollectIncomingRequestAzureFunctions(false)
+ .setInternalLogging(false, false)
+ .enableWebInstrumentation(false)
+
+ const telemetryClient = defaultClient
+
+ const machineId = machineIdSync()
+ const projectId = getProjectId()
+ const arch = process.arch
+ const platform = process.platform
+ const nodeVersion = process.version
+
+ const commonProps = {
+ machineId,
+ projectId,
+ arch,
+ platform,
+ nodeVersion,
+ isCI,
+ }
+
+ return {
+ reportConfig: (params) => {
+ try {
+ telemetryClient.trackEvent({
+ name: 'eslint:config',
+ properties: {
+ ...commonProps,
+ ...params,
+ },
+ })
+
+ telemetryClient.flush()
+ dispose()
+ } catch (e) {
+ console.error('Failed to report telemetry for config')
+ }
+ },
+ reportInstall: () => {
+ try {
+ telemetryClient.trackEvent({
+ name: 'eslint:install',
+ properties: commonProps,
+ })
+
+ telemetryClient.flush()
+ dispose()
+ } catch (e) {
+ console.error('Failed to report telemetry for install')
+ }
+ },
+ }
+}
diff --git a/packages/eslint/src/types.ts b/packages/eslint/src/types.ts
index 64b9b28..a29e31c 100644
--- a/packages/eslint/src/types.ts
+++ b/packages/eslint/src/types.ts
@@ -1,4 +1,5 @@
import { Mode, NotNullParsedQuery, PoorNodeType } from '@codeque/core'
+
export type ParsedQueryWithSettings = {
parsedQuery: NotNullParsedQuery
mode: Mode
@@ -7,6 +8,16 @@ export type ParsedQueryWithSettings = {
excludeFiles: string[]
includeFiles: string[] | undefined
}
+
+export type RuleOption = {
+ mode?: Mode
+ query?: string
+ message?: string
+ caseInsensitive?: boolean
+ includeFiles?: string[]
+ excludeFiles?: string[]
+}
+
export type SearchFn = (node: PoorNodeType) => void
export type VisitorsSearchMap = Record
export type VisitorsSearchArrayMap = Record>
diff --git a/packages/eslint/src/utils.ts b/packages/eslint/src/utils.ts
index 9589f2e..582e9a9 100644
--- a/packages/eslint/src/utils.ts
+++ b/packages/eslint/src/utils.ts
@@ -1,4 +1,4 @@
-import { ParsedQuery, PoorNodeType } from '@codeque/core'
+import { ParsedQuery, ParserType, PoorNodeType } from '@codeque/core'
import { SearchFn } from './types'
export const formatQueryParseErrors = (queries: [ParsedQuery[], boolean][]) => {
@@ -19,12 +19,35 @@ export const createMultipleSearchFunctionsExecutor =
}
const typescriptEslintParser = '@typescript-eslint/parser' as const
+const babelEslintParser = '@babel/eslint-parser' as const
+const esprimaParser = 'esprima' as const
+const espreeParser = 'espree' as const
+const eslintParser = 'eslint' as const // in fact it's espree
-type SupportedParsers = typeof typescriptEslintParser
-export const supportedParsers = [typescriptEslintParser]
+type SupportedParsers =
+ | typeof typescriptEslintParser
+ | typeof babelEslintParser
+ | typeof esprimaParser
+ | typeof espreeParser
+ | typeof eslintParser
-export const parserNamesMappingsToCodeQueInternal = {
- [typescriptEslintParser]: 'typescript-eslint',
+export const supportedParsers = [
+ typescriptEslintParser,
+ babelEslintParser,
+ esprimaParser,
+ espreeParser,
+ eslintParser,
+]
+
+export const parserNamesMappingsToCodeQueInternal: Record<
+ SupportedParsers,
+ ParserType
+> = {
+ [typescriptEslintParser]: 'typescript-eslint-parser',
+ [babelEslintParser]: 'babel-eslint-parser',
+ [esprimaParser]: 'esprima',
+ [espreeParser]: 'espree',
+ [eslintParser]: 'espree',
} as const
export const extractParserNameFromResolvedPath = (pathToParser: string) => {
@@ -48,7 +71,7 @@ export const assertCompatibleParser = (parserPath: string) => {
if (!supportedParsers.includes(parser as any)) {
throw new Error(
- `\nCodeQue does not support "${parser}" parser.\nSupported parsers are:\n -${supportedParsers.join(
+ `\nCodeQue does not support "${parser}" parser.\nSupported parsers are:\n- ${supportedParsers.join(
'\n- ',
)}\nPlease open an issue to request parser support.\nVisit https://github.com/codeque-co/codeque/issues\n`,
)
diff --git a/packages/eslint/tsconfig.json b/packages/eslint/tsconfig.json
index 58de4f4..6560fa6 100644
--- a/packages/eslint/tsconfig.json
+++ b/packages/eslint/tsconfig.json
@@ -3,20 +3,12 @@
"compilerOptions": {
"baseUrl": "./src",
"paths": {
- "/*": [
- "src/*"
- ]
+ "/*": ["src/*"]
},
"outDir": "dist",
"skipLibCheck": true,
"declaration": false
},
- "include": ["src"],
- "exclude": [
- "__tests__/**/__fixtures__",
- "__tests__/**/__fixturesOther__",
- "dist",
- "node_modules",
- "tools/*.js"
- ]
-}
\ No newline at end of file
+ "include": ["src", "declarations.d.ts"],
+ "exclude": ["dist", "node_modules", "tools/*.js", "jest/**", "jest.config.js"]
+}
diff --git a/packages/tree-sitter-port/.gitignore b/packages/tree-sitter-port/.gitignore
new file mode 100644
index 0000000..770eab4
--- /dev/null
+++ b/packages/tree-sitter-port/.gitignore
@@ -0,0 +1 @@
+input
\ No newline at end of file
diff --git a/packages/tree-sitter-port/LICENSE.md b/packages/tree-sitter-port/LICENSE.md
new file mode 100644
index 0000000..113cf00
--- /dev/null
+++ b/packages/tree-sitter-port/LICENSE.md
@@ -0,0 +1,54 @@
+# Sustainable Use License
+
+Version 1.0
+
+## Acceptance
+
+By using the software, you agree to all of the terms and conditions below.
+
+## Copyright License
+
+The licensor grants you a non-exclusive, royalty-free, worldwide, non-sublicensable, non-transferable license to use, copy, distribute, make available, and prepare derivative works of the software, in each case subject to the limitations below.
+
+## Limitations
+
+You may use or modify the software only for your own internal business purposes or for non-commercial or personal use.
+You may distribute the software or provide it to others only if you do so free of charge for non-commercial purposes.
+You may not alter, remove, or obscure any licensing, copyright, or other notices of the licensor in the software. Any use of the licensor’s trademarks is subject to applicable law.
+
+## Patents
+
+The licensor grants you a license, under any patent claims the licensor can license, or becomes able to license, to make, have made, use, sell, offer for sale, import and have imported the software, in each case subject to the limitations and conditions in this license. This license does not cover any patent claims that you cause to be infringed by modifications or additions to the software. If you or your company make any written claim that the software infringes or contributes to infringement of any patent, your patent license for the software granted under these terms ends immediately. If your company makes such a claim, your patent license ends immediately for work on behalf of your company.
+
+## Notices
+
+You must ensure that anyone who gets a copy of any part of the software from you also gets a copy of these terms.
+If you modify the software, you must include in any modified copies of the software a prominent notice stating that you have modified the software.
+
+## No Other Rights
+
+These terms do not imply any licenses other than those expressly granted in these terms.
+
+## Termination
+
+If you use the software in violation of these terms, such use is not licensed, and your license will automatically terminate. If the licensor provides you with a notice of your violation, and you cease all violation of this license no later than 30 days after you receive that notice, your license will be reinstated retroactively. However, if you violate these terms after such reinstatement, any additional violation of these terms will cause your license to terminate automatically and permanently.
+
+## No Liability
+
+As far as the law allows, the software comes as is, without any warranty or condition, and the licensor will not be liable to you for any damages arising out of these terms or the use or nature of the software, under any kind of legal claim.
+
+## Definitions
+
+The “licensor” is the entity offering these terms.
+
+The “software” is the software the licensor makes available under these terms, including any portion of it.
+
+“You” refers to the individual or entity agreeing to these terms.
+
+“Your company” is any legal entity, sole proprietorship, or other kind of organization that you work for, plus all organizations that have control over, are under the control of, or are under common control with that organization. Control means ownership of substantially all the assets of an entity, or the power to direct its management and policies by vote, contract, or otherwise. Control can be direct or indirect.
+
+“Your license” is the license granted to you for the software under these terms.
+
+“Use” means anything you do with the software requiring your license.
+
+“Trademark” means trademarks, service marks, and similar rights.
\ No newline at end of file
diff --git a/packages/tree-sitter-port/Readme.md b/packages/tree-sitter-port/Readme.md
new file mode 100644
index 0000000..a4e7495
--- /dev/null
+++ b/packages/tree-sitter-port/Readme.md
@@ -0,0 +1,32 @@
+# CodeQue Tree Sitter port
+
+This repo is set of scripts to manage building files required for Tree Sitter parsers to work with CodeQue.
+
+It includes:
+- Fetching newest versions of parsers
+- Building WASM files
+- Generating node type mappings
+- Copying generated files into `vscode` and `core` directories
+
+## Usage
+
+Upgrade integrated parsers versions if needed
+
+`yarn parsers-upgrade`
+
+Build wasm files for parsers and generate mappings for node fields
+
+`yarn build-wasm-and-generate-mappings`
+
+
+Copy generated files into `vscode` and `core` directories
+
+`yarn copy-files`
+
+## Preparation to generate wasm files
+
+Follow the requirements installation steps in [tree sitter readme](https://github.com/tree-sitter/tree-sitter/blob/master/lib/binding_web/README.md#generate-wasm-language-files)
+
+What's needed
+- Emscripten (currently working with non-docker installation )
+- tree-sitter-cli
diff --git a/packages/tree-sitter-port/output/tree-sitter-c-sharp/fields-meta.json b/packages/tree-sitter-port/output/tree-sitter-c-sharp/fields-meta.json
new file mode 100644
index 0000000..b9a5289
--- /dev/null
+++ b/packages/tree-sitter-port/output/tree-sitter-c-sharp/fields-meta.json
@@ -0,0 +1,4827 @@
+{
+ "accessor_declaration": {
+ "type": "accessor_declaration",
+ "singleFieldNames": ["body", "name"],
+ "nodeTypeToMultipleFieldName": {
+ "attribute_list": "children",
+ "modifier": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "accessor_list": {
+ "type": "accessor_list",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "accessor_declaration": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "alias_qualified_name": {
+ "type": "alias_qualified_name",
+ "singleFieldNames": ["alias", "name"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "and_pattern": {
+ "type": "and_pattern",
+ "singleFieldNames": ["left", "operator", "right"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "anonymous_method_expression": {
+ "type": "anonymous_method_expression",
+ "singleFieldNames": ["parameters"],
+ "nodeTypeToMultipleFieldName": {
+ "block": "children",
+ "modifier": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "anonymous_object_creation_expression": {
+ "type": "anonymous_object_creation_expression",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "element_access_expression": "children",
+ "element_binding_expression": "children",
+ "generic_name": "children",
+ "identifier": "children",
+ "member_access_expression": "children",
+ "parenthesized_expression": "children",
+ "prefix_unary_expression": "children",
+ "this": "children",
+ "tuple_expression": "children",
+ "anonymous_method_expression": "children",
+ "anonymous_object_creation_expression": "children",
+ "array_creation_expression": "children",
+ "as_expression": "children",
+ "assignment_expression": "children",
+ "await_expression": "children",
+ "base": "children",
+ "binary_expression": "children",
+ "cast_expression": "children",
+ "checked_expression": "children",
+ "conditional_access_expression": "children",
+ "conditional_expression": "children",
+ "default_expression": "children",
+ "implicit_array_creation_expression": "children",
+ "implicit_object_creation_expression": "children",
+ "implicit_stackalloc_expression": "children",
+ "initializer_expression": "children",
+ "interpolated_string_expression": "children",
+ "invocation_expression": "children",
+ "is_expression": "children",
+ "is_pattern_expression": "children",
+ "lambda_expression": "children",
+ "boolean_literal": "children",
+ "character_literal": "children",
+ "integer_literal": "children",
+ "null_literal": "children",
+ "raw_string_literal": "children",
+ "real_literal": "children",
+ "string_literal": "children",
+ "verbatim_string_literal": "children",
+ "makeref_expression": "children",
+ "object_creation_expression": "children",
+ "postfix_unary_expression": "children",
+ "preproc_if": "children",
+ "query_expression": "children",
+ "range_expression": "children",
+ "ref_expression": "children",
+ "reftype_expression": "children",
+ "refvalue_expression": "children",
+ "sizeof_expression": "children",
+ "stackalloc_expression": "children",
+ "switch_expression": "children",
+ "throw_expression": "children",
+ "typeof_expression": "children",
+ "with_expression": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "argument": {
+ "type": "argument",
+ "singleFieldNames": ["name"],
+ "nodeTypeToMultipleFieldName": {
+ "declaration_expression": "children",
+ "element_access_expression": "children",
+ "element_binding_expression": "children",
+ "generic_name": "children",
+ "identifier": "children",
+ "member_access_expression": "children",
+ "parenthesized_expression": "children",
+ "prefix_unary_expression": "children",
+ "this": "children",
+ "tuple_expression": "children",
+ "anonymous_method_expression": "children",
+ "anonymous_object_creation_expression": "children",
+ "array_creation_expression": "children",
+ "as_expression": "children",
+ "assignment_expression": "children",
+ "await_expression": "children",
+ "base": "children",
+ "binary_expression": "children",
+ "cast_expression": "children",
+ "checked_expression": "children",
+ "conditional_access_expression": "children",
+ "conditional_expression": "children",
+ "default_expression": "children",
+ "implicit_array_creation_expression": "children",
+ "implicit_object_creation_expression": "children",
+ "implicit_stackalloc_expression": "children",
+ "initializer_expression": "children",
+ "interpolated_string_expression": "children",
+ "invocation_expression": "children",
+ "is_expression": "children",
+ "is_pattern_expression": "children",
+ "lambda_expression": "children",
+ "boolean_literal": "children",
+ "character_literal": "children",
+ "integer_literal": "children",
+ "null_literal": "children",
+ "raw_string_literal": "children",
+ "real_literal": "children",
+ "string_literal": "children",
+ "verbatim_string_literal": "children",
+ "makeref_expression": "children",
+ "object_creation_expression": "children",
+ "postfix_unary_expression": "children",
+ "preproc_if": "children",
+ "query_expression": "children",
+ "range_expression": "children",
+ "ref_expression": "children",
+ "reftype_expression": "children",
+ "refvalue_expression": "children",
+ "sizeof_expression": "children",
+ "stackalloc_expression": "children",
+ "switch_expression": "children",
+ "throw_expression": "children",
+ "typeof_expression": "children",
+ "with_expression": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "argument_list": {
+ "type": "argument_list",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "argument": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "array_creation_expression": {
+ "type": "array_creation_expression",
+ "singleFieldNames": ["type"],
+ "nodeTypeToMultipleFieldName": {
+ "initializer_expression": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "array_rank_specifier": {
+ "type": "array_rank_specifier",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "element_access_expression": "children",
+ "element_binding_expression": "children",
+ "generic_name": "children",
+ "identifier": "children",
+ "member_access_expression": "children",
+ "parenthesized_expression": "children",
+ "prefix_unary_expression": "children",
+ "this": "children",
+ "tuple_expression": "children",
+ "anonymous_method_expression": "children",
+ "anonymous_object_creation_expression": "children",
+ "array_creation_expression": "children",
+ "as_expression": "children",
+ "assignment_expression": "children",
+ "await_expression": "children",
+ "base": "children",
+ "binary_expression": "children",
+ "cast_expression": "children",
+ "checked_expression": "children",
+ "conditional_access_expression": "children",
+ "conditional_expression": "children",
+ "default_expression": "children",
+ "implicit_array_creation_expression": "children",
+ "implicit_object_creation_expression": "children",
+ "implicit_stackalloc_expression": "children",
+ "initializer_expression": "children",
+ "interpolated_string_expression": "children",
+ "invocation_expression": "children",
+ "is_expression": "children",
+ "is_pattern_expression": "children",
+ "lambda_expression": "children",
+ "boolean_literal": "children",
+ "character_literal": "children",
+ "integer_literal": "children",
+ "null_literal": "children",
+ "raw_string_literal": "children",
+ "real_literal": "children",
+ "string_literal": "children",
+ "verbatim_string_literal": "children",
+ "makeref_expression": "children",
+ "object_creation_expression": "children",
+ "postfix_unary_expression": "children",
+ "preproc_if": "children",
+ "query_expression": "children",
+ "range_expression": "children",
+ "ref_expression": "children",
+ "reftype_expression": "children",
+ "refvalue_expression": "children",
+ "sizeof_expression": "children",
+ "stackalloc_expression": "children",
+ "switch_expression": "children",
+ "throw_expression": "children",
+ "typeof_expression": "children",
+ "with_expression": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "array_type": {
+ "type": "array_type",
+ "singleFieldNames": ["rank", "type"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "arrow_expression_clause": {
+ "type": "arrow_expression_clause",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "element_access_expression": "children",
+ "element_binding_expression": "children",
+ "generic_name": "children",
+ "identifier": "children",
+ "member_access_expression": "children",
+ "parenthesized_expression": "children",
+ "prefix_unary_expression": "children",
+ "this": "children",
+ "tuple_expression": "children",
+ "anonymous_method_expression": "children",
+ "anonymous_object_creation_expression": "children",
+ "array_creation_expression": "children",
+ "as_expression": "children",
+ "assignment_expression": "children",
+ "await_expression": "children",
+ "base": "children",
+ "binary_expression": "children",
+ "cast_expression": "children",
+ "checked_expression": "children",
+ "conditional_access_expression": "children",
+ "conditional_expression": "children",
+ "default_expression": "children",
+ "implicit_array_creation_expression": "children",
+ "implicit_object_creation_expression": "children",
+ "implicit_stackalloc_expression": "children",
+ "initializer_expression": "children",
+ "interpolated_string_expression": "children",
+ "invocation_expression": "children",
+ "is_expression": "children",
+ "is_pattern_expression": "children",
+ "lambda_expression": "children",
+ "boolean_literal": "children",
+ "character_literal": "children",
+ "integer_literal": "children",
+ "null_literal": "children",
+ "raw_string_literal": "children",
+ "real_literal": "children",
+ "string_literal": "children",
+ "verbatim_string_literal": "children",
+ "makeref_expression": "children",
+ "object_creation_expression": "children",
+ "postfix_unary_expression": "children",
+ "preproc_if": "children",
+ "query_expression": "children",
+ "range_expression": "children",
+ "ref_expression": "children",
+ "reftype_expression": "children",
+ "refvalue_expression": "children",
+ "sizeof_expression": "children",
+ "stackalloc_expression": "children",
+ "switch_expression": "children",
+ "throw_expression": "children",
+ "typeof_expression": "children",
+ "with_expression": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "as_expression": {
+ "type": "as_expression",
+ "singleFieldNames": ["left", "operator", "right"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "assignment_expression": {
+ "type": "assignment_expression",
+ "singleFieldNames": ["left", "operator", "right"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "attribute": {
+ "type": "attribute",
+ "singleFieldNames": ["name"],
+ "nodeTypeToMultipleFieldName": {
+ "attribute_argument_list": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "attribute_argument": {
+ "type": "attribute_argument",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "element_access_expression": "children",
+ "element_binding_expression": "children",
+ "generic_name": "children",
+ "identifier": "children",
+ "member_access_expression": "children",
+ "parenthesized_expression": "children",
+ "prefix_unary_expression": "children",
+ "this": "children",
+ "tuple_expression": "children",
+ "anonymous_method_expression": "children",
+ "anonymous_object_creation_expression": "children",
+ "array_creation_expression": "children",
+ "as_expression": "children",
+ "assignment_expression": "children",
+ "await_expression": "children",
+ "base": "children",
+ "binary_expression": "children",
+ "cast_expression": "children",
+ "checked_expression": "children",
+ "conditional_access_expression": "children",
+ "conditional_expression": "children",
+ "default_expression": "children",
+ "implicit_array_creation_expression": "children",
+ "implicit_object_creation_expression": "children",
+ "implicit_stackalloc_expression": "children",
+ "initializer_expression": "children",
+ "interpolated_string_expression": "children",
+ "invocation_expression": "children",
+ "is_expression": "children",
+ "is_pattern_expression": "children",
+ "lambda_expression": "children",
+ "boolean_literal": "children",
+ "character_literal": "children",
+ "integer_literal": "children",
+ "null_literal": "children",
+ "raw_string_literal": "children",
+ "real_literal": "children",
+ "string_literal": "children",
+ "verbatim_string_literal": "children",
+ "makeref_expression": "children",
+ "object_creation_expression": "children",
+ "postfix_unary_expression": "children",
+ "preproc_if": "children",
+ "query_expression": "children",
+ "range_expression": "children",
+ "ref_expression": "children",
+ "reftype_expression": "children",
+ "refvalue_expression": "children",
+ "sizeof_expression": "children",
+ "stackalloc_expression": "children",
+ "switch_expression": "children",
+ "throw_expression": "children",
+ "typeof_expression": "children",
+ "with_expression": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "attribute_argument_list": {
+ "type": "attribute_argument_list",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "attribute_argument": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "attribute_list": {
+ "type": "attribute_list",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "attribute": "children",
+ "attribute_target_specifier": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "attribute_target_specifier": {
+ "type": "attribute_target_specifier",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "await_expression": {
+ "type": "await_expression",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "element_access_expression": "children",
+ "element_binding_expression": "children",
+ "generic_name": "children",
+ "identifier": "children",
+ "member_access_expression": "children",
+ "parenthesized_expression": "children",
+ "prefix_unary_expression": "children",
+ "this": "children",
+ "tuple_expression": "children",
+ "anonymous_method_expression": "children",
+ "anonymous_object_creation_expression": "children",
+ "array_creation_expression": "children",
+ "as_expression": "children",
+ "assignment_expression": "children",
+ "await_expression": "children",
+ "base": "children",
+ "binary_expression": "children",
+ "cast_expression": "children",
+ "checked_expression": "children",
+ "conditional_access_expression": "children",
+ "conditional_expression": "children",
+ "default_expression": "children",
+ "implicit_array_creation_expression": "children",
+ "implicit_object_creation_expression": "children",
+ "implicit_stackalloc_expression": "children",
+ "initializer_expression": "children",
+ "interpolated_string_expression": "children",
+ "invocation_expression": "children",
+ "is_expression": "children",
+ "is_pattern_expression": "children",
+ "lambda_expression": "children",
+ "boolean_literal": "children",
+ "character_literal": "children",
+ "integer_literal": "children",
+ "null_literal": "children",
+ "raw_string_literal": "children",
+ "real_literal": "children",
+ "string_literal": "children",
+ "verbatim_string_literal": "children",
+ "makeref_expression": "children",
+ "object_creation_expression": "children",
+ "postfix_unary_expression": "children",
+ "preproc_if": "children",
+ "query_expression": "children",
+ "range_expression": "children",
+ "ref_expression": "children",
+ "reftype_expression": "children",
+ "refvalue_expression": "children",
+ "sizeof_expression": "children",
+ "stackalloc_expression": "children",
+ "switch_expression": "children",
+ "throw_expression": "children",
+ "typeof_expression": "children",
+ "with_expression": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "base_list": {
+ "type": "base_list",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "argument_list": "children",
+ "primary_constructor_base_type": "children",
+ "alias_qualified_name": "children",
+ "array_type": "children",
+ "function_pointer_type": "children",
+ "generic_name": "children",
+ "identifier": "children",
+ "implicit_type": "children",
+ "nullable_type": "children",
+ "pointer_type": "children",
+ "predefined_type": "children",
+ "qualified_name": "children",
+ "ref_type": "children",
+ "scoped_type": "children",
+ "tuple_type": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "binary_expression": {
+ "type": "binary_expression",
+ "singleFieldNames": ["left", "operator", "right"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "block": {
+ "type": "block",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "block": "children",
+ "break_statement": "children",
+ "checked_statement": "children",
+ "continue_statement": "children",
+ "do_statement": "children",
+ "empty_statement": "children",
+ "expression_statement": "children",
+ "fixed_statement": "children",
+ "for_statement": "children",
+ "foreach_statement": "children",
+ "goto_statement": "children",
+ "if_statement": "children",
+ "labeled_statement": "children",
+ "local_declaration_statement": "children",
+ "local_function_statement": "children",
+ "lock_statement": "children",
+ "preproc_if": "children",
+ "return_statement": "children",
+ "switch_statement": "children",
+ "throw_statement": "children",
+ "try_statement": "children",
+ "unsafe_statement": "children",
+ "using_statement": "children",
+ "while_statement": "children",
+ "yield_statement": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "boolean_literal": {
+ "type": "boolean_literal",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "bracketed_argument_list": {
+ "type": "bracketed_argument_list",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "argument": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "bracketed_parameter_list": {
+ "type": "bracketed_parameter_list",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "identifier": "name",
+ "array_type": "type",
+ "nullable_type": "type",
+ "attribute_list": "children",
+ "parameter": "children"
+ },
+ "multipleOrChildrenFieldNames": ["name", "type", "children"]
+ },
+ "break_statement": {
+ "type": "break_statement",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "calling_convention": {
+ "type": "calling_convention",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "identifier": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "cast_expression": {
+ "type": "cast_expression",
+ "singleFieldNames": ["type", "value"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "catch_clause": {
+ "type": "catch_clause",
+ "singleFieldNames": ["body"],
+ "nodeTypeToMultipleFieldName": {
+ "catch_declaration": "children",
+ "catch_filter_clause": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "catch_declaration": {
+ "type": "catch_declaration",
+ "singleFieldNames": ["name", "type"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "catch_filter_clause": {
+ "type": "catch_filter_clause",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "element_access_expression": "children",
+ "element_binding_expression": "children",
+ "generic_name": "children",
+ "identifier": "children",
+ "member_access_expression": "children",
+ "parenthesized_expression": "children",
+ "prefix_unary_expression": "children",
+ "this": "children",
+ "tuple_expression": "children",
+ "anonymous_method_expression": "children",
+ "anonymous_object_creation_expression": "children",
+ "array_creation_expression": "children",
+ "as_expression": "children",
+ "assignment_expression": "children",
+ "await_expression": "children",
+ "base": "children",
+ "binary_expression": "children",
+ "cast_expression": "children",
+ "checked_expression": "children",
+ "conditional_access_expression": "children",
+ "conditional_expression": "children",
+ "default_expression": "children",
+ "implicit_array_creation_expression": "children",
+ "implicit_object_creation_expression": "children",
+ "implicit_stackalloc_expression": "children",
+ "initializer_expression": "children",
+ "interpolated_string_expression": "children",
+ "invocation_expression": "children",
+ "is_expression": "children",
+ "is_pattern_expression": "children",
+ "lambda_expression": "children",
+ "boolean_literal": "children",
+ "character_literal": "children",
+ "integer_literal": "children",
+ "null_literal": "children",
+ "raw_string_literal": "children",
+ "real_literal": "children",
+ "string_literal": "children",
+ "verbatim_string_literal": "children",
+ "makeref_expression": "children",
+ "object_creation_expression": "children",
+ "postfix_unary_expression": "children",
+ "preproc_if": "children",
+ "query_expression": "children",
+ "range_expression": "children",
+ "ref_expression": "children",
+ "reftype_expression": "children",
+ "refvalue_expression": "children",
+ "sizeof_expression": "children",
+ "stackalloc_expression": "children",
+ "switch_expression": "children",
+ "throw_expression": "children",
+ "typeof_expression": "children",
+ "with_expression": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "character_literal": {
+ "type": "character_literal",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "character_literal_content": "children",
+ "escape_sequence": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "checked_expression": {
+ "type": "checked_expression",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "element_access_expression": "children",
+ "element_binding_expression": "children",
+ "generic_name": "children",
+ "identifier": "children",
+ "member_access_expression": "children",
+ "parenthesized_expression": "children",
+ "prefix_unary_expression": "children",
+ "this": "children",
+ "tuple_expression": "children",
+ "anonymous_method_expression": "children",
+ "anonymous_object_creation_expression": "children",
+ "array_creation_expression": "children",
+ "as_expression": "children",
+ "assignment_expression": "children",
+ "await_expression": "children",
+ "base": "children",
+ "binary_expression": "children",
+ "cast_expression": "children",
+ "checked_expression": "children",
+ "conditional_access_expression": "children",
+ "conditional_expression": "children",
+ "default_expression": "children",
+ "implicit_array_creation_expression": "children",
+ "implicit_object_creation_expression": "children",
+ "implicit_stackalloc_expression": "children",
+ "initializer_expression": "children",
+ "interpolated_string_expression": "children",
+ "invocation_expression": "children",
+ "is_expression": "children",
+ "is_pattern_expression": "children",
+ "lambda_expression": "children",
+ "boolean_literal": "children",
+ "character_literal": "children",
+ "integer_literal": "children",
+ "null_literal": "children",
+ "raw_string_literal": "children",
+ "real_literal": "children",
+ "string_literal": "children",
+ "verbatim_string_literal": "children",
+ "makeref_expression": "children",
+ "object_creation_expression": "children",
+ "postfix_unary_expression": "children",
+ "preproc_if": "children",
+ "query_expression": "children",
+ "range_expression": "children",
+ "ref_expression": "children",
+ "reftype_expression": "children",
+ "refvalue_expression": "children",
+ "sizeof_expression": "children",
+ "stackalloc_expression": "children",
+ "switch_expression": "children",
+ "throw_expression": "children",
+ "typeof_expression": "children",
+ "with_expression": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "checked_statement": {
+ "type": "checked_statement",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "block": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "class_declaration": {
+ "type": "class_declaration",
+ "singleFieldNames": ["body", "name"],
+ "nodeTypeToMultipleFieldName": {
+ "attribute_list": "children",
+ "base_list": "children",
+ "modifier": "children",
+ "parameter_list": "children",
+ "type_parameter_constraints_clause": "children",
+ "type_parameter_list": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "compilation_unit": {
+ "type": "compilation_unit",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "extern_alias_directive": "children",
+ "file_scoped_namespace_declaration": "children",
+ "global_attribute": "children",
+ "global_statement": "children",
+ "namespace_declaration": "children",
+ "preproc_if": "children",
+ "shebang_directive": "children",
+ "class_declaration": "children",
+ "delegate_declaration": "children",
+ "enum_declaration": "children",
+ "interface_declaration": "children",
+ "record_declaration": "children",
+ "struct_declaration": "children",
+ "using_directive": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "conditional_access_expression": {
+ "type": "conditional_access_expression",
+ "singleFieldNames": ["condition"],
+ "nodeTypeToMultipleFieldName": {
+ "element_binding_expression": "children",
+ "member_binding_expression": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "conditional_expression": {
+ "type": "conditional_expression",
+ "singleFieldNames": ["alternative", "condition", "consequence"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "constant_pattern": {
+ "type": "constant_pattern",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "binary_expression": "children",
+ "cast_expression": "children",
+ "default_expression": "children",
+ "generic_name": "children",
+ "identifier": "children",
+ "interpolated_string_expression": "children",
+ "invocation_expression": "children",
+ "boolean_literal": "children",
+ "character_literal": "children",
+ "integer_literal": "children",
+ "null_literal": "children",
+ "raw_string_literal": "children",
+ "real_literal": "children",
+ "string_literal": "children",
+ "verbatim_string_literal": "children",
+ "member_access_expression": "children",
+ "parenthesized_expression": "children",
+ "postfix_unary_expression": "children",
+ "prefix_unary_expression": "children",
+ "sizeof_expression": "children",
+ "tuple_expression": "children",
+ "typeof_expression": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "constructor_constraint": {
+ "type": "constructor_constraint",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "constructor_declaration": {
+ "type": "constructor_declaration",
+ "singleFieldNames": ["body", "name", "parameters"],
+ "nodeTypeToMultipleFieldName": {
+ "attribute_list": "children",
+ "constructor_initializer": "children",
+ "modifier": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "constructor_initializer": {
+ "type": "constructor_initializer",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "argument_list": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "continue_statement": {
+ "type": "continue_statement",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "conversion_operator_declaration": {
+ "type": "conversion_operator_declaration",
+ "singleFieldNames": ["body", "parameters", "type"],
+ "nodeTypeToMultipleFieldName": {
+ "attribute_list": "children",
+ "explicit_interface_specifier": "children",
+ "modifier": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "declaration_expression": {
+ "type": "declaration_expression",
+ "singleFieldNames": ["name", "type"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "declaration_list": {
+ "type": "declaration_list",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "class_declaration": "children",
+ "constructor_declaration": "children",
+ "conversion_operator_declaration": "children",
+ "delegate_declaration": "children",
+ "destructor_declaration": "children",
+ "enum_declaration": "children",
+ "event_declaration": "children",
+ "event_field_declaration": "children",
+ "field_declaration": "children",
+ "indexer_declaration": "children",
+ "interface_declaration": "children",
+ "method_declaration": "children",
+ "namespace_declaration": "children",
+ "operator_declaration": "children",
+ "preproc_if": "children",
+ "property_declaration": "children",
+ "record_declaration": "children",
+ "struct_declaration": "children",
+ "using_directive": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "declaration_pattern": {
+ "type": "declaration_pattern",
+ "singleFieldNames": ["name", "type"],
+ "nodeTypeToMultipleFieldName": {
+ "discard": "children",
+ "parenthesized_variable_designation": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "default_expression": {
+ "type": "default_expression",
+ "singleFieldNames": ["type"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "delegate_declaration": {
+ "type": "delegate_declaration",
+ "singleFieldNames": ["name", "parameters", "type", "type_parameters"],
+ "nodeTypeToMultipleFieldName": {
+ "attribute_list": "children",
+ "modifier": "children",
+ "type_parameter_constraints_clause": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "destructor_declaration": {
+ "type": "destructor_declaration",
+ "singleFieldNames": ["body", "name", "parameters"],
+ "nodeTypeToMultipleFieldName": {
+ "attribute_list": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "do_statement": {
+ "type": "do_statement",
+ "singleFieldNames": ["body", "condition"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "element_access_expression": {
+ "type": "element_access_expression",
+ "singleFieldNames": ["expression", "subscript"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "element_binding_expression": {
+ "type": "element_binding_expression",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "argument": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "empty_statement": {
+ "type": "empty_statement",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "enum_declaration": {
+ "type": "enum_declaration",
+ "singleFieldNames": ["body", "name"],
+ "nodeTypeToMultipleFieldName": {
+ "attribute_list": "children",
+ "base_list": "children",
+ "modifier": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "enum_member_declaration": {
+ "type": "enum_member_declaration",
+ "singleFieldNames": ["name", "value"],
+ "nodeTypeToMultipleFieldName": {
+ "attribute_list": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "enum_member_declaration_list": {
+ "type": "enum_member_declaration_list",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "enum_member_declaration": "children",
+ "preproc_if": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "event_declaration": {
+ "type": "event_declaration",
+ "singleFieldNames": ["accessors", "name", "type"],
+ "nodeTypeToMultipleFieldName": {
+ "attribute_list": "children",
+ "explicit_interface_specifier": "children",
+ "modifier": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "event_field_declaration": {
+ "type": "event_field_declaration",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "attribute_list": "children",
+ "modifier": "children",
+ "variable_declaration": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "explicit_interface_specifier": {
+ "type": "explicit_interface_specifier",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "alias_qualified_name": "children",
+ "generic_name": "children",
+ "identifier": "children",
+ "qualified_name": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "expression_statement": {
+ "type": "expression_statement",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "assignment_expression": "children",
+ "await_expression": "children",
+ "invocation_expression": "children",
+ "object_creation_expression": "children",
+ "parenthesized_expression": "children",
+ "postfix_unary_expression": "children",
+ "prefix_unary_expression": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "extern_alias_directive": {
+ "type": "extern_alias_directive",
+ "singleFieldNames": ["name"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "field_declaration": {
+ "type": "field_declaration",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "attribute_list": "children",
+ "modifier": "children",
+ "variable_declaration": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "file_scoped_namespace_declaration": {
+ "type": "file_scoped_namespace_declaration",
+ "singleFieldNames": ["name"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "finally_clause": {
+ "type": "finally_clause",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "block": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "fixed_statement": {
+ "type": "fixed_statement",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "block": "children",
+ "break_statement": "children",
+ "checked_statement": "children",
+ "continue_statement": "children",
+ "do_statement": "children",
+ "empty_statement": "children",
+ "expression_statement": "children",
+ "fixed_statement": "children",
+ "for_statement": "children",
+ "foreach_statement": "children",
+ "goto_statement": "children",
+ "if_statement": "children",
+ "labeled_statement": "children",
+ "local_declaration_statement": "children",
+ "local_function_statement": "children",
+ "lock_statement": "children",
+ "preproc_if": "children",
+ "return_statement": "children",
+ "switch_statement": "children",
+ "throw_statement": "children",
+ "try_statement": "children",
+ "unsafe_statement": "children",
+ "using_statement": "children",
+ "while_statement": "children",
+ "yield_statement": "children",
+ "variable_declaration": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "for_statement": {
+ "type": "for_statement",
+ "singleFieldNames": ["body", "condition"],
+ "nodeTypeToMultipleFieldName": {
+ ",": "update",
+ "element_access_expression": "update",
+ "element_binding_expression": "update",
+ "generic_name": "update",
+ "identifier": "update",
+ "member_access_expression": "update",
+ "parenthesized_expression": "update",
+ "prefix_unary_expression": "update",
+ "this": "update",
+ "tuple_expression": "update",
+ "anonymous_method_expression": "update",
+ "anonymous_object_creation_expression": "update",
+ "array_creation_expression": "update",
+ "as_expression": "update",
+ "assignment_expression": "update",
+ "await_expression": "update",
+ "base": "update",
+ "binary_expression": "update",
+ "cast_expression": "update",
+ "checked_expression": "update",
+ "conditional_access_expression": "update",
+ "conditional_expression": "update",
+ "default_expression": "update",
+ "implicit_array_creation_expression": "update",
+ "implicit_object_creation_expression": "update",
+ "implicit_stackalloc_expression": "update",
+ "initializer_expression": "update",
+ "interpolated_string_expression": "update",
+ "invocation_expression": "update",
+ "is_expression": "update",
+ "is_pattern_expression": "update",
+ "lambda_expression": "update",
+ "boolean_literal": "update",
+ "character_literal": "update",
+ "integer_literal": "update",
+ "null_literal": "update",
+ "raw_string_literal": "update",
+ "real_literal": "update",
+ "string_literal": "update",
+ "verbatim_string_literal": "update",
+ "makeref_expression": "update",
+ "object_creation_expression": "update",
+ "postfix_unary_expression": "update",
+ "preproc_if": "update",
+ "query_expression": "update",
+ "range_expression": "update",
+ "ref_expression": "update",
+ "reftype_expression": "update",
+ "refvalue_expression": "update",
+ "sizeof_expression": "update",
+ "stackalloc_expression": "update",
+ "switch_expression": "update",
+ "throw_expression": "update",
+ "typeof_expression": "update",
+ "with_expression": "update",
+ "variable_declaration": "initializer"
+ },
+ "multipleOrChildrenFieldNames": ["initializer", "update"]
+ },
+ "foreach_statement": {
+ "type": "foreach_statement",
+ "singleFieldNames": ["body", "left", "right", "type"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "from_clause": {
+ "type": "from_clause",
+ "singleFieldNames": ["name", "type"],
+ "nodeTypeToMultipleFieldName": {
+ "element_access_expression": "children",
+ "element_binding_expression": "children",
+ "generic_name": "children",
+ "identifier": "children",
+ "member_access_expression": "children",
+ "parenthesized_expression": "children",
+ "prefix_unary_expression": "children",
+ "this": "children",
+ "tuple_expression": "children",
+ "anonymous_method_expression": "children",
+ "anonymous_object_creation_expression": "children",
+ "array_creation_expression": "children",
+ "as_expression": "children",
+ "assignment_expression": "children",
+ "await_expression": "children",
+ "base": "children",
+ "binary_expression": "children",
+ "cast_expression": "children",
+ "checked_expression": "children",
+ "conditional_access_expression": "children",
+ "conditional_expression": "children",
+ "default_expression": "children",
+ "implicit_array_creation_expression": "children",
+ "implicit_object_creation_expression": "children",
+ "implicit_stackalloc_expression": "children",
+ "initializer_expression": "children",
+ "interpolated_string_expression": "children",
+ "invocation_expression": "children",
+ "is_expression": "children",
+ "is_pattern_expression": "children",
+ "lambda_expression": "children",
+ "boolean_literal": "children",
+ "character_literal": "children",
+ "integer_literal": "children",
+ "null_literal": "children",
+ "raw_string_literal": "children",
+ "real_literal": "children",
+ "string_literal": "children",
+ "verbatim_string_literal": "children",
+ "makeref_expression": "children",
+ "object_creation_expression": "children",
+ "postfix_unary_expression": "children",
+ "preproc_if": "children",
+ "query_expression": "children",
+ "range_expression": "children",
+ "ref_expression": "children",
+ "reftype_expression": "children",
+ "refvalue_expression": "children",
+ "sizeof_expression": "children",
+ "stackalloc_expression": "children",
+ "switch_expression": "children",
+ "throw_expression": "children",
+ "typeof_expression": "children",
+ "with_expression": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "function_pointer_parameter": {
+ "type": "function_pointer_parameter",
+ "singleFieldNames": ["type"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "function_pointer_type": {
+ "type": "function_pointer_type",
+ "singleFieldNames": ["returns"],
+ "nodeTypeToMultipleFieldName": {
+ "calling_convention": "children",
+ "function_pointer_parameter": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "generic_name": {
+ "type": "generic_name",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "identifier": "children",
+ "type_argument_list": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "global_attribute": {
+ "type": "global_attribute",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "attribute": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "global_statement": {
+ "type": "global_statement",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "block": "children",
+ "break_statement": "children",
+ "checked_statement": "children",
+ "continue_statement": "children",
+ "do_statement": "children",
+ "empty_statement": "children",
+ "expression_statement": "children",
+ "fixed_statement": "children",
+ "for_statement": "children",
+ "foreach_statement": "children",
+ "goto_statement": "children",
+ "if_statement": "children",
+ "labeled_statement": "children",
+ "local_declaration_statement": "children",
+ "local_function_statement": "children",
+ "lock_statement": "children",
+ "preproc_if": "children",
+ "return_statement": "children",
+ "switch_statement": "children",
+ "throw_statement": "children",
+ "try_statement": "children",
+ "unsafe_statement": "children",
+ "using_statement": "children",
+ "while_statement": "children",
+ "yield_statement": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "goto_statement": {
+ "type": "goto_statement",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "element_access_expression": "children",
+ "element_binding_expression": "children",
+ "generic_name": "children",
+ "identifier": "children",
+ "member_access_expression": "children",
+ "parenthesized_expression": "children",
+ "prefix_unary_expression": "children",
+ "this": "children",
+ "tuple_expression": "children",
+ "anonymous_method_expression": "children",
+ "anonymous_object_creation_expression": "children",
+ "array_creation_expression": "children",
+ "as_expression": "children",
+ "assignment_expression": "children",
+ "await_expression": "children",
+ "base": "children",
+ "binary_expression": "children",
+ "cast_expression": "children",
+ "checked_expression": "children",
+ "conditional_access_expression": "children",
+ "conditional_expression": "children",
+ "default_expression": "children",
+ "implicit_array_creation_expression": "children",
+ "implicit_object_creation_expression": "children",
+ "implicit_stackalloc_expression": "children",
+ "initializer_expression": "children",
+ "interpolated_string_expression": "children",
+ "invocation_expression": "children",
+ "is_expression": "children",
+ "is_pattern_expression": "children",
+ "lambda_expression": "children",
+ "boolean_literal": "children",
+ "character_literal": "children",
+ "integer_literal": "children",
+ "null_literal": "children",
+ "raw_string_literal": "children",
+ "real_literal": "children",
+ "string_literal": "children",
+ "verbatim_string_literal": "children",
+ "makeref_expression": "children",
+ "object_creation_expression": "children",
+ "postfix_unary_expression": "children",
+ "preproc_if": "children",
+ "query_expression": "children",
+ "range_expression": "children",
+ "ref_expression": "children",
+ "reftype_expression": "children",
+ "refvalue_expression": "children",
+ "sizeof_expression": "children",
+ "stackalloc_expression": "children",
+ "switch_expression": "children",
+ "throw_expression": "children",
+ "typeof_expression": "children",
+ "with_expression": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "group_clause": {
+ "type": "group_clause",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "element_access_expression": "children",
+ "element_binding_expression": "children",
+ "generic_name": "children",
+ "identifier": "children",
+ "member_access_expression": "children",
+ "parenthesized_expression": "children",
+ "prefix_unary_expression": "children",
+ "this": "children",
+ "tuple_expression": "children",
+ "anonymous_method_expression": "children",
+ "anonymous_object_creation_expression": "children",
+ "array_creation_expression": "children",
+ "as_expression": "children",
+ "assignment_expression": "children",
+ "await_expression": "children",
+ "base": "children",
+ "binary_expression": "children",
+ "cast_expression": "children",
+ "checked_expression": "children",
+ "conditional_access_expression": "children",
+ "conditional_expression": "children",
+ "default_expression": "children",
+ "implicit_array_creation_expression": "children",
+ "implicit_object_creation_expression": "children",
+ "implicit_stackalloc_expression": "children",
+ "initializer_expression": "children",
+ "interpolated_string_expression": "children",
+ "invocation_expression": "children",
+ "is_expression": "children",
+ "is_pattern_expression": "children",
+ "lambda_expression": "children",
+ "boolean_literal": "children",
+ "character_literal": "children",
+ "integer_literal": "children",
+ "null_literal": "children",
+ "raw_string_literal": "children",
+ "real_literal": "children",
+ "string_literal": "children",
+ "verbatim_string_literal": "children",
+ "makeref_expression": "children",
+ "object_creation_expression": "children",
+ "postfix_unary_expression": "children",
+ "preproc_if": "children",
+ "query_expression": "children",
+ "range_expression": "children",
+ "ref_expression": "children",
+ "reftype_expression": "children",
+ "refvalue_expression": "children",
+ "sizeof_expression": "children",
+ "stackalloc_expression": "children",
+ "switch_expression": "children",
+ "throw_expression": "children",
+ "typeof_expression": "children",
+ "with_expression": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "identifier": {
+ "type": "identifier",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "if_statement": {
+ "type": "if_statement",
+ "singleFieldNames": ["alternative", "condition", "consequence"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "implicit_array_creation_expression": {
+ "type": "implicit_array_creation_expression",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "initializer_expression": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "implicit_object_creation_expression": {
+ "type": "implicit_object_creation_expression",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "argument_list": "children",
+ "initializer_expression": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "implicit_parameter": {
+ "type": "implicit_parameter",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "implicit_stackalloc_expression": {
+ "type": "implicit_stackalloc_expression",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "initializer_expression": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "implicit_type": {
+ "type": "implicit_type",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "indexer_declaration": {
+ "type": "indexer_declaration",
+ "singleFieldNames": ["accessors", "parameters", "type", "value"],
+ "nodeTypeToMultipleFieldName": {
+ "attribute_list": "children",
+ "explicit_interface_specifier": "children",
+ "modifier": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "initializer_expression": {
+ "type": "initializer_expression",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "element_access_expression": "children",
+ "element_binding_expression": "children",
+ "generic_name": "children",
+ "identifier": "children",
+ "member_access_expression": "children",
+ "parenthesized_expression": "children",
+ "prefix_unary_expression": "children",
+ "this": "children",
+ "tuple_expression": "children",
+ "anonymous_method_expression": "children",
+ "anonymous_object_creation_expression": "children",
+ "array_creation_expression": "children",
+ "as_expression": "children",
+ "assignment_expression": "children",
+ "await_expression": "children",
+ "base": "children",
+ "binary_expression": "children",
+ "cast_expression": "children",
+ "checked_expression": "children",
+ "conditional_access_expression": "children",
+ "conditional_expression": "children",
+ "default_expression": "children",
+ "implicit_array_creation_expression": "children",
+ "implicit_object_creation_expression": "children",
+ "implicit_stackalloc_expression": "children",
+ "initializer_expression": "children",
+ "interpolated_string_expression": "children",
+ "invocation_expression": "children",
+ "is_expression": "children",
+ "is_pattern_expression": "children",
+ "lambda_expression": "children",
+ "boolean_literal": "children",
+ "character_literal": "children",
+ "integer_literal": "children",
+ "null_literal": "children",
+ "raw_string_literal": "children",
+ "real_literal": "children",
+ "string_literal": "children",
+ "verbatim_string_literal": "children",
+ "makeref_expression": "children",
+ "object_creation_expression": "children",
+ "postfix_unary_expression": "children",
+ "preproc_if": "children",
+ "query_expression": "children",
+ "range_expression": "children",
+ "ref_expression": "children",
+ "reftype_expression": "children",
+ "refvalue_expression": "children",
+ "sizeof_expression": "children",
+ "stackalloc_expression": "children",
+ "switch_expression": "children",
+ "throw_expression": "children",
+ "typeof_expression": "children",
+ "with_expression": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "interface_declaration": {
+ "type": "interface_declaration",
+ "singleFieldNames": ["body", "name", "type_parameters"],
+ "nodeTypeToMultipleFieldName": {
+ "attribute_list": "children",
+ "base_list": "children",
+ "modifier": "children",
+ "type_parameter_constraints_clause": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "interpolated_string_expression": {
+ "type": "interpolated_string_expression",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "escape_sequence": "children",
+ "interpolation": "children",
+ "interpolation_quote": "children",
+ "interpolation_start": "children",
+ "string_content": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "interpolation": {
+ "type": "interpolation",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "element_access_expression": "children",
+ "element_binding_expression": "children",
+ "generic_name": "children",
+ "identifier": "children",
+ "member_access_expression": "children",
+ "parenthesized_expression": "children",
+ "prefix_unary_expression": "children",
+ "this": "children",
+ "tuple_expression": "children",
+ "anonymous_method_expression": "children",
+ "anonymous_object_creation_expression": "children",
+ "array_creation_expression": "children",
+ "as_expression": "children",
+ "assignment_expression": "children",
+ "await_expression": "children",
+ "base": "children",
+ "binary_expression": "children",
+ "cast_expression": "children",
+ "checked_expression": "children",
+ "conditional_access_expression": "children",
+ "conditional_expression": "children",
+ "default_expression": "children",
+ "implicit_array_creation_expression": "children",
+ "implicit_object_creation_expression": "children",
+ "implicit_stackalloc_expression": "children",
+ "initializer_expression": "children",
+ "interpolated_string_expression": "children",
+ "invocation_expression": "children",
+ "is_expression": "children",
+ "is_pattern_expression": "children",
+ "lambda_expression": "children",
+ "boolean_literal": "children",
+ "character_literal": "children",
+ "integer_literal": "children",
+ "null_literal": "children",
+ "raw_string_literal": "children",
+ "real_literal": "children",
+ "string_literal": "children",
+ "verbatim_string_literal": "children",
+ "makeref_expression": "children",
+ "object_creation_expression": "children",
+ "postfix_unary_expression": "children",
+ "preproc_if": "children",
+ "query_expression": "children",
+ "range_expression": "children",
+ "ref_expression": "children",
+ "reftype_expression": "children",
+ "refvalue_expression": "children",
+ "sizeof_expression": "children",
+ "stackalloc_expression": "children",
+ "switch_expression": "children",
+ "throw_expression": "children",
+ "typeof_expression": "children",
+ "with_expression": "children",
+ "interpolation_alignment_clause": "children",
+ "interpolation_brace": "children",
+ "interpolation_format_clause": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "interpolation_alignment_clause": {
+ "type": "interpolation_alignment_clause",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "element_access_expression": "children",
+ "element_binding_expression": "children",
+ "generic_name": "children",
+ "identifier": "children",
+ "member_access_expression": "children",
+ "parenthesized_expression": "children",
+ "prefix_unary_expression": "children",
+ "this": "children",
+ "tuple_expression": "children",
+ "anonymous_method_expression": "children",
+ "anonymous_object_creation_expression": "children",
+ "array_creation_expression": "children",
+ "as_expression": "children",
+ "assignment_expression": "children",
+ "await_expression": "children",
+ "base": "children",
+ "binary_expression": "children",
+ "cast_expression": "children",
+ "checked_expression": "children",
+ "conditional_access_expression": "children",
+ "conditional_expression": "children",
+ "default_expression": "children",
+ "implicit_array_creation_expression": "children",
+ "implicit_object_creation_expression": "children",
+ "implicit_stackalloc_expression": "children",
+ "initializer_expression": "children",
+ "interpolated_string_expression": "children",
+ "invocation_expression": "children",
+ "is_expression": "children",
+ "is_pattern_expression": "children",
+ "lambda_expression": "children",
+ "boolean_literal": "children",
+ "character_literal": "children",
+ "integer_literal": "children",
+ "null_literal": "children",
+ "raw_string_literal": "children",
+ "real_literal": "children",
+ "string_literal": "children",
+ "verbatim_string_literal": "children",
+ "makeref_expression": "children",
+ "object_creation_expression": "children",
+ "postfix_unary_expression": "children",
+ "preproc_if": "children",
+ "query_expression": "children",
+ "range_expression": "children",
+ "ref_expression": "children",
+ "reftype_expression": "children",
+ "refvalue_expression": "children",
+ "sizeof_expression": "children",
+ "stackalloc_expression": "children",
+ "switch_expression": "children",
+ "throw_expression": "children",
+ "typeof_expression": "children",
+ "with_expression": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "interpolation_format_clause": {
+ "type": "interpolation_format_clause",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "invocation_expression": {
+ "type": "invocation_expression",
+ "singleFieldNames": ["arguments", "function"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "is_expression": {
+ "type": "is_expression",
+ "singleFieldNames": ["left", "operator", "right"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "is_pattern_expression": {
+ "type": "is_pattern_expression",
+ "singleFieldNames": ["expression", "pattern"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "join_clause": {
+ "type": "join_clause",
+ "singleFieldNames": ["type"],
+ "nodeTypeToMultipleFieldName": {
+ "element_access_expression": "children",
+ "element_binding_expression": "children",
+ "generic_name": "children",
+ "identifier": "children",
+ "member_access_expression": "children",
+ "parenthesized_expression": "children",
+ "prefix_unary_expression": "children",
+ "this": "children",
+ "tuple_expression": "children",
+ "anonymous_method_expression": "children",
+ "anonymous_object_creation_expression": "children",
+ "array_creation_expression": "children",
+ "as_expression": "children",
+ "assignment_expression": "children",
+ "await_expression": "children",
+ "base": "children",
+ "binary_expression": "children",
+ "cast_expression": "children",
+ "checked_expression": "children",
+ "conditional_access_expression": "children",
+ "conditional_expression": "children",
+ "default_expression": "children",
+ "implicit_array_creation_expression": "children",
+ "implicit_object_creation_expression": "children",
+ "implicit_stackalloc_expression": "children",
+ "initializer_expression": "children",
+ "interpolated_string_expression": "children",
+ "invocation_expression": "children",
+ "is_expression": "children",
+ "is_pattern_expression": "children",
+ "lambda_expression": "children",
+ "boolean_literal": "children",
+ "character_literal": "children",
+ "integer_literal": "children",
+ "null_literal": "children",
+ "raw_string_literal": "children",
+ "real_literal": "children",
+ "string_literal": "children",
+ "verbatim_string_literal": "children",
+ "makeref_expression": "children",
+ "object_creation_expression": "children",
+ "postfix_unary_expression": "children",
+ "preproc_if": "children",
+ "query_expression": "children",
+ "range_expression": "children",
+ "ref_expression": "children",
+ "reftype_expression": "children",
+ "refvalue_expression": "children",
+ "sizeof_expression": "children",
+ "stackalloc_expression": "children",
+ "switch_expression": "children",
+ "throw_expression": "children",
+ "typeof_expression": "children",
+ "with_expression": "children",
+ "join_into_clause": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "join_into_clause": {
+ "type": "join_into_clause",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "identifier": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "labeled_statement": {
+ "type": "labeled_statement",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "identifier": "children",
+ "block": "children",
+ "break_statement": "children",
+ "checked_statement": "children",
+ "continue_statement": "children",
+ "do_statement": "children",
+ "empty_statement": "children",
+ "expression_statement": "children",
+ "fixed_statement": "children",
+ "for_statement": "children",
+ "foreach_statement": "children",
+ "goto_statement": "children",
+ "if_statement": "children",
+ "labeled_statement": "children",
+ "local_declaration_statement": "children",
+ "local_function_statement": "children",
+ "lock_statement": "children",
+ "preproc_if": "children",
+ "return_statement": "children",
+ "switch_statement": "children",
+ "throw_statement": "children",
+ "try_statement": "children",
+ "unsafe_statement": "children",
+ "using_statement": "children",
+ "while_statement": "children",
+ "yield_statement": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "lambda_expression": {
+ "type": "lambda_expression",
+ "singleFieldNames": ["body", "parameters", "type"],
+ "nodeTypeToMultipleFieldName": {
+ "attribute_list": "children",
+ "modifier": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "let_clause": {
+ "type": "let_clause",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "element_access_expression": "children",
+ "element_binding_expression": "children",
+ "generic_name": "children",
+ "identifier": "children",
+ "member_access_expression": "children",
+ "parenthesized_expression": "children",
+ "prefix_unary_expression": "children",
+ "this": "children",
+ "tuple_expression": "children",
+ "anonymous_method_expression": "children",
+ "anonymous_object_creation_expression": "children",
+ "array_creation_expression": "children",
+ "as_expression": "children",
+ "assignment_expression": "children",
+ "await_expression": "children",
+ "base": "children",
+ "binary_expression": "children",
+ "cast_expression": "children",
+ "checked_expression": "children",
+ "conditional_access_expression": "children",
+ "conditional_expression": "children",
+ "default_expression": "children",
+ "implicit_array_creation_expression": "children",
+ "implicit_object_creation_expression": "children",
+ "implicit_stackalloc_expression": "children",
+ "initializer_expression": "children",
+ "interpolated_string_expression": "children",
+ "invocation_expression": "children",
+ "is_expression": "children",
+ "is_pattern_expression": "children",
+ "lambda_expression": "children",
+ "boolean_literal": "children",
+ "character_literal": "children",
+ "integer_literal": "children",
+ "null_literal": "children",
+ "raw_string_literal": "children",
+ "real_literal": "children",
+ "string_literal": "children",
+ "verbatim_string_literal": "children",
+ "makeref_expression": "children",
+ "object_creation_expression": "children",
+ "postfix_unary_expression": "children",
+ "preproc_if": "children",
+ "query_expression": "children",
+ "range_expression": "children",
+ "ref_expression": "children",
+ "reftype_expression": "children",
+ "refvalue_expression": "children",
+ "sizeof_expression": "children",
+ "stackalloc_expression": "children",
+ "switch_expression": "children",
+ "throw_expression": "children",
+ "typeof_expression": "children",
+ "with_expression": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "list_pattern": {
+ "type": "list_pattern",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "and_pattern": "children",
+ "constant_pattern": "children",
+ "declaration_pattern": "children",
+ "discard": "children",
+ "list_pattern": "children",
+ "negated_pattern": "children",
+ "or_pattern": "children",
+ "parenthesized_pattern": "children",
+ "recursive_pattern": "children",
+ "relational_pattern": "children",
+ "type_pattern": "children",
+ "var_pattern": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "local_declaration_statement": {
+ "type": "local_declaration_statement",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "modifier": "children",
+ "variable_declaration": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "local_function_statement": {
+ "type": "local_function_statement",
+ "singleFieldNames": [
+ "body",
+ "name",
+ "parameters",
+ "type",
+ "type_parameters"
+ ],
+ "nodeTypeToMultipleFieldName": {
+ "attribute_list": "children",
+ "modifier": "children",
+ "type_parameter_constraints_clause": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "lock_statement": {
+ "type": "lock_statement",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "element_access_expression": "children",
+ "element_binding_expression": "children",
+ "generic_name": "children",
+ "identifier": "children",
+ "member_access_expression": "children",
+ "parenthesized_expression": "children",
+ "prefix_unary_expression": "children",
+ "this": "children",
+ "tuple_expression": "children",
+ "anonymous_method_expression": "children",
+ "anonymous_object_creation_expression": "children",
+ "array_creation_expression": "children",
+ "as_expression": "children",
+ "assignment_expression": "children",
+ "await_expression": "children",
+ "base": "children",
+ "binary_expression": "children",
+ "cast_expression": "children",
+ "checked_expression": "children",
+ "conditional_access_expression": "children",
+ "conditional_expression": "children",
+ "default_expression": "children",
+ "implicit_array_creation_expression": "children",
+ "implicit_object_creation_expression": "children",
+ "implicit_stackalloc_expression": "children",
+ "initializer_expression": "children",
+ "interpolated_string_expression": "children",
+ "invocation_expression": "children",
+ "is_expression": "children",
+ "is_pattern_expression": "children",
+ "lambda_expression": "children",
+ "boolean_literal": "children",
+ "character_literal": "children",
+ "integer_literal": "children",
+ "null_literal": "children",
+ "raw_string_literal": "children",
+ "real_literal": "children",
+ "string_literal": "children",
+ "verbatim_string_literal": "children",
+ "makeref_expression": "children",
+ "object_creation_expression": "children",
+ "postfix_unary_expression": "children",
+ "preproc_if": "children",
+ "query_expression": "children",
+ "range_expression": "children",
+ "ref_expression": "children",
+ "reftype_expression": "children",
+ "refvalue_expression": "children",
+ "sizeof_expression": "children",
+ "stackalloc_expression": "children",
+ "switch_expression": "children",
+ "throw_expression": "children",
+ "typeof_expression": "children",
+ "with_expression": "children",
+ "block": "children",
+ "break_statement": "children",
+ "checked_statement": "children",
+ "continue_statement": "children",
+ "do_statement": "children",
+ "empty_statement": "children",
+ "expression_statement": "children",
+ "fixed_statement": "children",
+ "for_statement": "children",
+ "foreach_statement": "children",
+ "goto_statement": "children",
+ "if_statement": "children",
+ "labeled_statement": "children",
+ "local_declaration_statement": "children",
+ "local_function_statement": "children",
+ "lock_statement": "children",
+ "return_statement": "children",
+ "switch_statement": "children",
+ "throw_statement": "children",
+ "try_statement": "children",
+ "unsafe_statement": "children",
+ "using_statement": "children",
+ "while_statement": "children",
+ "yield_statement": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "makeref_expression": {
+ "type": "makeref_expression",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "element_access_expression": "children",
+ "element_binding_expression": "children",
+ "generic_name": "children",
+ "identifier": "children",
+ "member_access_expression": "children",
+ "parenthesized_expression": "children",
+ "prefix_unary_expression": "children",
+ "this": "children",
+ "tuple_expression": "children",
+ "anonymous_method_expression": "children",
+ "anonymous_object_creation_expression": "children",
+ "array_creation_expression": "children",
+ "as_expression": "children",
+ "assignment_expression": "children",
+ "await_expression": "children",
+ "base": "children",
+ "binary_expression": "children",
+ "cast_expression": "children",
+ "checked_expression": "children",
+ "conditional_access_expression": "children",
+ "conditional_expression": "children",
+ "default_expression": "children",
+ "implicit_array_creation_expression": "children",
+ "implicit_object_creation_expression": "children",
+ "implicit_stackalloc_expression": "children",
+ "initializer_expression": "children",
+ "interpolated_string_expression": "children",
+ "invocation_expression": "children",
+ "is_expression": "children",
+ "is_pattern_expression": "children",
+ "lambda_expression": "children",
+ "boolean_literal": "children",
+ "character_literal": "children",
+ "integer_literal": "children",
+ "null_literal": "children",
+ "raw_string_literal": "children",
+ "real_literal": "children",
+ "string_literal": "children",
+ "verbatim_string_literal": "children",
+ "makeref_expression": "children",
+ "object_creation_expression": "children",
+ "postfix_unary_expression": "children",
+ "preproc_if": "children",
+ "query_expression": "children",
+ "range_expression": "children",
+ "ref_expression": "children",
+ "reftype_expression": "children",
+ "refvalue_expression": "children",
+ "sizeof_expression": "children",
+ "stackalloc_expression": "children",
+ "switch_expression": "children",
+ "throw_expression": "children",
+ "typeof_expression": "children",
+ "with_expression": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "member_access_expression": {
+ "type": "member_access_expression",
+ "singleFieldNames": ["expression", "name"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "member_binding_expression": {
+ "type": "member_binding_expression",
+ "singleFieldNames": ["name"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "method_declaration": {
+ "type": "method_declaration",
+ "singleFieldNames": [
+ "body",
+ "name",
+ "parameters",
+ "returns",
+ "type_parameters"
+ ],
+ "nodeTypeToMultipleFieldName": {
+ "attribute_list": "children",
+ "explicit_interface_specifier": "children",
+ "modifier": "children",
+ "type_parameter_constraints_clause": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "modifier": {
+ "type": "modifier",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "namespace_declaration": {
+ "type": "namespace_declaration",
+ "singleFieldNames": ["body", "name"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "negated_pattern": {
+ "type": "negated_pattern",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "and_pattern": "children",
+ "constant_pattern": "children",
+ "declaration_pattern": "children",
+ "discard": "children",
+ "list_pattern": "children",
+ "negated_pattern": "children",
+ "or_pattern": "children",
+ "parenthesized_pattern": "children",
+ "recursive_pattern": "children",
+ "relational_pattern": "children",
+ "type_pattern": "children",
+ "var_pattern": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "nullable_type": {
+ "type": "nullable_type",
+ "singleFieldNames": ["type"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "object_creation_expression": {
+ "type": "object_creation_expression",
+ "singleFieldNames": ["arguments", "initializer", "type"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "operator_declaration": {
+ "type": "operator_declaration",
+ "singleFieldNames": ["body", "operator", "parameters", "type"],
+ "nodeTypeToMultipleFieldName": {
+ "attribute_list": "children",
+ "explicit_interface_specifier": "children",
+ "modifier": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "or_pattern": {
+ "type": "or_pattern",
+ "singleFieldNames": ["left", "operator", "right"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "order_by_clause": {
+ "type": "order_by_clause",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "element_access_expression": "children",
+ "element_binding_expression": "children",
+ "generic_name": "children",
+ "identifier": "children",
+ "member_access_expression": "children",
+ "parenthesized_expression": "children",
+ "prefix_unary_expression": "children",
+ "this": "children",
+ "tuple_expression": "children",
+ "anonymous_method_expression": "children",
+ "anonymous_object_creation_expression": "children",
+ "array_creation_expression": "children",
+ "as_expression": "children",
+ "assignment_expression": "children",
+ "await_expression": "children",
+ "base": "children",
+ "binary_expression": "children",
+ "cast_expression": "children",
+ "checked_expression": "children",
+ "conditional_access_expression": "children",
+ "conditional_expression": "children",
+ "default_expression": "children",
+ "implicit_array_creation_expression": "children",
+ "implicit_object_creation_expression": "children",
+ "implicit_stackalloc_expression": "children",
+ "initializer_expression": "children",
+ "interpolated_string_expression": "children",
+ "invocation_expression": "children",
+ "is_expression": "children",
+ "is_pattern_expression": "children",
+ "lambda_expression": "children",
+ "boolean_literal": "children",
+ "character_literal": "children",
+ "integer_literal": "children",
+ "null_literal": "children",
+ "raw_string_literal": "children",
+ "real_literal": "children",
+ "string_literal": "children",
+ "verbatim_string_literal": "children",
+ "makeref_expression": "children",
+ "object_creation_expression": "children",
+ "postfix_unary_expression": "children",
+ "preproc_if": "children",
+ "query_expression": "children",
+ "range_expression": "children",
+ "ref_expression": "children",
+ "reftype_expression": "children",
+ "refvalue_expression": "children",
+ "sizeof_expression": "children",
+ "stackalloc_expression": "children",
+ "switch_expression": "children",
+ "throw_expression": "children",
+ "typeof_expression": "children",
+ "with_expression": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "parameter": {
+ "type": "parameter",
+ "singleFieldNames": ["name", "type"],
+ "nodeTypeToMultipleFieldName": {
+ "attribute_list": "children",
+ "element_access_expression": "children",
+ "element_binding_expression": "children",
+ "generic_name": "children",
+ "identifier": "children",
+ "member_access_expression": "children",
+ "parenthesized_expression": "children",
+ "prefix_unary_expression": "children",
+ "this": "children",
+ "tuple_expression": "children",
+ "anonymous_method_expression": "children",
+ "anonymous_object_creation_expression": "children",
+ "array_creation_expression": "children",
+ "as_expression": "children",
+ "assignment_expression": "children",
+ "await_expression": "children",
+ "base": "children",
+ "binary_expression": "children",
+ "cast_expression": "children",
+ "checked_expression": "children",
+ "conditional_access_expression": "children",
+ "conditional_expression": "children",
+ "default_expression": "children",
+ "implicit_array_creation_expression": "children",
+ "implicit_object_creation_expression": "children",
+ "implicit_stackalloc_expression": "children",
+ "initializer_expression": "children",
+ "interpolated_string_expression": "children",
+ "invocation_expression": "children",
+ "is_expression": "children",
+ "is_pattern_expression": "children",
+ "lambda_expression": "children",
+ "boolean_literal": "children",
+ "character_literal": "children",
+ "integer_literal": "children",
+ "null_literal": "children",
+ "raw_string_literal": "children",
+ "real_literal": "children",
+ "string_literal": "children",
+ "verbatim_string_literal": "children",
+ "makeref_expression": "children",
+ "object_creation_expression": "children",
+ "postfix_unary_expression": "children",
+ "preproc_if": "children",
+ "query_expression": "children",
+ "range_expression": "children",
+ "ref_expression": "children",
+ "reftype_expression": "children",
+ "refvalue_expression": "children",
+ "sizeof_expression": "children",
+ "stackalloc_expression": "children",
+ "switch_expression": "children",
+ "throw_expression": "children",
+ "typeof_expression": "children",
+ "with_expression": "children",
+ "modifier": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "parameter_list": {
+ "type": "parameter_list",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "identifier": "name",
+ "array_type": "type",
+ "nullable_type": "type",
+ "attribute_list": "children",
+ "parameter": "children"
+ },
+ "multipleOrChildrenFieldNames": ["name", "type", "children"]
+ },
+ "parenthesized_expression": {
+ "type": "parenthesized_expression",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "boolean_literal": "children",
+ "character_literal": "children",
+ "integer_literal": "children",
+ "element_access_expression": "children",
+ "element_binding_expression": "children",
+ "generic_name": "children",
+ "identifier": "children",
+ "member_access_expression": "children",
+ "parenthesized_expression": "children",
+ "prefix_unary_expression": "children",
+ "this": "children",
+ "tuple_expression": "children",
+ "anonymous_method_expression": "children",
+ "anonymous_object_creation_expression": "children",
+ "array_creation_expression": "children",
+ "as_expression": "children",
+ "assignment_expression": "children",
+ "await_expression": "children",
+ "base": "children",
+ "binary_expression": "children",
+ "cast_expression": "children",
+ "checked_expression": "children",
+ "conditional_access_expression": "children",
+ "conditional_expression": "children",
+ "default_expression": "children",
+ "implicit_array_creation_expression": "children",
+ "implicit_object_creation_expression": "children",
+ "implicit_stackalloc_expression": "children",
+ "initializer_expression": "children",
+ "interpolated_string_expression": "children",
+ "invocation_expression": "children",
+ "is_expression": "children",
+ "is_pattern_expression": "children",
+ "lambda_expression": "children",
+ "null_literal": "children",
+ "raw_string_literal": "children",
+ "real_literal": "children",
+ "string_literal": "children",
+ "verbatim_string_literal": "children",
+ "makeref_expression": "children",
+ "object_creation_expression": "children",
+ "postfix_unary_expression": "children",
+ "preproc_if": "children",
+ "query_expression": "children",
+ "range_expression": "children",
+ "ref_expression": "children",
+ "reftype_expression": "children",
+ "refvalue_expression": "children",
+ "sizeof_expression": "children",
+ "stackalloc_expression": "children",
+ "switch_expression": "children",
+ "throw_expression": "children",
+ "typeof_expression": "children",
+ "with_expression": "children",
+ "unary_expression": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "parenthesized_pattern": {
+ "type": "parenthesized_pattern",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "and_pattern": "children",
+ "constant_pattern": "children",
+ "declaration_pattern": "children",
+ "discard": "children",
+ "list_pattern": "children",
+ "negated_pattern": "children",
+ "or_pattern": "children",
+ "parenthesized_pattern": "children",
+ "recursive_pattern": "children",
+ "relational_pattern": "children",
+ "type_pattern": "children",
+ "var_pattern": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "parenthesized_variable_designation": {
+ "type": "parenthesized_variable_designation",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "identifier": "name",
+ "discard": "children",
+ "parenthesized_variable_designation": "children"
+ },
+ "multipleOrChildrenFieldNames": ["name", "children"]
+ },
+ "pointer_type": {
+ "type": "pointer_type",
+ "singleFieldNames": ["type"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "positional_pattern_clause": {
+ "type": "positional_pattern_clause",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "subpattern": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "postfix_unary_expression": {
+ "type": "postfix_unary_expression",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "element_access_expression": "children",
+ "element_binding_expression": "children",
+ "generic_name": "children",
+ "identifier": "children",
+ "member_access_expression": "children",
+ "parenthesized_expression": "children",
+ "prefix_unary_expression": "children",
+ "this": "children",
+ "tuple_expression": "children",
+ "anonymous_method_expression": "children",
+ "anonymous_object_creation_expression": "children",
+ "array_creation_expression": "children",
+ "as_expression": "children",
+ "assignment_expression": "children",
+ "await_expression": "children",
+ "base": "children",
+ "binary_expression": "children",
+ "cast_expression": "children",
+ "checked_expression": "children",
+ "conditional_access_expression": "children",
+ "conditional_expression": "children",
+ "default_expression": "children",
+ "implicit_array_creation_expression": "children",
+ "implicit_object_creation_expression": "children",
+ "implicit_stackalloc_expression": "children",
+ "initializer_expression": "children",
+ "interpolated_string_expression": "children",
+ "invocation_expression": "children",
+ "is_expression": "children",
+ "is_pattern_expression": "children",
+ "lambda_expression": "children",
+ "boolean_literal": "children",
+ "character_literal": "children",
+ "integer_literal": "children",
+ "null_literal": "children",
+ "raw_string_literal": "children",
+ "real_literal": "children",
+ "string_literal": "children",
+ "verbatim_string_literal": "children",
+ "makeref_expression": "children",
+ "object_creation_expression": "children",
+ "postfix_unary_expression": "children",
+ "preproc_if": "children",
+ "query_expression": "children",
+ "range_expression": "children",
+ "ref_expression": "children",
+ "reftype_expression": "children",
+ "refvalue_expression": "children",
+ "sizeof_expression": "children",
+ "stackalloc_expression": "children",
+ "switch_expression": "children",
+ "throw_expression": "children",
+ "typeof_expression": "children",
+ "with_expression": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "prefix_unary_expression": {
+ "type": "prefix_unary_expression",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "element_access_expression": "children",
+ "element_binding_expression": "children",
+ "generic_name": "children",
+ "identifier": "children",
+ "member_access_expression": "children",
+ "parenthesized_expression": "children",
+ "prefix_unary_expression": "children",
+ "this": "children",
+ "tuple_expression": "children",
+ "anonymous_method_expression": "children",
+ "anonymous_object_creation_expression": "children",
+ "array_creation_expression": "children",
+ "as_expression": "children",
+ "assignment_expression": "children",
+ "await_expression": "children",
+ "base": "children",
+ "binary_expression": "children",
+ "cast_expression": "children",
+ "checked_expression": "children",
+ "conditional_access_expression": "children",
+ "conditional_expression": "children",
+ "default_expression": "children",
+ "implicit_array_creation_expression": "children",
+ "implicit_object_creation_expression": "children",
+ "implicit_stackalloc_expression": "children",
+ "initializer_expression": "children",
+ "interpolated_string_expression": "children",
+ "invocation_expression": "children",
+ "is_expression": "children",
+ "is_pattern_expression": "children",
+ "lambda_expression": "children",
+ "boolean_literal": "children",
+ "character_literal": "children",
+ "integer_literal": "children",
+ "null_literal": "children",
+ "raw_string_literal": "children",
+ "real_literal": "children",
+ "string_literal": "children",
+ "verbatim_string_literal": "children",
+ "makeref_expression": "children",
+ "object_creation_expression": "children",
+ "postfix_unary_expression": "children",
+ "preproc_if": "children",
+ "query_expression": "children",
+ "range_expression": "children",
+ "ref_expression": "children",
+ "reftype_expression": "children",
+ "refvalue_expression": "children",
+ "sizeof_expression": "children",
+ "stackalloc_expression": "children",
+ "switch_expression": "children",
+ "throw_expression": "children",
+ "typeof_expression": "children",
+ "with_expression": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "preproc_define": {
+ "type": "preproc_define",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "preproc_arg": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "preproc_elif": {
+ "type": "preproc_elif",
+ "singleFieldNames": ["alternative", "condition"],
+ "nodeTypeToMultipleFieldName": {
+ "class_declaration": "children",
+ "constructor_declaration": "children",
+ "conversion_operator_declaration": "children",
+ "delegate_declaration": "children",
+ "destructor_declaration": "children",
+ "enum_declaration": "children",
+ "event_declaration": "children",
+ "event_field_declaration": "children",
+ "field_declaration": "children",
+ "indexer_declaration": "children",
+ "interface_declaration": "children",
+ "method_declaration": "children",
+ "namespace_declaration": "children",
+ "operator_declaration": "children",
+ "preproc_if": "children",
+ "property_declaration": "children",
+ "record_declaration": "children",
+ "struct_declaration": "children",
+ "using_directive": "children",
+ "enum_member_declaration": "children",
+ "element_access_expression": "children",
+ "element_binding_expression": "children",
+ "generic_name": "children",
+ "identifier": "children",
+ "member_access_expression": "children",
+ "parenthesized_expression": "children",
+ "prefix_unary_expression": "children",
+ "this": "children",
+ "tuple_expression": "children",
+ "anonymous_method_expression": "children",
+ "anonymous_object_creation_expression": "children",
+ "array_creation_expression": "children",
+ "as_expression": "children",
+ "assignment_expression": "children",
+ "await_expression": "children",
+ "base": "children",
+ "binary_expression": "children",
+ "cast_expression": "children",
+ "checked_expression": "children",
+ "conditional_access_expression": "children",
+ "conditional_expression": "children",
+ "default_expression": "children",
+ "implicit_array_creation_expression": "children",
+ "implicit_object_creation_expression": "children",
+ "implicit_stackalloc_expression": "children",
+ "initializer_expression": "children",
+ "interpolated_string_expression": "children",
+ "invocation_expression": "children",
+ "is_expression": "children",
+ "is_pattern_expression": "children",
+ "lambda_expression": "children",
+ "boolean_literal": "children",
+ "character_literal": "children",
+ "integer_literal": "children",
+ "null_literal": "children",
+ "raw_string_literal": "children",
+ "real_literal": "children",
+ "string_literal": "children",
+ "verbatim_string_literal": "children",
+ "makeref_expression": "children",
+ "object_creation_expression": "children",
+ "postfix_unary_expression": "children",
+ "query_expression": "children",
+ "range_expression": "children",
+ "ref_expression": "children",
+ "reftype_expression": "children",
+ "refvalue_expression": "children",
+ "sizeof_expression": "children",
+ "stackalloc_expression": "children",
+ "switch_expression": "children",
+ "throw_expression": "children",
+ "typeof_expression": "children",
+ "with_expression": "children",
+ "extern_alias_directive": "children",
+ "file_scoped_namespace_declaration": "children",
+ "global_attribute": "children",
+ "block": "children",
+ "break_statement": "children",
+ "checked_statement": "children",
+ "continue_statement": "children",
+ "do_statement": "children",
+ "empty_statement": "children",
+ "expression_statement": "children",
+ "fixed_statement": "children",
+ "for_statement": "children",
+ "foreach_statement": "children",
+ "goto_statement": "children",
+ "if_statement": "children",
+ "labeled_statement": "children",
+ "local_declaration_statement": "children",
+ "local_function_statement": "children",
+ "lock_statement": "children",
+ "return_statement": "children",
+ "switch_statement": "children",
+ "throw_statement": "children",
+ "try_statement": "children",
+ "unsafe_statement": "children",
+ "using_statement": "children",
+ "while_statement": "children",
+ "yield_statement": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "preproc_else": {
+ "type": "preproc_else",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "class_declaration": "children",
+ "constructor_declaration": "children",
+ "conversion_operator_declaration": "children",
+ "delegate_declaration": "children",
+ "destructor_declaration": "children",
+ "enum_declaration": "children",
+ "event_declaration": "children",
+ "event_field_declaration": "children",
+ "field_declaration": "children",
+ "indexer_declaration": "children",
+ "interface_declaration": "children",
+ "method_declaration": "children",
+ "namespace_declaration": "children",
+ "operator_declaration": "children",
+ "preproc_if": "children",
+ "property_declaration": "children",
+ "record_declaration": "children",
+ "struct_declaration": "children",
+ "using_directive": "children",
+ "enum_member_declaration": "children",
+ "element_access_expression": "children",
+ "element_binding_expression": "children",
+ "generic_name": "children",
+ "identifier": "children",
+ "member_access_expression": "children",
+ "parenthesized_expression": "children",
+ "prefix_unary_expression": "children",
+ "this": "children",
+ "tuple_expression": "children",
+ "anonymous_method_expression": "children",
+ "anonymous_object_creation_expression": "children",
+ "array_creation_expression": "children",
+ "as_expression": "children",
+ "assignment_expression": "children",
+ "await_expression": "children",
+ "base": "children",
+ "binary_expression": "children",
+ "cast_expression": "children",
+ "checked_expression": "children",
+ "conditional_access_expression": "children",
+ "conditional_expression": "children",
+ "default_expression": "children",
+ "implicit_array_creation_expression": "children",
+ "implicit_object_creation_expression": "children",
+ "implicit_stackalloc_expression": "children",
+ "initializer_expression": "children",
+ "interpolated_string_expression": "children",
+ "invocation_expression": "children",
+ "is_expression": "children",
+ "is_pattern_expression": "children",
+ "lambda_expression": "children",
+ "boolean_literal": "children",
+ "character_literal": "children",
+ "integer_literal": "children",
+ "null_literal": "children",
+ "raw_string_literal": "children",
+ "real_literal": "children",
+ "string_literal": "children",
+ "verbatim_string_literal": "children",
+ "makeref_expression": "children",
+ "object_creation_expression": "children",
+ "postfix_unary_expression": "children",
+ "query_expression": "children",
+ "range_expression": "children",
+ "ref_expression": "children",
+ "reftype_expression": "children",
+ "refvalue_expression": "children",
+ "sizeof_expression": "children",
+ "stackalloc_expression": "children",
+ "switch_expression": "children",
+ "throw_expression": "children",
+ "typeof_expression": "children",
+ "with_expression": "children",
+ "extern_alias_directive": "children",
+ "file_scoped_namespace_declaration": "children",
+ "global_attribute": "children",
+ "block": "children",
+ "break_statement": "children",
+ "checked_statement": "children",
+ "continue_statement": "children",
+ "do_statement": "children",
+ "empty_statement": "children",
+ "expression_statement": "children",
+ "fixed_statement": "children",
+ "for_statement": "children",
+ "foreach_statement": "children",
+ "goto_statement": "children",
+ "if_statement": "children",
+ "labeled_statement": "children",
+ "local_declaration_statement": "children",
+ "local_function_statement": "children",
+ "lock_statement": "children",
+ "return_statement": "children",
+ "switch_statement": "children",
+ "throw_statement": "children",
+ "try_statement": "children",
+ "unsafe_statement": "children",
+ "using_statement": "children",
+ "while_statement": "children",
+ "yield_statement": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "preproc_endregion": {
+ "type": "preproc_endregion",
+ "singleFieldNames": ["content"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "preproc_error": {
+ "type": "preproc_error",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "preproc_arg": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "preproc_if": {
+ "type": "preproc_if",
+ "singleFieldNames": ["alternative", "condition"],
+ "nodeTypeToMultipleFieldName": {
+ "class_declaration": "children",
+ "constructor_declaration": "children",
+ "conversion_operator_declaration": "children",
+ "delegate_declaration": "children",
+ "destructor_declaration": "children",
+ "enum_declaration": "children",
+ "event_declaration": "children",
+ "event_field_declaration": "children",
+ "field_declaration": "children",
+ "indexer_declaration": "children",
+ "interface_declaration": "children",
+ "method_declaration": "children",
+ "namespace_declaration": "children",
+ "operator_declaration": "children",
+ "preproc_if": "children",
+ "property_declaration": "children",
+ "record_declaration": "children",
+ "struct_declaration": "children",
+ "using_directive": "children",
+ "enum_member_declaration": "children",
+ "element_access_expression": "children",
+ "element_binding_expression": "children",
+ "generic_name": "children",
+ "identifier": "children",
+ "member_access_expression": "children",
+ "parenthesized_expression": "children",
+ "prefix_unary_expression": "children",
+ "this": "children",
+ "tuple_expression": "children",
+ "anonymous_method_expression": "children",
+ "anonymous_object_creation_expression": "children",
+ "array_creation_expression": "children",
+ "as_expression": "children",
+ "assignment_expression": "children",
+ "await_expression": "children",
+ "base": "children",
+ "binary_expression": "children",
+ "cast_expression": "children",
+ "checked_expression": "children",
+ "conditional_access_expression": "children",
+ "conditional_expression": "children",
+ "default_expression": "children",
+ "implicit_array_creation_expression": "children",
+ "implicit_object_creation_expression": "children",
+ "implicit_stackalloc_expression": "children",
+ "initializer_expression": "children",
+ "interpolated_string_expression": "children",
+ "invocation_expression": "children",
+ "is_expression": "children",
+ "is_pattern_expression": "children",
+ "lambda_expression": "children",
+ "boolean_literal": "children",
+ "character_literal": "children",
+ "integer_literal": "children",
+ "null_literal": "children",
+ "raw_string_literal": "children",
+ "real_literal": "children",
+ "string_literal": "children",
+ "verbatim_string_literal": "children",
+ "makeref_expression": "children",
+ "object_creation_expression": "children",
+ "postfix_unary_expression": "children",
+ "query_expression": "children",
+ "range_expression": "children",
+ "ref_expression": "children",
+ "reftype_expression": "children",
+ "refvalue_expression": "children",
+ "sizeof_expression": "children",
+ "stackalloc_expression": "children",
+ "switch_expression": "children",
+ "throw_expression": "children",
+ "typeof_expression": "children",
+ "with_expression": "children",
+ "extern_alias_directive": "children",
+ "file_scoped_namespace_declaration": "children",
+ "global_attribute": "children",
+ "block": "children",
+ "break_statement": "children",
+ "checked_statement": "children",
+ "continue_statement": "children",
+ "do_statement": "children",
+ "empty_statement": "children",
+ "expression_statement": "children",
+ "fixed_statement": "children",
+ "for_statement": "children",
+ "foreach_statement": "children",
+ "goto_statement": "children",
+ "if_statement": "children",
+ "labeled_statement": "children",
+ "local_declaration_statement": "children",
+ "local_function_statement": "children",
+ "lock_statement": "children",
+ "return_statement": "children",
+ "switch_statement": "children",
+ "throw_statement": "children",
+ "try_statement": "children",
+ "unsafe_statement": "children",
+ "using_statement": "children",
+ "while_statement": "children",
+ "yield_statement": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "preproc_line": {
+ "type": "preproc_line",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "integer_literal": "children",
+ "string_literal": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "preproc_nullable": {
+ "type": "preproc_nullable",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "preproc_pragma": {
+ "type": "preproc_pragma",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "identifier": "children",
+ "integer_literal": "children",
+ "string_literal": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "preproc_region": {
+ "type": "preproc_region",
+ "singleFieldNames": ["content"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "preproc_undef": {
+ "type": "preproc_undef",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "preproc_arg": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "primary_constructor_base_type": {
+ "type": "primary_constructor_base_type",
+ "singleFieldNames": ["type"],
+ "nodeTypeToMultipleFieldName": {
+ "argument_list": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "property_declaration": {
+ "type": "property_declaration",
+ "singleFieldNames": ["accessors", "name", "type", "value"],
+ "nodeTypeToMultipleFieldName": {
+ "attribute_list": "children",
+ "explicit_interface_specifier": "children",
+ "modifier": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "property_pattern_clause": {
+ "type": "property_pattern_clause",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "subpattern": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "qualified_name": {
+ "type": "qualified_name",
+ "singleFieldNames": ["name", "qualifier"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "query_expression": {
+ "type": "query_expression",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "from_clause": "children",
+ "group_clause": "children",
+ "identifier": "children",
+ "join_clause": "children",
+ "let_clause": "children",
+ "order_by_clause": "children",
+ "select_clause": "children",
+ "where_clause": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "range_expression": {
+ "type": "range_expression",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "element_access_expression": "children",
+ "element_binding_expression": "children",
+ "generic_name": "children",
+ "identifier": "children",
+ "member_access_expression": "children",
+ "parenthesized_expression": "children",
+ "prefix_unary_expression": "children",
+ "this": "children",
+ "tuple_expression": "children",
+ "anonymous_method_expression": "children",
+ "anonymous_object_creation_expression": "children",
+ "array_creation_expression": "children",
+ "as_expression": "children",
+ "assignment_expression": "children",
+ "await_expression": "children",
+ "base": "children",
+ "binary_expression": "children",
+ "cast_expression": "children",
+ "checked_expression": "children",
+ "conditional_access_expression": "children",
+ "conditional_expression": "children",
+ "default_expression": "children",
+ "implicit_array_creation_expression": "children",
+ "implicit_object_creation_expression": "children",
+ "implicit_stackalloc_expression": "children",
+ "initializer_expression": "children",
+ "interpolated_string_expression": "children",
+ "invocation_expression": "children",
+ "is_expression": "children",
+ "is_pattern_expression": "children",
+ "lambda_expression": "children",
+ "boolean_literal": "children",
+ "character_literal": "children",
+ "integer_literal": "children",
+ "null_literal": "children",
+ "raw_string_literal": "children",
+ "real_literal": "children",
+ "string_literal": "children",
+ "verbatim_string_literal": "children",
+ "makeref_expression": "children",
+ "object_creation_expression": "children",
+ "postfix_unary_expression": "children",
+ "preproc_if": "children",
+ "query_expression": "children",
+ "range_expression": "children",
+ "ref_expression": "children",
+ "reftype_expression": "children",
+ "refvalue_expression": "children",
+ "sizeof_expression": "children",
+ "stackalloc_expression": "children",
+ "switch_expression": "children",
+ "throw_expression": "children",
+ "typeof_expression": "children",
+ "with_expression": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "raw_string_literal": {
+ "type": "raw_string_literal",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "raw_string_content": "children",
+ "raw_string_end": "children",
+ "raw_string_start": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "record_declaration": {
+ "type": "record_declaration",
+ "singleFieldNames": ["body", "name"],
+ "nodeTypeToMultipleFieldName": {
+ "attribute_list": "children",
+ "base_list": "children",
+ "modifier": "children",
+ "parameter_list": "children",
+ "type_parameter_constraints_clause": "children",
+ "type_parameter_list": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "recursive_pattern": {
+ "type": "recursive_pattern",
+ "singleFieldNames": ["name", "type"],
+ "nodeTypeToMultipleFieldName": {
+ "discard": "children",
+ "parenthesized_variable_designation": "children",
+ "positional_pattern_clause": "children",
+ "property_pattern_clause": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "ref_expression": {
+ "type": "ref_expression",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "element_access_expression": "children",
+ "element_binding_expression": "children",
+ "generic_name": "children",
+ "identifier": "children",
+ "member_access_expression": "children",
+ "parenthesized_expression": "children",
+ "prefix_unary_expression": "children",
+ "this": "children",
+ "tuple_expression": "children",
+ "anonymous_method_expression": "children",
+ "anonymous_object_creation_expression": "children",
+ "array_creation_expression": "children",
+ "as_expression": "children",
+ "assignment_expression": "children",
+ "await_expression": "children",
+ "base": "children",
+ "binary_expression": "children",
+ "cast_expression": "children",
+ "checked_expression": "children",
+ "conditional_access_expression": "children",
+ "conditional_expression": "children",
+ "default_expression": "children",
+ "implicit_array_creation_expression": "children",
+ "implicit_object_creation_expression": "children",
+ "implicit_stackalloc_expression": "children",
+ "initializer_expression": "children",
+ "interpolated_string_expression": "children",
+ "invocation_expression": "children",
+ "is_expression": "children",
+ "is_pattern_expression": "children",
+ "lambda_expression": "children",
+ "boolean_literal": "children",
+ "character_literal": "children",
+ "integer_literal": "children",
+ "null_literal": "children",
+ "raw_string_literal": "children",
+ "real_literal": "children",
+ "string_literal": "children",
+ "verbatim_string_literal": "children",
+ "makeref_expression": "children",
+ "object_creation_expression": "children",
+ "postfix_unary_expression": "children",
+ "preproc_if": "children",
+ "query_expression": "children",
+ "range_expression": "children",
+ "ref_expression": "children",
+ "reftype_expression": "children",
+ "refvalue_expression": "children",
+ "sizeof_expression": "children",
+ "stackalloc_expression": "children",
+ "switch_expression": "children",
+ "throw_expression": "children",
+ "typeof_expression": "children",
+ "with_expression": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "ref_type": {
+ "type": "ref_type",
+ "singleFieldNames": ["type"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "reftype_expression": {
+ "type": "reftype_expression",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "element_access_expression": "children",
+ "element_binding_expression": "children",
+ "generic_name": "children",
+ "identifier": "children",
+ "member_access_expression": "children",
+ "parenthesized_expression": "children",
+ "prefix_unary_expression": "children",
+ "this": "children",
+ "tuple_expression": "children",
+ "anonymous_method_expression": "children",
+ "anonymous_object_creation_expression": "children",
+ "array_creation_expression": "children",
+ "as_expression": "children",
+ "assignment_expression": "children",
+ "await_expression": "children",
+ "base": "children",
+ "binary_expression": "children",
+ "cast_expression": "children",
+ "checked_expression": "children",
+ "conditional_access_expression": "children",
+ "conditional_expression": "children",
+ "default_expression": "children",
+ "implicit_array_creation_expression": "children",
+ "implicit_object_creation_expression": "children",
+ "implicit_stackalloc_expression": "children",
+ "initializer_expression": "children",
+ "interpolated_string_expression": "children",
+ "invocation_expression": "children",
+ "is_expression": "children",
+ "is_pattern_expression": "children",
+ "lambda_expression": "children",
+ "boolean_literal": "children",
+ "character_literal": "children",
+ "integer_literal": "children",
+ "null_literal": "children",
+ "raw_string_literal": "children",
+ "real_literal": "children",
+ "string_literal": "children",
+ "verbatim_string_literal": "children",
+ "makeref_expression": "children",
+ "object_creation_expression": "children",
+ "postfix_unary_expression": "children",
+ "preproc_if": "children",
+ "query_expression": "children",
+ "range_expression": "children",
+ "ref_expression": "children",
+ "reftype_expression": "children",
+ "refvalue_expression": "children",
+ "sizeof_expression": "children",
+ "stackalloc_expression": "children",
+ "switch_expression": "children",
+ "throw_expression": "children",
+ "typeof_expression": "children",
+ "with_expression": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "refvalue_expression": {
+ "type": "refvalue_expression",
+ "singleFieldNames": ["type", "value"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "relational_pattern": {
+ "type": "relational_pattern",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "element_access_expression": "children",
+ "element_binding_expression": "children",
+ "generic_name": "children",
+ "identifier": "children",
+ "member_access_expression": "children",
+ "parenthesized_expression": "children",
+ "prefix_unary_expression": "children",
+ "this": "children",
+ "tuple_expression": "children",
+ "anonymous_method_expression": "children",
+ "anonymous_object_creation_expression": "children",
+ "array_creation_expression": "children",
+ "as_expression": "children",
+ "assignment_expression": "children",
+ "await_expression": "children",
+ "base": "children",
+ "binary_expression": "children",
+ "cast_expression": "children",
+ "checked_expression": "children",
+ "conditional_access_expression": "children",
+ "conditional_expression": "children",
+ "default_expression": "children",
+ "implicit_array_creation_expression": "children",
+ "implicit_object_creation_expression": "children",
+ "implicit_stackalloc_expression": "children",
+ "initializer_expression": "children",
+ "interpolated_string_expression": "children",
+ "invocation_expression": "children",
+ "is_expression": "children",
+ "is_pattern_expression": "children",
+ "lambda_expression": "children",
+ "boolean_literal": "children",
+ "character_literal": "children",
+ "integer_literal": "children",
+ "null_literal": "children",
+ "raw_string_literal": "children",
+ "real_literal": "children",
+ "string_literal": "children",
+ "verbatim_string_literal": "children",
+ "makeref_expression": "children",
+ "object_creation_expression": "children",
+ "postfix_unary_expression": "children",
+ "preproc_if": "children",
+ "query_expression": "children",
+ "range_expression": "children",
+ "ref_expression": "children",
+ "reftype_expression": "children",
+ "refvalue_expression": "children",
+ "sizeof_expression": "children",
+ "stackalloc_expression": "children",
+ "switch_expression": "children",
+ "throw_expression": "children",
+ "typeof_expression": "children",
+ "with_expression": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "return_statement": {
+ "type": "return_statement",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "element_access_expression": "children",
+ "element_binding_expression": "children",
+ "generic_name": "children",
+ "identifier": "children",
+ "member_access_expression": "children",
+ "parenthesized_expression": "children",
+ "prefix_unary_expression": "children",
+ "this": "children",
+ "tuple_expression": "children",
+ "anonymous_method_expression": "children",
+ "anonymous_object_creation_expression": "children",
+ "array_creation_expression": "children",
+ "as_expression": "children",
+ "assignment_expression": "children",
+ "await_expression": "children",
+ "base": "children",
+ "binary_expression": "children",
+ "cast_expression": "children",
+ "checked_expression": "children",
+ "conditional_access_expression": "children",
+ "conditional_expression": "children",
+ "default_expression": "children",
+ "implicit_array_creation_expression": "children",
+ "implicit_object_creation_expression": "children",
+ "implicit_stackalloc_expression": "children",
+ "initializer_expression": "children",
+ "interpolated_string_expression": "children",
+ "invocation_expression": "children",
+ "is_expression": "children",
+ "is_pattern_expression": "children",
+ "lambda_expression": "children",
+ "boolean_literal": "children",
+ "character_literal": "children",
+ "integer_literal": "children",
+ "null_literal": "children",
+ "raw_string_literal": "children",
+ "real_literal": "children",
+ "string_literal": "children",
+ "verbatim_string_literal": "children",
+ "makeref_expression": "children",
+ "object_creation_expression": "children",
+ "postfix_unary_expression": "children",
+ "preproc_if": "children",
+ "query_expression": "children",
+ "range_expression": "children",
+ "ref_expression": "children",
+ "reftype_expression": "children",
+ "refvalue_expression": "children",
+ "sizeof_expression": "children",
+ "stackalloc_expression": "children",
+ "switch_expression": "children",
+ "throw_expression": "children",
+ "typeof_expression": "children",
+ "with_expression": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "scoped_type": {
+ "type": "scoped_type",
+ "singleFieldNames": ["type"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "select_clause": {
+ "type": "select_clause",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "element_access_expression": "children",
+ "element_binding_expression": "children",
+ "generic_name": "children",
+ "identifier": "children",
+ "member_access_expression": "children",
+ "parenthesized_expression": "children",
+ "prefix_unary_expression": "children",
+ "this": "children",
+ "tuple_expression": "children",
+ "anonymous_method_expression": "children",
+ "anonymous_object_creation_expression": "children",
+ "array_creation_expression": "children",
+ "as_expression": "children",
+ "assignment_expression": "children",
+ "await_expression": "children",
+ "base": "children",
+ "binary_expression": "children",
+ "cast_expression": "children",
+ "checked_expression": "children",
+ "conditional_access_expression": "children",
+ "conditional_expression": "children",
+ "default_expression": "children",
+ "implicit_array_creation_expression": "children",
+ "implicit_object_creation_expression": "children",
+ "implicit_stackalloc_expression": "children",
+ "initializer_expression": "children",
+ "interpolated_string_expression": "children",
+ "invocation_expression": "children",
+ "is_expression": "children",
+ "is_pattern_expression": "children",
+ "lambda_expression": "children",
+ "boolean_literal": "children",
+ "character_literal": "children",
+ "integer_literal": "children",
+ "null_literal": "children",
+ "raw_string_literal": "children",
+ "real_literal": "children",
+ "string_literal": "children",
+ "verbatim_string_literal": "children",
+ "makeref_expression": "children",
+ "object_creation_expression": "children",
+ "postfix_unary_expression": "children",
+ "preproc_if": "children",
+ "query_expression": "children",
+ "range_expression": "children",
+ "ref_expression": "children",
+ "reftype_expression": "children",
+ "refvalue_expression": "children",
+ "sizeof_expression": "children",
+ "stackalloc_expression": "children",
+ "switch_expression": "children",
+ "throw_expression": "children",
+ "typeof_expression": "children",
+ "with_expression": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "sizeof_expression": {
+ "type": "sizeof_expression",
+ "singleFieldNames": ["type"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "stackalloc_expression": {
+ "type": "stackalloc_expression",
+ "singleFieldNames": ["type"],
+ "nodeTypeToMultipleFieldName": {
+ "initializer_expression": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "string_literal": {
+ "type": "string_literal",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "escape_sequence": "children",
+ "string_literal_content": "children",
+ "string_literal_encoding": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "string_literal_content": {
+ "type": "string_literal_content",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "struct_declaration": {
+ "type": "struct_declaration",
+ "singleFieldNames": ["body", "name"],
+ "nodeTypeToMultipleFieldName": {
+ "attribute_list": "children",
+ "base_list": "children",
+ "modifier": "children",
+ "parameter_list": "children",
+ "type_parameter_constraints_clause": "children",
+ "type_parameter_list": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "subpattern": {
+ "type": "subpattern",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "element_access_expression": "children",
+ "element_binding_expression": "children",
+ "generic_name": "children",
+ "identifier": "children",
+ "member_access_expression": "children",
+ "parenthesized_expression": "children",
+ "prefix_unary_expression": "children",
+ "this": "children",
+ "tuple_expression": "children",
+ "anonymous_method_expression": "children",
+ "anonymous_object_creation_expression": "children",
+ "array_creation_expression": "children",
+ "as_expression": "children",
+ "assignment_expression": "children",
+ "await_expression": "children",
+ "base": "children",
+ "binary_expression": "children",
+ "cast_expression": "children",
+ "checked_expression": "children",
+ "conditional_access_expression": "children",
+ "conditional_expression": "children",
+ "default_expression": "children",
+ "implicit_array_creation_expression": "children",
+ "implicit_object_creation_expression": "children",
+ "implicit_stackalloc_expression": "children",
+ "initializer_expression": "children",
+ "interpolated_string_expression": "children",
+ "invocation_expression": "children",
+ "is_expression": "children",
+ "is_pattern_expression": "children",
+ "lambda_expression": "children",
+ "boolean_literal": "children",
+ "character_literal": "children",
+ "integer_literal": "children",
+ "null_literal": "children",
+ "raw_string_literal": "children",
+ "real_literal": "children",
+ "string_literal": "children",
+ "verbatim_string_literal": "children",
+ "makeref_expression": "children",
+ "object_creation_expression": "children",
+ "postfix_unary_expression": "children",
+ "preproc_if": "children",
+ "query_expression": "children",
+ "range_expression": "children",
+ "ref_expression": "children",
+ "reftype_expression": "children",
+ "refvalue_expression": "children",
+ "sizeof_expression": "children",
+ "stackalloc_expression": "children",
+ "switch_expression": "children",
+ "throw_expression": "children",
+ "typeof_expression": "children",
+ "with_expression": "children",
+ "and_pattern": "children",
+ "constant_pattern": "children",
+ "declaration_pattern": "children",
+ "discard": "children",
+ "list_pattern": "children",
+ "negated_pattern": "children",
+ "or_pattern": "children",
+ "parenthesized_pattern": "children",
+ "recursive_pattern": "children",
+ "relational_pattern": "children",
+ "type_pattern": "children",
+ "var_pattern": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "switch_body": {
+ "type": "switch_body",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "switch_section": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "switch_expression": {
+ "type": "switch_expression",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "element_access_expression": "children",
+ "element_binding_expression": "children",
+ "generic_name": "children",
+ "identifier": "children",
+ "member_access_expression": "children",
+ "parenthesized_expression": "children",
+ "prefix_unary_expression": "children",
+ "this": "children",
+ "tuple_expression": "children",
+ "anonymous_method_expression": "children",
+ "anonymous_object_creation_expression": "children",
+ "array_creation_expression": "children",
+ "as_expression": "children",
+ "assignment_expression": "children",
+ "await_expression": "children",
+ "base": "children",
+ "binary_expression": "children",
+ "cast_expression": "children",
+ "checked_expression": "children",
+ "conditional_access_expression": "children",
+ "conditional_expression": "children",
+ "default_expression": "children",
+ "implicit_array_creation_expression": "children",
+ "implicit_object_creation_expression": "children",
+ "implicit_stackalloc_expression": "children",
+ "initializer_expression": "children",
+ "interpolated_string_expression": "children",
+ "invocation_expression": "children",
+ "is_expression": "children",
+ "is_pattern_expression": "children",
+ "lambda_expression": "children",
+ "boolean_literal": "children",
+ "character_literal": "children",
+ "integer_literal": "children",
+ "null_literal": "children",
+ "raw_string_literal": "children",
+ "real_literal": "children",
+ "string_literal": "children",
+ "verbatim_string_literal": "children",
+ "makeref_expression": "children",
+ "object_creation_expression": "children",
+ "postfix_unary_expression": "children",
+ "preproc_if": "children",
+ "query_expression": "children",
+ "range_expression": "children",
+ "ref_expression": "children",
+ "reftype_expression": "children",
+ "refvalue_expression": "children",
+ "sizeof_expression": "children",
+ "stackalloc_expression": "children",
+ "switch_expression": "children",
+ "throw_expression": "children",
+ "typeof_expression": "children",
+ "with_expression": "children",
+ "switch_expression_arm": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "switch_expression_arm": {
+ "type": "switch_expression_arm",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "element_access_expression": "children",
+ "element_binding_expression": "children",
+ "generic_name": "children",
+ "identifier": "children",
+ "member_access_expression": "children",
+ "parenthesized_expression": "children",
+ "prefix_unary_expression": "children",
+ "this": "children",
+ "tuple_expression": "children",
+ "anonymous_method_expression": "children",
+ "anonymous_object_creation_expression": "children",
+ "array_creation_expression": "children",
+ "as_expression": "children",
+ "assignment_expression": "children",
+ "await_expression": "children",
+ "base": "children",
+ "binary_expression": "children",
+ "cast_expression": "children",
+ "checked_expression": "children",
+ "conditional_access_expression": "children",
+ "conditional_expression": "children",
+ "default_expression": "children",
+ "implicit_array_creation_expression": "children",
+ "implicit_object_creation_expression": "children",
+ "implicit_stackalloc_expression": "children",
+ "initializer_expression": "children",
+ "interpolated_string_expression": "children",
+ "invocation_expression": "children",
+ "is_expression": "children",
+ "is_pattern_expression": "children",
+ "lambda_expression": "children",
+ "boolean_literal": "children",
+ "character_literal": "children",
+ "integer_literal": "children",
+ "null_literal": "children",
+ "raw_string_literal": "children",
+ "real_literal": "children",
+ "string_literal": "children",
+ "verbatim_string_literal": "children",
+ "makeref_expression": "children",
+ "object_creation_expression": "children",
+ "postfix_unary_expression": "children",
+ "preproc_if": "children",
+ "query_expression": "children",
+ "range_expression": "children",
+ "ref_expression": "children",
+ "reftype_expression": "children",
+ "refvalue_expression": "children",
+ "sizeof_expression": "children",
+ "stackalloc_expression": "children",
+ "switch_expression": "children",
+ "throw_expression": "children",
+ "typeof_expression": "children",
+ "with_expression": "children",
+ "and_pattern": "children",
+ "constant_pattern": "children",
+ "declaration_pattern": "children",
+ "discard": "children",
+ "list_pattern": "children",
+ "negated_pattern": "children",
+ "or_pattern": "children",
+ "parenthesized_pattern": "children",
+ "recursive_pattern": "children",
+ "relational_pattern": "children",
+ "type_pattern": "children",
+ "var_pattern": "children",
+ "when_clause": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "switch_section": {
+ "type": "switch_section",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "element_access_expression": "children",
+ "element_binding_expression": "children",
+ "generic_name": "children",
+ "identifier": "children",
+ "member_access_expression": "children",
+ "parenthesized_expression": "children",
+ "prefix_unary_expression": "children",
+ "this": "children",
+ "tuple_expression": "children",
+ "anonymous_method_expression": "children",
+ "anonymous_object_creation_expression": "children",
+ "array_creation_expression": "children",
+ "as_expression": "children",
+ "assignment_expression": "children",
+ "await_expression": "children",
+ "base": "children",
+ "binary_expression": "children",
+ "cast_expression": "children",
+ "checked_expression": "children",
+ "conditional_access_expression": "children",
+ "conditional_expression": "children",
+ "default_expression": "children",
+ "implicit_array_creation_expression": "children",
+ "implicit_object_creation_expression": "children",
+ "implicit_stackalloc_expression": "children",
+ "initializer_expression": "children",
+ "interpolated_string_expression": "children",
+ "invocation_expression": "children",
+ "is_expression": "children",
+ "is_pattern_expression": "children",
+ "lambda_expression": "children",
+ "boolean_literal": "children",
+ "character_literal": "children",
+ "integer_literal": "children",
+ "null_literal": "children",
+ "raw_string_literal": "children",
+ "real_literal": "children",
+ "string_literal": "children",
+ "verbatim_string_literal": "children",
+ "makeref_expression": "children",
+ "object_creation_expression": "children",
+ "postfix_unary_expression": "children",
+ "preproc_if": "children",
+ "query_expression": "children",
+ "range_expression": "children",
+ "ref_expression": "children",
+ "reftype_expression": "children",
+ "refvalue_expression": "children",
+ "sizeof_expression": "children",
+ "stackalloc_expression": "children",
+ "switch_expression": "children",
+ "throw_expression": "children",
+ "typeof_expression": "children",
+ "with_expression": "children",
+ "and_pattern": "children",
+ "constant_pattern": "children",
+ "declaration_pattern": "children",
+ "discard": "children",
+ "list_pattern": "children",
+ "negated_pattern": "children",
+ "or_pattern": "children",
+ "parenthesized_pattern": "children",
+ "recursive_pattern": "children",
+ "relational_pattern": "children",
+ "type_pattern": "children",
+ "var_pattern": "children",
+ "block": "children",
+ "break_statement": "children",
+ "checked_statement": "children",
+ "continue_statement": "children",
+ "do_statement": "children",
+ "empty_statement": "children",
+ "expression_statement": "children",
+ "fixed_statement": "children",
+ "for_statement": "children",
+ "foreach_statement": "children",
+ "goto_statement": "children",
+ "if_statement": "children",
+ "labeled_statement": "children",
+ "local_declaration_statement": "children",
+ "local_function_statement": "children",
+ "lock_statement": "children",
+ "return_statement": "children",
+ "switch_statement": "children",
+ "throw_statement": "children",
+ "try_statement": "children",
+ "unsafe_statement": "children",
+ "using_statement": "children",
+ "while_statement": "children",
+ "yield_statement": "children",
+ "when_clause": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "switch_statement": {
+ "type": "switch_statement",
+ "singleFieldNames": ["body", "value"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "throw_expression": {
+ "type": "throw_expression",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "element_access_expression": "children",
+ "element_binding_expression": "children",
+ "generic_name": "children",
+ "identifier": "children",
+ "member_access_expression": "children",
+ "parenthesized_expression": "children",
+ "prefix_unary_expression": "children",
+ "this": "children",
+ "tuple_expression": "children",
+ "anonymous_method_expression": "children",
+ "anonymous_object_creation_expression": "children",
+ "array_creation_expression": "children",
+ "as_expression": "children",
+ "assignment_expression": "children",
+ "await_expression": "children",
+ "base": "children",
+ "binary_expression": "children",
+ "cast_expression": "children",
+ "checked_expression": "children",
+ "conditional_access_expression": "children",
+ "conditional_expression": "children",
+ "default_expression": "children",
+ "implicit_array_creation_expression": "children",
+ "implicit_object_creation_expression": "children",
+ "implicit_stackalloc_expression": "children",
+ "initializer_expression": "children",
+ "interpolated_string_expression": "children",
+ "invocation_expression": "children",
+ "is_expression": "children",
+ "is_pattern_expression": "children",
+ "lambda_expression": "children",
+ "boolean_literal": "children",
+ "character_literal": "children",
+ "integer_literal": "children",
+ "null_literal": "children",
+ "raw_string_literal": "children",
+ "real_literal": "children",
+ "string_literal": "children",
+ "verbatim_string_literal": "children",
+ "makeref_expression": "children",
+ "object_creation_expression": "children",
+ "postfix_unary_expression": "children",
+ "preproc_if": "children",
+ "query_expression": "children",
+ "range_expression": "children",
+ "ref_expression": "children",
+ "reftype_expression": "children",
+ "refvalue_expression": "children",
+ "sizeof_expression": "children",
+ "stackalloc_expression": "children",
+ "switch_expression": "children",
+ "throw_expression": "children",
+ "typeof_expression": "children",
+ "with_expression": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "throw_statement": {
+ "type": "throw_statement",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "element_access_expression": "children",
+ "element_binding_expression": "children",
+ "generic_name": "children",
+ "identifier": "children",
+ "member_access_expression": "children",
+ "parenthesized_expression": "children",
+ "prefix_unary_expression": "children",
+ "this": "children",
+ "tuple_expression": "children",
+ "anonymous_method_expression": "children",
+ "anonymous_object_creation_expression": "children",
+ "array_creation_expression": "children",
+ "as_expression": "children",
+ "assignment_expression": "children",
+ "await_expression": "children",
+ "base": "children",
+ "binary_expression": "children",
+ "cast_expression": "children",
+ "checked_expression": "children",
+ "conditional_access_expression": "children",
+ "conditional_expression": "children",
+ "default_expression": "children",
+ "implicit_array_creation_expression": "children",
+ "implicit_object_creation_expression": "children",
+ "implicit_stackalloc_expression": "children",
+ "initializer_expression": "children",
+ "interpolated_string_expression": "children",
+ "invocation_expression": "children",
+ "is_expression": "children",
+ "is_pattern_expression": "children",
+ "lambda_expression": "children",
+ "boolean_literal": "children",
+ "character_literal": "children",
+ "integer_literal": "children",
+ "null_literal": "children",
+ "raw_string_literal": "children",
+ "real_literal": "children",
+ "string_literal": "children",
+ "verbatim_string_literal": "children",
+ "makeref_expression": "children",
+ "object_creation_expression": "children",
+ "postfix_unary_expression": "children",
+ "preproc_if": "children",
+ "query_expression": "children",
+ "range_expression": "children",
+ "ref_expression": "children",
+ "reftype_expression": "children",
+ "refvalue_expression": "children",
+ "sizeof_expression": "children",
+ "stackalloc_expression": "children",
+ "switch_expression": "children",
+ "throw_expression": "children",
+ "typeof_expression": "children",
+ "with_expression": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "try_statement": {
+ "type": "try_statement",
+ "singleFieldNames": ["body"],
+ "nodeTypeToMultipleFieldName": {
+ "catch_clause": "children",
+ "finally_clause": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "tuple_element": {
+ "type": "tuple_element",
+ "singleFieldNames": ["name", "type"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "tuple_expression": {
+ "type": "tuple_expression",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "argument": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "tuple_pattern": {
+ "type": "tuple_pattern",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "identifier": "name",
+ "discard": "children",
+ "tuple_pattern": "children"
+ },
+ "multipleOrChildrenFieldNames": ["name", "children"]
+ },
+ "tuple_type": {
+ "type": "tuple_type",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "tuple_element": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "type_argument_list": {
+ "type": "type_argument_list",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "alias_qualified_name": "children",
+ "array_type": "children",
+ "function_pointer_type": "children",
+ "generic_name": "children",
+ "identifier": "children",
+ "implicit_type": "children",
+ "nullable_type": "children",
+ "pointer_type": "children",
+ "predefined_type": "children",
+ "qualified_name": "children",
+ "ref_type": "children",
+ "scoped_type": "children",
+ "tuple_type": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "type_parameter": {
+ "type": "type_parameter",
+ "singleFieldNames": ["name"],
+ "nodeTypeToMultipleFieldName": {
+ "attribute_list": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "type_parameter_constraint": {
+ "type": "type_parameter_constraint",
+ "singleFieldNames": ["type"],
+ "nodeTypeToMultipleFieldName": {
+ "constructor_constraint": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "type_parameter_constraints_clause": {
+ "type": "type_parameter_constraints_clause",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "identifier": "children",
+ "type_parameter_constraint": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "type_parameter_list": {
+ "type": "type_parameter_list",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "type_parameter": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "type_pattern": {
+ "type": "type_pattern",
+ "singleFieldNames": ["type"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "typeof_expression": {
+ "type": "typeof_expression",
+ "singleFieldNames": ["type"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "unary_expression": {
+ "type": "unary_expression",
+ "singleFieldNames": ["argument", "operator"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "unsafe_statement": {
+ "type": "unsafe_statement",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "block": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "using_directive": {
+ "type": "using_directive",
+ "singleFieldNames": ["name"],
+ "nodeTypeToMultipleFieldName": {
+ "alias_qualified_name": "children",
+ "array_type": "children",
+ "function_pointer_type": "children",
+ "generic_name": "children",
+ "identifier": "children",
+ "implicit_type": "children",
+ "nullable_type": "children",
+ "pointer_type": "children",
+ "predefined_type": "children",
+ "qualified_name": "children",
+ "ref_type": "children",
+ "scoped_type": "children",
+ "tuple_type": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "using_statement": {
+ "type": "using_statement",
+ "singleFieldNames": ["body"],
+ "nodeTypeToMultipleFieldName": {
+ "element_access_expression": "children",
+ "element_binding_expression": "children",
+ "generic_name": "children",
+ "identifier": "children",
+ "member_access_expression": "children",
+ "parenthesized_expression": "children",
+ "prefix_unary_expression": "children",
+ "this": "children",
+ "tuple_expression": "children",
+ "anonymous_method_expression": "children",
+ "anonymous_object_creation_expression": "children",
+ "array_creation_expression": "children",
+ "as_expression": "children",
+ "assignment_expression": "children",
+ "await_expression": "children",
+ "base": "children",
+ "binary_expression": "children",
+ "cast_expression": "children",
+ "checked_expression": "children",
+ "conditional_access_expression": "children",
+ "conditional_expression": "children",
+ "default_expression": "children",
+ "implicit_array_creation_expression": "children",
+ "implicit_object_creation_expression": "children",
+ "implicit_stackalloc_expression": "children",
+ "initializer_expression": "children",
+ "interpolated_string_expression": "children",
+ "invocation_expression": "children",
+ "is_expression": "children",
+ "is_pattern_expression": "children",
+ "lambda_expression": "children",
+ "boolean_literal": "children",
+ "character_literal": "children",
+ "integer_literal": "children",
+ "null_literal": "children",
+ "raw_string_literal": "children",
+ "real_literal": "children",
+ "string_literal": "children",
+ "verbatim_string_literal": "children",
+ "makeref_expression": "children",
+ "object_creation_expression": "children",
+ "postfix_unary_expression": "children",
+ "preproc_if": "children",
+ "query_expression": "children",
+ "range_expression": "children",
+ "ref_expression": "children",
+ "reftype_expression": "children",
+ "refvalue_expression": "children",
+ "sizeof_expression": "children",
+ "stackalloc_expression": "children",
+ "switch_expression": "children",
+ "throw_expression": "children",
+ "typeof_expression": "children",
+ "with_expression": "children",
+ "variable_declaration": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "var_pattern": {
+ "type": "var_pattern",
+ "singleFieldNames": ["name"],
+ "nodeTypeToMultipleFieldName": {
+ "discard": "children",
+ "parenthesized_variable_designation": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "variable_declaration": {
+ "type": "variable_declaration",
+ "singleFieldNames": ["type"],
+ "nodeTypeToMultipleFieldName": {
+ "variable_declarator": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "variable_declarator": {
+ "type": "variable_declarator",
+ "singleFieldNames": ["name"],
+ "nodeTypeToMultipleFieldName": {
+ "bracketed_argument_list": "children",
+ "element_access_expression": "children",
+ "element_binding_expression": "children",
+ "generic_name": "children",
+ "identifier": "children",
+ "member_access_expression": "children",
+ "parenthesized_expression": "children",
+ "prefix_unary_expression": "children",
+ "this": "children",
+ "tuple_expression": "children",
+ "anonymous_method_expression": "children",
+ "anonymous_object_creation_expression": "children",
+ "array_creation_expression": "children",
+ "as_expression": "children",
+ "assignment_expression": "children",
+ "await_expression": "children",
+ "base": "children",
+ "binary_expression": "children",
+ "cast_expression": "children",
+ "checked_expression": "children",
+ "conditional_access_expression": "children",
+ "conditional_expression": "children",
+ "default_expression": "children",
+ "implicit_array_creation_expression": "children",
+ "implicit_object_creation_expression": "children",
+ "implicit_stackalloc_expression": "children",
+ "initializer_expression": "children",
+ "interpolated_string_expression": "children",
+ "invocation_expression": "children",
+ "is_expression": "children",
+ "is_pattern_expression": "children",
+ "lambda_expression": "children",
+ "boolean_literal": "children",
+ "character_literal": "children",
+ "integer_literal": "children",
+ "null_literal": "children",
+ "raw_string_literal": "children",
+ "real_literal": "children",
+ "string_literal": "children",
+ "verbatim_string_literal": "children",
+ "makeref_expression": "children",
+ "object_creation_expression": "children",
+ "postfix_unary_expression": "children",
+ "preproc_if": "children",
+ "query_expression": "children",
+ "range_expression": "children",
+ "ref_expression": "children",
+ "reftype_expression": "children",
+ "refvalue_expression": "children",
+ "sizeof_expression": "children",
+ "stackalloc_expression": "children",
+ "switch_expression": "children",
+ "throw_expression": "children",
+ "typeof_expression": "children",
+ "with_expression": "children",
+ "tuple_pattern": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "when_clause": {
+ "type": "when_clause",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "element_access_expression": "children",
+ "element_binding_expression": "children",
+ "generic_name": "children",
+ "identifier": "children",
+ "member_access_expression": "children",
+ "parenthesized_expression": "children",
+ "prefix_unary_expression": "children",
+ "this": "children",
+ "tuple_expression": "children",
+ "anonymous_method_expression": "children",
+ "anonymous_object_creation_expression": "children",
+ "array_creation_expression": "children",
+ "as_expression": "children",
+ "assignment_expression": "children",
+ "await_expression": "children",
+ "base": "children",
+ "binary_expression": "children",
+ "cast_expression": "children",
+ "checked_expression": "children",
+ "conditional_access_expression": "children",
+ "conditional_expression": "children",
+ "default_expression": "children",
+ "implicit_array_creation_expression": "children",
+ "implicit_object_creation_expression": "children",
+ "implicit_stackalloc_expression": "children",
+ "initializer_expression": "children",
+ "interpolated_string_expression": "children",
+ "invocation_expression": "children",
+ "is_expression": "children",
+ "is_pattern_expression": "children",
+ "lambda_expression": "children",
+ "boolean_literal": "children",
+ "character_literal": "children",
+ "integer_literal": "children",
+ "null_literal": "children",
+ "raw_string_literal": "children",
+ "real_literal": "children",
+ "string_literal": "children",
+ "verbatim_string_literal": "children",
+ "makeref_expression": "children",
+ "object_creation_expression": "children",
+ "postfix_unary_expression": "children",
+ "preproc_if": "children",
+ "query_expression": "children",
+ "range_expression": "children",
+ "ref_expression": "children",
+ "reftype_expression": "children",
+ "refvalue_expression": "children",
+ "sizeof_expression": "children",
+ "stackalloc_expression": "children",
+ "switch_expression": "children",
+ "throw_expression": "children",
+ "typeof_expression": "children",
+ "with_expression": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "where_clause": {
+ "type": "where_clause",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "element_access_expression": "children",
+ "element_binding_expression": "children",
+ "generic_name": "children",
+ "identifier": "children",
+ "member_access_expression": "children",
+ "parenthesized_expression": "children",
+ "prefix_unary_expression": "children",
+ "this": "children",
+ "tuple_expression": "children",
+ "anonymous_method_expression": "children",
+ "anonymous_object_creation_expression": "children",
+ "array_creation_expression": "children",
+ "as_expression": "children",
+ "assignment_expression": "children",
+ "await_expression": "children",
+ "base": "children",
+ "binary_expression": "children",
+ "cast_expression": "children",
+ "checked_expression": "children",
+ "conditional_access_expression": "children",
+ "conditional_expression": "children",
+ "default_expression": "children",
+ "implicit_array_creation_expression": "children",
+ "implicit_object_creation_expression": "children",
+ "implicit_stackalloc_expression": "children",
+ "initializer_expression": "children",
+ "interpolated_string_expression": "children",
+ "invocation_expression": "children",
+ "is_expression": "children",
+ "is_pattern_expression": "children",
+ "lambda_expression": "children",
+ "boolean_literal": "children",
+ "character_literal": "children",
+ "integer_literal": "children",
+ "null_literal": "children",
+ "raw_string_literal": "children",
+ "real_literal": "children",
+ "string_literal": "children",
+ "verbatim_string_literal": "children",
+ "makeref_expression": "children",
+ "object_creation_expression": "children",
+ "postfix_unary_expression": "children",
+ "preproc_if": "children",
+ "query_expression": "children",
+ "range_expression": "children",
+ "ref_expression": "children",
+ "reftype_expression": "children",
+ "refvalue_expression": "children",
+ "sizeof_expression": "children",
+ "stackalloc_expression": "children",
+ "switch_expression": "children",
+ "throw_expression": "children",
+ "typeof_expression": "children",
+ "with_expression": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "while_statement": {
+ "type": "while_statement",
+ "singleFieldNames": ["body", "condition"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "with_expression": {
+ "type": "with_expression",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "element_access_expression": "children",
+ "element_binding_expression": "children",
+ "generic_name": "children",
+ "identifier": "children",
+ "member_access_expression": "children",
+ "parenthesized_expression": "children",
+ "prefix_unary_expression": "children",
+ "this": "children",
+ "tuple_expression": "children",
+ "anonymous_method_expression": "children",
+ "anonymous_object_creation_expression": "children",
+ "array_creation_expression": "children",
+ "as_expression": "children",
+ "assignment_expression": "children",
+ "await_expression": "children",
+ "base": "children",
+ "binary_expression": "children",
+ "cast_expression": "children",
+ "checked_expression": "children",
+ "conditional_access_expression": "children",
+ "conditional_expression": "children",
+ "default_expression": "children",
+ "implicit_array_creation_expression": "children",
+ "implicit_object_creation_expression": "children",
+ "implicit_stackalloc_expression": "children",
+ "initializer_expression": "children",
+ "interpolated_string_expression": "children",
+ "invocation_expression": "children",
+ "is_expression": "children",
+ "is_pattern_expression": "children",
+ "lambda_expression": "children",
+ "boolean_literal": "children",
+ "character_literal": "children",
+ "integer_literal": "children",
+ "null_literal": "children",
+ "raw_string_literal": "children",
+ "real_literal": "children",
+ "string_literal": "children",
+ "verbatim_string_literal": "children",
+ "makeref_expression": "children",
+ "object_creation_expression": "children",
+ "postfix_unary_expression": "children",
+ "preproc_if": "children",
+ "query_expression": "children",
+ "range_expression": "children",
+ "ref_expression": "children",
+ "reftype_expression": "children",
+ "refvalue_expression": "children",
+ "sizeof_expression": "children",
+ "stackalloc_expression": "children",
+ "switch_expression": "children",
+ "throw_expression": "children",
+ "typeof_expression": "children",
+ "with_expression": "children",
+ "with_initializer": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "with_initializer": {
+ "type": "with_initializer",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "element_access_expression": "children",
+ "element_binding_expression": "children",
+ "generic_name": "children",
+ "identifier": "children",
+ "member_access_expression": "children",
+ "parenthesized_expression": "children",
+ "prefix_unary_expression": "children",
+ "this": "children",
+ "tuple_expression": "children",
+ "anonymous_method_expression": "children",
+ "anonymous_object_creation_expression": "children",
+ "array_creation_expression": "children",
+ "as_expression": "children",
+ "assignment_expression": "children",
+ "await_expression": "children",
+ "base": "children",
+ "binary_expression": "children",
+ "cast_expression": "children",
+ "checked_expression": "children",
+ "conditional_access_expression": "children",
+ "conditional_expression": "children",
+ "default_expression": "children",
+ "implicit_array_creation_expression": "children",
+ "implicit_object_creation_expression": "children",
+ "implicit_stackalloc_expression": "children",
+ "initializer_expression": "children",
+ "interpolated_string_expression": "children",
+ "invocation_expression": "children",
+ "is_expression": "children",
+ "is_pattern_expression": "children",
+ "lambda_expression": "children",
+ "boolean_literal": "children",
+ "character_literal": "children",
+ "integer_literal": "children",
+ "null_literal": "children",
+ "raw_string_literal": "children",
+ "real_literal": "children",
+ "string_literal": "children",
+ "verbatim_string_literal": "children",
+ "makeref_expression": "children",
+ "object_creation_expression": "children",
+ "postfix_unary_expression": "children",
+ "preproc_if": "children",
+ "query_expression": "children",
+ "range_expression": "children",
+ "ref_expression": "children",
+ "reftype_expression": "children",
+ "refvalue_expression": "children",
+ "sizeof_expression": "children",
+ "stackalloc_expression": "children",
+ "switch_expression": "children",
+ "throw_expression": "children",
+ "typeof_expression": "children",
+ "with_expression": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "yield_statement": {
+ "type": "yield_statement",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "element_access_expression": "children",
+ "element_binding_expression": "children",
+ "generic_name": "children",
+ "identifier": "children",
+ "member_access_expression": "children",
+ "parenthesized_expression": "children",
+ "prefix_unary_expression": "children",
+ "this": "children",
+ "tuple_expression": "children",
+ "anonymous_method_expression": "children",
+ "anonymous_object_creation_expression": "children",
+ "array_creation_expression": "children",
+ "as_expression": "children",
+ "assignment_expression": "children",
+ "await_expression": "children",
+ "base": "children",
+ "binary_expression": "children",
+ "cast_expression": "children",
+ "checked_expression": "children",
+ "conditional_access_expression": "children",
+ "conditional_expression": "children",
+ "default_expression": "children",
+ "implicit_array_creation_expression": "children",
+ "implicit_object_creation_expression": "children",
+ "implicit_stackalloc_expression": "children",
+ "initializer_expression": "children",
+ "interpolated_string_expression": "children",
+ "invocation_expression": "children",
+ "is_expression": "children",
+ "is_pattern_expression": "children",
+ "lambda_expression": "children",
+ "boolean_literal": "children",
+ "character_literal": "children",
+ "integer_literal": "children",
+ "null_literal": "children",
+ "raw_string_literal": "children",
+ "real_literal": "children",
+ "string_literal": "children",
+ "verbatim_string_literal": "children",
+ "makeref_expression": "children",
+ "object_creation_expression": "children",
+ "postfix_unary_expression": "children",
+ "preproc_if": "children",
+ "query_expression": "children",
+ "range_expression": "children",
+ "ref_expression": "children",
+ "reftype_expression": "children",
+ "refvalue_expression": "children",
+ "sizeof_expression": "children",
+ "stackalloc_expression": "children",
+ "switch_expression": "children",
+ "throw_expression": "children",
+ "typeof_expression": "children",
+ "with_expression": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "!": {
+ "type": "!",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "!=": {
+ "type": "!=",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "%": {
+ "type": "%",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "%=": {
+ "type": "%=",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "&": {
+ "type": "&",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "&&": {
+ "type": "&&",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "&=": {
+ "type": "&=",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "*": {
+ "type": "*",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "*=": {
+ "type": "*=",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "+": {
+ "type": "+",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "++": {
+ "type": "++",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "+=": {
+ "type": "+=",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "-": {
+ "type": "-",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "--": {
+ "type": "--",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "-=": {
+ "type": "-=",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "/": {
+ "type": "/",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "/=": {
+ "type": "/=",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "<": {
+ "type": "<",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "<<": {
+ "type": "<<",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "<<=": {
+ "type": "<<=",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "<=": {
+ "type": "<=",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "=": {
+ "type": "=",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "==": {
+ "type": "==",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ ">": {
+ "type": ">",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ ">=": {
+ "type": ">=",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ ">>": {
+ "type": ">>",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ ">>=": {
+ "type": ">>=",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ ">>>": {
+ "type": ">>>",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ ">>>=": {
+ "type": ">>>=",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "??": {
+ "type": "??",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "??=": {
+ "type": "??=",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "^": {
+ "type": "^",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "^=": {
+ "type": "^=",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "add": {
+ "type": "add",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "and": {
+ "type": "and",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "as": {
+ "type": "as",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "character_literal_content": {
+ "type": "character_literal_content",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "comment": {
+ "type": "comment",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "discard": {
+ "type": "discard",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "escape_sequence": {
+ "type": "escape_sequence",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "false": {
+ "type": "false",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "get": {
+ "type": "get",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "init": {
+ "type": "init",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "integer_literal": {
+ "type": "integer_literal",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "interpolation_brace": {
+ "type": "interpolation_brace",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "interpolation_quote": {
+ "type": "interpolation_quote",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "interpolation_start": {
+ "type": "interpolation_start",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "is": {
+ "type": "is",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "null_literal": {
+ "type": "null_literal",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "or": {
+ "type": "or",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "predefined_type": {
+ "type": "predefined_type",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "preproc_arg": {
+ "type": "preproc_arg",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "raw_string_content": {
+ "type": "raw_string_content",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "raw_string_end": {
+ "type": "raw_string_end",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "raw_string_start": {
+ "type": "raw_string_start",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "real_literal": {
+ "type": "real_literal",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "remove": {
+ "type": "remove",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "set": {
+ "type": "set",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "shebang_directive": {
+ "type": "shebang_directive",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "string_content": {
+ "type": "string_content",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "string_literal_encoding": {
+ "type": "string_literal_encoding",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "true": {
+ "type": "true",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "verbatim_string_literal": {
+ "type": "verbatim_string_literal",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "|": {
+ "type": "|",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "|=": {
+ "type": "|=",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "||": {
+ "type": "||",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "~": {
+ "type": "~",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ }
+}
diff --git a/packages/tree-sitter-port/output/tree-sitter-c-sharp/meta.json b/packages/tree-sitter-port/output/tree-sitter-c-sharp/meta.json
new file mode 100644
index 0000000..61fdd02
--- /dev/null
+++ b/packages/tree-sitter-port/output/tree-sitter-c-sharp/meta.json
@@ -0,0 +1,5 @@
+{
+ "name": "tree-sitter-c-sharp",
+ "version": "0.21.2",
+ "generatedAt": "2024-06-26T15:41:38.824Z"
+}
diff --git a/packages/tree-sitter-port/output/tree-sitter-c-sharp/parser.wasm b/packages/tree-sitter-port/output/tree-sitter-c-sharp/parser.wasm
new file mode 100755
index 0000000..65e8511
Binary files /dev/null and b/packages/tree-sitter-port/output/tree-sitter-c-sharp/parser.wasm differ
diff --git a/packages/tree-sitter-port/output/tree-sitter-c/fields-meta.json b/packages/tree-sitter-port/output/tree-sitter-c/fields-meta.json
new file mode 100644
index 0000000..d28eed0
--- /dev/null
+++ b/packages/tree-sitter-port/output/tree-sitter-c/fields-meta.json
@@ -0,0 +1,1729 @@
+{
+ "abstract_array_declarator": {
+ "type": "abstract_array_declarator",
+ "singleFieldNames": ["declarator", "size"],
+ "nodeTypeToMultipleFieldName": {
+ "type_qualifier": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "abstract_function_declarator": {
+ "type": "abstract_function_declarator",
+ "singleFieldNames": ["declarator", "parameters"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "abstract_parenthesized_declarator": {
+ "type": "abstract_parenthesized_declarator",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "abstract_array_declarator": "children",
+ "abstract_function_declarator": "children",
+ "abstract_parenthesized_declarator": "children",
+ "abstract_pointer_declarator": "children",
+ "ms_call_modifier": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "abstract_pointer_declarator": {
+ "type": "abstract_pointer_declarator",
+ "singleFieldNames": ["declarator"],
+ "nodeTypeToMultipleFieldName": {
+ "ms_pointer_modifier": "children",
+ "type_qualifier": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "alignas_qualifier": {
+ "type": "alignas_qualifier",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "alignof_expression": "children",
+ "assignment_expression": "children",
+ "binary_expression": "children",
+ "call_expression": "children",
+ "cast_expression": "children",
+ "char_literal": "children",
+ "compound_literal_expression": "children",
+ "concatenated_string": "children",
+ "conditional_expression": "children",
+ "false": "children",
+ "field_expression": "children",
+ "generic_expression": "children",
+ "gnu_asm_expression": "children",
+ "identifier": "children",
+ "null": "children",
+ "number_literal": "children",
+ "offsetof_expression": "children",
+ "parenthesized_expression": "children",
+ "pointer_expression": "children",
+ "sizeof_expression": "children",
+ "string_literal": "children",
+ "subscript_expression": "children",
+ "true": "children",
+ "unary_expression": "children",
+ "update_expression": "children",
+ "type_descriptor": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "alignof_expression": {
+ "type": "alignof_expression",
+ "singleFieldNames": ["type"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "argument_list": {
+ "type": "argument_list",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "compound_statement": "children",
+ "alignof_expression": "children",
+ "assignment_expression": "children",
+ "binary_expression": "children",
+ "call_expression": "children",
+ "cast_expression": "children",
+ "char_literal": "children",
+ "compound_literal_expression": "children",
+ "concatenated_string": "children",
+ "conditional_expression": "children",
+ "false": "children",
+ "field_expression": "children",
+ "generic_expression": "children",
+ "gnu_asm_expression": "children",
+ "identifier": "children",
+ "null": "children",
+ "number_literal": "children",
+ "offsetof_expression": "children",
+ "parenthesized_expression": "children",
+ "pointer_expression": "children",
+ "sizeof_expression": "children",
+ "string_literal": "children",
+ "subscript_expression": "children",
+ "true": "children",
+ "unary_expression": "children",
+ "update_expression": "children",
+ "preproc_defined": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "array_declarator": {
+ "type": "array_declarator",
+ "singleFieldNames": ["declarator", "size"],
+ "nodeTypeToMultipleFieldName": {
+ "type_qualifier": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "assignment_expression": {
+ "type": "assignment_expression",
+ "singleFieldNames": ["left", "operator", "right"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "attribute": {
+ "type": "attribute",
+ "singleFieldNames": ["name", "prefix"],
+ "nodeTypeToMultipleFieldName": {
+ "argument_list": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "attribute_declaration": {
+ "type": "attribute_declaration",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "attribute": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "attribute_specifier": {
+ "type": "attribute_specifier",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "argument_list": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "attributed_declarator": {
+ "type": "attributed_declarator",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "array_declarator": "children",
+ "attributed_declarator": "children",
+ "function_declarator": "children",
+ "identifier": "children",
+ "parenthesized_declarator": "children",
+ "pointer_declarator": "children",
+ "field_identifier": "children",
+ "primitive_type": "children",
+ "type_identifier": "children",
+ "attribute_declaration": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "attributed_statement": {
+ "type": "attributed_statement",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "attribute_declaration": "children",
+ "attributed_statement": "children",
+ "break_statement": "children",
+ "case_statement": "children",
+ "compound_statement": "children",
+ "continue_statement": "children",
+ "do_statement": "children",
+ "expression_statement": "children",
+ "for_statement": "children",
+ "goto_statement": "children",
+ "if_statement": "children",
+ "labeled_statement": "children",
+ "return_statement": "children",
+ "seh_leave_statement": "children",
+ "seh_try_statement": "children",
+ "switch_statement": "children",
+ "while_statement": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "binary_expression": {
+ "type": "binary_expression",
+ "singleFieldNames": ["left", "operator", "right"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "bitfield_clause": {
+ "type": "bitfield_clause",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "alignof_expression": "children",
+ "assignment_expression": "children",
+ "binary_expression": "children",
+ "call_expression": "children",
+ "cast_expression": "children",
+ "char_literal": "children",
+ "compound_literal_expression": "children",
+ "concatenated_string": "children",
+ "conditional_expression": "children",
+ "false": "children",
+ "field_expression": "children",
+ "generic_expression": "children",
+ "gnu_asm_expression": "children",
+ "identifier": "children",
+ "null": "children",
+ "number_literal": "children",
+ "offsetof_expression": "children",
+ "parenthesized_expression": "children",
+ "pointer_expression": "children",
+ "sizeof_expression": "children",
+ "string_literal": "children",
+ "subscript_expression": "children",
+ "true": "children",
+ "unary_expression": "children",
+ "update_expression": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "break_statement": {
+ "type": "break_statement",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "call_expression": {
+ "type": "call_expression",
+ "singleFieldNames": ["arguments", "function"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "case_statement": {
+ "type": "case_statement",
+ "singleFieldNames": ["value"],
+ "nodeTypeToMultipleFieldName": {
+ "attributed_statement": "children",
+ "break_statement": "children",
+ "compound_statement": "children",
+ "continue_statement": "children",
+ "declaration": "children",
+ "do_statement": "children",
+ "expression_statement": "children",
+ "for_statement": "children",
+ "goto_statement": "children",
+ "if_statement": "children",
+ "labeled_statement": "children",
+ "return_statement": "children",
+ "seh_leave_statement": "children",
+ "seh_try_statement": "children",
+ "switch_statement": "children",
+ "type_definition": "children",
+ "while_statement": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "cast_expression": {
+ "type": "cast_expression",
+ "singleFieldNames": ["type", "value"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "char_literal": {
+ "type": "char_literal",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "character": "children",
+ "escape_sequence": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "comma_expression": {
+ "type": "comma_expression",
+ "singleFieldNames": ["left", "right"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "compound_literal_expression": {
+ "type": "compound_literal_expression",
+ "singleFieldNames": ["type", "value"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "compound_statement": {
+ "type": "compound_statement",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "declaration": "children",
+ "function_definition": "children",
+ "linkage_specification": "children",
+ "preproc_call": "children",
+ "preproc_def": "children",
+ "preproc_function_def": "children",
+ "preproc_if": "children",
+ "preproc_ifdef": "children",
+ "preproc_include": "children",
+ "attributed_statement": "children",
+ "break_statement": "children",
+ "case_statement": "children",
+ "compound_statement": "children",
+ "continue_statement": "children",
+ "do_statement": "children",
+ "expression_statement": "children",
+ "for_statement": "children",
+ "goto_statement": "children",
+ "if_statement": "children",
+ "labeled_statement": "children",
+ "return_statement": "children",
+ "seh_leave_statement": "children",
+ "seh_try_statement": "children",
+ "switch_statement": "children",
+ "while_statement": "children",
+ "type_definition": "children",
+ "enum_specifier": "children",
+ "macro_type_specifier": "children",
+ "primitive_type": "children",
+ "sized_type_specifier": "children",
+ "struct_specifier": "children",
+ "type_identifier": "children",
+ "union_specifier": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "concatenated_string": {
+ "type": "concatenated_string",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "identifier": "children",
+ "string_literal": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "conditional_expression": {
+ "type": "conditional_expression",
+ "singleFieldNames": ["alternative", "condition", "consequence"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "continue_statement": {
+ "type": "continue_statement",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "declaration": {
+ "type": "declaration",
+ "singleFieldNames": ["type"],
+ "nodeTypeToMultipleFieldName": {
+ "array_declarator": "declarator",
+ "attributed_declarator": "declarator",
+ "function_declarator": "declarator",
+ "gnu_asm_expression": "declarator",
+ "identifier": "declarator",
+ "init_declarator": "declarator",
+ "ms_call_modifier": "declarator",
+ "parenthesized_declarator": "declarator",
+ "pointer_declarator": "declarator",
+ "attribute_declaration": "children",
+ "attribute_specifier": "children",
+ "ms_declspec_modifier": "children",
+ "storage_class_specifier": "children",
+ "type_qualifier": "children"
+ },
+ "multipleOrChildrenFieldNames": ["declarator", "children"]
+ },
+ "declaration_list": {
+ "type": "declaration_list",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "declaration": "children",
+ "function_definition": "children",
+ "linkage_specification": "children",
+ "preproc_call": "children",
+ "preproc_def": "children",
+ "preproc_function_def": "children",
+ "preproc_if": "children",
+ "preproc_ifdef": "children",
+ "preproc_include": "children",
+ "attributed_statement": "children",
+ "break_statement": "children",
+ "case_statement": "children",
+ "compound_statement": "children",
+ "continue_statement": "children",
+ "do_statement": "children",
+ "expression_statement": "children",
+ "for_statement": "children",
+ "goto_statement": "children",
+ "if_statement": "children",
+ "labeled_statement": "children",
+ "return_statement": "children",
+ "seh_leave_statement": "children",
+ "seh_try_statement": "children",
+ "switch_statement": "children",
+ "while_statement": "children",
+ "type_definition": "children",
+ "enum_specifier": "children",
+ "macro_type_specifier": "children",
+ "primitive_type": "children",
+ "sized_type_specifier": "children",
+ "struct_specifier": "children",
+ "type_identifier": "children",
+ "union_specifier": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "do_statement": {
+ "type": "do_statement",
+ "singleFieldNames": ["body", "condition"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "else_clause": {
+ "type": "else_clause",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "attributed_statement": "children",
+ "break_statement": "children",
+ "case_statement": "children",
+ "compound_statement": "children",
+ "continue_statement": "children",
+ "do_statement": "children",
+ "expression_statement": "children",
+ "for_statement": "children",
+ "goto_statement": "children",
+ "if_statement": "children",
+ "labeled_statement": "children",
+ "return_statement": "children",
+ "seh_leave_statement": "children",
+ "seh_try_statement": "children",
+ "switch_statement": "children",
+ "while_statement": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "enum_specifier": {
+ "type": "enum_specifier",
+ "singleFieldNames": ["body", "name", "underlying_type"],
+ "nodeTypeToMultipleFieldName": {
+ "attribute_specifier": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "enumerator": {
+ "type": "enumerator",
+ "singleFieldNames": ["name", "value"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "enumerator_list": {
+ "type": "enumerator_list",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "enumerator": "children",
+ "preproc_call": "children",
+ "preproc_if": "children",
+ "preproc_ifdef": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "expression_statement": {
+ "type": "expression_statement",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "comma_expression": "children",
+ "alignof_expression": "children",
+ "assignment_expression": "children",
+ "binary_expression": "children",
+ "call_expression": "children",
+ "cast_expression": "children",
+ "char_literal": "children",
+ "compound_literal_expression": "children",
+ "concatenated_string": "children",
+ "conditional_expression": "children",
+ "false": "children",
+ "field_expression": "children",
+ "generic_expression": "children",
+ "gnu_asm_expression": "children",
+ "identifier": "children",
+ "null": "children",
+ "number_literal": "children",
+ "offsetof_expression": "children",
+ "parenthesized_expression": "children",
+ "pointer_expression": "children",
+ "sizeof_expression": "children",
+ "string_literal": "children",
+ "subscript_expression": "children",
+ "true": "children",
+ "unary_expression": "children",
+ "update_expression": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "field_declaration": {
+ "type": "field_declaration",
+ "singleFieldNames": ["type"],
+ "nodeTypeToMultipleFieldName": {
+ "array_declarator": "declarator",
+ "attributed_declarator": "declarator",
+ "field_identifier": "declarator",
+ "function_declarator": "declarator",
+ "parenthesized_declarator": "declarator",
+ "pointer_declarator": "declarator",
+ "attribute_declaration": "children",
+ "attribute_specifier": "children",
+ "bitfield_clause": "children",
+ "ms_declspec_modifier": "children",
+ "storage_class_specifier": "children",
+ "type_qualifier": "children"
+ },
+ "multipleOrChildrenFieldNames": ["declarator", "children"]
+ },
+ "field_declaration_list": {
+ "type": "field_declaration_list",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "field_declaration": "children",
+ "preproc_call": "children",
+ "preproc_def": "children",
+ "preproc_function_def": "children",
+ "preproc_if": "children",
+ "preproc_ifdef": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "field_designator": {
+ "type": "field_designator",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "field_identifier": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "field_expression": {
+ "type": "field_expression",
+ "singleFieldNames": ["argument", "field", "operator"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "for_statement": {
+ "type": "for_statement",
+ "singleFieldNames": ["body", "condition", "initializer", "update"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "function_declarator": {
+ "type": "function_declarator",
+ "singleFieldNames": ["declarator", "parameters"],
+ "nodeTypeToMultipleFieldName": {
+ "attribute_specifier": "children",
+ "call_expression": "children",
+ "gnu_asm_expression": "children",
+ "identifier": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "function_definition": {
+ "type": "function_definition",
+ "singleFieldNames": ["body", "declarator", "type"],
+ "nodeTypeToMultipleFieldName": {
+ "attribute_declaration": "children",
+ "attribute_specifier": "children",
+ "declaration": "children",
+ "ms_call_modifier": "children",
+ "ms_declspec_modifier": "children",
+ "storage_class_specifier": "children",
+ "type_qualifier": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "generic_expression": {
+ "type": "generic_expression",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "alignof_expression": "children",
+ "assignment_expression": "children",
+ "binary_expression": "children",
+ "call_expression": "children",
+ "cast_expression": "children",
+ "char_literal": "children",
+ "compound_literal_expression": "children",
+ "concatenated_string": "children",
+ "conditional_expression": "children",
+ "false": "children",
+ "field_expression": "children",
+ "generic_expression": "children",
+ "gnu_asm_expression": "children",
+ "identifier": "children",
+ "null": "children",
+ "number_literal": "children",
+ "offsetof_expression": "children",
+ "parenthesized_expression": "children",
+ "pointer_expression": "children",
+ "sizeof_expression": "children",
+ "string_literal": "children",
+ "subscript_expression": "children",
+ "true": "children",
+ "unary_expression": "children",
+ "update_expression": "children",
+ "type_descriptor": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "gnu_asm_clobber_list": {
+ "type": "gnu_asm_clobber_list",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "concatenated_string": "register",
+ "string_literal": "register"
+ },
+ "multipleOrChildrenFieldNames": ["register"]
+ },
+ "gnu_asm_expression": {
+ "type": "gnu_asm_expression",
+ "singleFieldNames": [
+ "assembly_code",
+ "clobbers",
+ "goto_labels",
+ "input_operands",
+ "output_operands"
+ ],
+ "nodeTypeToMultipleFieldName": {
+ "gnu_asm_qualifier": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "gnu_asm_goto_list": {
+ "type": "gnu_asm_goto_list",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "identifier": "label"
+ },
+ "multipleOrChildrenFieldNames": ["label"]
+ },
+ "gnu_asm_input_operand": {
+ "type": "gnu_asm_input_operand",
+ "singleFieldNames": ["constraint", "symbol", "value"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "gnu_asm_input_operand_list": {
+ "type": "gnu_asm_input_operand_list",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "gnu_asm_input_operand": "operand"
+ },
+ "multipleOrChildrenFieldNames": ["operand"]
+ },
+ "gnu_asm_output_operand": {
+ "type": "gnu_asm_output_operand",
+ "singleFieldNames": ["constraint", "symbol", "value"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "gnu_asm_output_operand_list": {
+ "type": "gnu_asm_output_operand_list",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "gnu_asm_output_operand": "operand"
+ },
+ "multipleOrChildrenFieldNames": ["operand"]
+ },
+ "gnu_asm_qualifier": {
+ "type": "gnu_asm_qualifier",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "goto_statement": {
+ "type": "goto_statement",
+ "singleFieldNames": ["label"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "if_statement": {
+ "type": "if_statement",
+ "singleFieldNames": ["alternative", "condition", "consequence"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "init_declarator": {
+ "type": "init_declarator",
+ "singleFieldNames": ["declarator", "value"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "initializer_list": {
+ "type": "initializer_list",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "alignof_expression": "children",
+ "assignment_expression": "children",
+ "binary_expression": "children",
+ "call_expression": "children",
+ "cast_expression": "children",
+ "char_literal": "children",
+ "compound_literal_expression": "children",
+ "concatenated_string": "children",
+ "conditional_expression": "children",
+ "false": "children",
+ "field_expression": "children",
+ "generic_expression": "children",
+ "gnu_asm_expression": "children",
+ "identifier": "children",
+ "null": "children",
+ "number_literal": "children",
+ "offsetof_expression": "children",
+ "parenthesized_expression": "children",
+ "pointer_expression": "children",
+ "sizeof_expression": "children",
+ "string_literal": "children",
+ "subscript_expression": "children",
+ "true": "children",
+ "unary_expression": "children",
+ "update_expression": "children",
+ "initializer_list": "children",
+ "initializer_pair": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "initializer_pair": {
+ "type": "initializer_pair",
+ "singleFieldNames": ["value"],
+ "nodeTypeToMultipleFieldName": {
+ "field_designator": "designator",
+ "field_identifier": "designator",
+ "subscript_designator": "designator",
+ "subscript_range_designator": "designator"
+ },
+ "multipleOrChildrenFieldNames": ["designator"]
+ },
+ "labeled_statement": {
+ "type": "labeled_statement",
+ "singleFieldNames": ["label"],
+ "nodeTypeToMultipleFieldName": {
+ "attributed_statement": "children",
+ "break_statement": "children",
+ "case_statement": "children",
+ "compound_statement": "children",
+ "continue_statement": "children",
+ "do_statement": "children",
+ "expression_statement": "children",
+ "for_statement": "children",
+ "goto_statement": "children",
+ "if_statement": "children",
+ "labeled_statement": "children",
+ "return_statement": "children",
+ "seh_leave_statement": "children",
+ "seh_try_statement": "children",
+ "switch_statement": "children",
+ "while_statement": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "linkage_specification": {
+ "type": "linkage_specification",
+ "singleFieldNames": ["body", "value"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "macro_type_specifier": {
+ "type": "macro_type_specifier",
+ "singleFieldNames": ["name", "type"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "ms_based_modifier": {
+ "type": "ms_based_modifier",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "argument_list": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "ms_call_modifier": {
+ "type": "ms_call_modifier",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "ms_declspec_modifier": {
+ "type": "ms_declspec_modifier",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "identifier": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "ms_pointer_modifier": {
+ "type": "ms_pointer_modifier",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "ms_restrict_modifier": "children",
+ "ms_signed_ptr_modifier": "children",
+ "ms_unaligned_ptr_modifier": "children",
+ "ms_unsigned_ptr_modifier": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "ms_unaligned_ptr_modifier": {
+ "type": "ms_unaligned_ptr_modifier",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "null": {
+ "type": "null",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "offsetof_expression": {
+ "type": "offsetof_expression",
+ "singleFieldNames": ["member", "type"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "parameter_declaration": {
+ "type": "parameter_declaration",
+ "singleFieldNames": ["declarator", "type"],
+ "nodeTypeToMultipleFieldName": {
+ "attribute_declaration": "children",
+ "attribute_specifier": "children",
+ "ms_declspec_modifier": "children",
+ "storage_class_specifier": "children",
+ "type_qualifier": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "parameter_list": {
+ "type": "parameter_list",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "identifier": "children",
+ "parameter_declaration": "children",
+ "variadic_parameter": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "parenthesized_declarator": {
+ "type": "parenthesized_declarator",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "array_declarator": "children",
+ "attributed_declarator": "children",
+ "function_declarator": "children",
+ "identifier": "children",
+ "parenthesized_declarator": "children",
+ "pointer_declarator": "children",
+ "field_identifier": "children",
+ "primitive_type": "children",
+ "type_identifier": "children",
+ "ms_call_modifier": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "parenthesized_expression": {
+ "type": "parenthesized_expression",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "comma_expression": "children",
+ "alignof_expression": "children",
+ "assignment_expression": "children",
+ "binary_expression": "children",
+ "call_expression": "children",
+ "cast_expression": "children",
+ "char_literal": "children",
+ "compound_literal_expression": "children",
+ "concatenated_string": "children",
+ "conditional_expression": "children",
+ "false": "children",
+ "field_expression": "children",
+ "generic_expression": "children",
+ "gnu_asm_expression": "children",
+ "identifier": "children",
+ "null": "children",
+ "number_literal": "children",
+ "offsetof_expression": "children",
+ "parenthesized_expression": "children",
+ "pointer_expression": "children",
+ "sizeof_expression": "children",
+ "string_literal": "children",
+ "subscript_expression": "children",
+ "true": "children",
+ "unary_expression": "children",
+ "update_expression": "children",
+ "preproc_defined": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "pointer_declarator": {
+ "type": "pointer_declarator",
+ "singleFieldNames": ["declarator"],
+ "nodeTypeToMultipleFieldName": {
+ "ms_based_modifier": "children",
+ "ms_pointer_modifier": "children",
+ "type_qualifier": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "pointer_expression": {
+ "type": "pointer_expression",
+ "singleFieldNames": ["argument", "operator"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "preproc_call": {
+ "type": "preproc_call",
+ "singleFieldNames": ["argument", "directive"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "preproc_def": {
+ "type": "preproc_def",
+ "singleFieldNames": ["name", "value"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "preproc_defined": {
+ "type": "preproc_defined",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "identifier": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "preproc_elif": {
+ "type": "preproc_elif",
+ "singleFieldNames": ["alternative", "condition"],
+ "nodeTypeToMultipleFieldName": {
+ "declaration": "children",
+ "enumerator": "children",
+ "field_declaration": "children",
+ "function_definition": "children",
+ "linkage_specification": "children",
+ "preproc_call": "children",
+ "preproc_def": "children",
+ "preproc_function_def": "children",
+ "preproc_if": "children",
+ "preproc_ifdef": "children",
+ "preproc_include": "children",
+ "attributed_statement": "children",
+ "break_statement": "children",
+ "case_statement": "children",
+ "compound_statement": "children",
+ "continue_statement": "children",
+ "do_statement": "children",
+ "expression_statement": "children",
+ "for_statement": "children",
+ "goto_statement": "children",
+ "if_statement": "children",
+ "labeled_statement": "children",
+ "return_statement": "children",
+ "seh_leave_statement": "children",
+ "seh_try_statement": "children",
+ "switch_statement": "children",
+ "while_statement": "children",
+ "type_definition": "children",
+ "enum_specifier": "children",
+ "macro_type_specifier": "children",
+ "primitive_type": "children",
+ "sized_type_specifier": "children",
+ "struct_specifier": "children",
+ "type_identifier": "children",
+ "union_specifier": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "preproc_elifdef": {
+ "type": "preproc_elifdef",
+ "singleFieldNames": ["alternative", "name"],
+ "nodeTypeToMultipleFieldName": {
+ "declaration": "children",
+ "enumerator": "children",
+ "field_declaration": "children",
+ "function_definition": "children",
+ "linkage_specification": "children",
+ "preproc_call": "children",
+ "preproc_def": "children",
+ "preproc_function_def": "children",
+ "preproc_if": "children",
+ "preproc_ifdef": "children",
+ "preproc_include": "children",
+ "attributed_statement": "children",
+ "break_statement": "children",
+ "case_statement": "children",
+ "compound_statement": "children",
+ "continue_statement": "children",
+ "do_statement": "children",
+ "expression_statement": "children",
+ "for_statement": "children",
+ "goto_statement": "children",
+ "if_statement": "children",
+ "labeled_statement": "children",
+ "return_statement": "children",
+ "seh_leave_statement": "children",
+ "seh_try_statement": "children",
+ "switch_statement": "children",
+ "while_statement": "children",
+ "type_definition": "children",
+ "enum_specifier": "children",
+ "macro_type_specifier": "children",
+ "primitive_type": "children",
+ "sized_type_specifier": "children",
+ "struct_specifier": "children",
+ "type_identifier": "children",
+ "union_specifier": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "preproc_else": {
+ "type": "preproc_else",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "declaration": "children",
+ "enumerator": "children",
+ "field_declaration": "children",
+ "function_definition": "children",
+ "linkage_specification": "children",
+ "preproc_call": "children",
+ "preproc_def": "children",
+ "preproc_function_def": "children",
+ "preproc_if": "children",
+ "preproc_ifdef": "children",
+ "preproc_include": "children",
+ "attributed_statement": "children",
+ "break_statement": "children",
+ "case_statement": "children",
+ "compound_statement": "children",
+ "continue_statement": "children",
+ "do_statement": "children",
+ "expression_statement": "children",
+ "for_statement": "children",
+ "goto_statement": "children",
+ "if_statement": "children",
+ "labeled_statement": "children",
+ "return_statement": "children",
+ "seh_leave_statement": "children",
+ "seh_try_statement": "children",
+ "switch_statement": "children",
+ "while_statement": "children",
+ "type_definition": "children",
+ "enum_specifier": "children",
+ "macro_type_specifier": "children",
+ "primitive_type": "children",
+ "sized_type_specifier": "children",
+ "struct_specifier": "children",
+ "type_identifier": "children",
+ "union_specifier": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "preproc_function_def": {
+ "type": "preproc_function_def",
+ "singleFieldNames": ["name", "parameters", "value"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "preproc_if": {
+ "type": "preproc_if",
+ "singleFieldNames": ["alternative", "condition"],
+ "nodeTypeToMultipleFieldName": {
+ "declaration": "children",
+ "enumerator": "children",
+ "field_declaration": "children",
+ "function_definition": "children",
+ "linkage_specification": "children",
+ "preproc_call": "children",
+ "preproc_def": "children",
+ "preproc_function_def": "children",
+ "preproc_if": "children",
+ "preproc_ifdef": "children",
+ "preproc_include": "children",
+ "attributed_statement": "children",
+ "break_statement": "children",
+ "case_statement": "children",
+ "compound_statement": "children",
+ "continue_statement": "children",
+ "do_statement": "children",
+ "expression_statement": "children",
+ "for_statement": "children",
+ "goto_statement": "children",
+ "if_statement": "children",
+ "labeled_statement": "children",
+ "return_statement": "children",
+ "seh_leave_statement": "children",
+ "seh_try_statement": "children",
+ "switch_statement": "children",
+ "while_statement": "children",
+ "type_definition": "children",
+ "enum_specifier": "children",
+ "macro_type_specifier": "children",
+ "primitive_type": "children",
+ "sized_type_specifier": "children",
+ "struct_specifier": "children",
+ "type_identifier": "children",
+ "union_specifier": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "preproc_ifdef": {
+ "type": "preproc_ifdef",
+ "singleFieldNames": ["alternative", "name"],
+ "nodeTypeToMultipleFieldName": {
+ "declaration": "children",
+ "enumerator": "children",
+ "field_declaration": "children",
+ "function_definition": "children",
+ "linkage_specification": "children",
+ "preproc_call": "children",
+ "preproc_def": "children",
+ "preproc_function_def": "children",
+ "preproc_if": "children",
+ "preproc_ifdef": "children",
+ "preproc_include": "children",
+ "attributed_statement": "children",
+ "break_statement": "children",
+ "case_statement": "children",
+ "compound_statement": "children",
+ "continue_statement": "children",
+ "do_statement": "children",
+ "expression_statement": "children",
+ "for_statement": "children",
+ "goto_statement": "children",
+ "if_statement": "children",
+ "labeled_statement": "children",
+ "return_statement": "children",
+ "seh_leave_statement": "children",
+ "seh_try_statement": "children",
+ "switch_statement": "children",
+ "while_statement": "children",
+ "type_definition": "children",
+ "enum_specifier": "children",
+ "macro_type_specifier": "children",
+ "primitive_type": "children",
+ "sized_type_specifier": "children",
+ "struct_specifier": "children",
+ "type_identifier": "children",
+ "union_specifier": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "preproc_include": {
+ "type": "preproc_include",
+ "singleFieldNames": ["path"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "preproc_params": {
+ "type": "preproc_params",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "identifier": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "return_statement": {
+ "type": "return_statement",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "comma_expression": "children",
+ "alignof_expression": "children",
+ "assignment_expression": "children",
+ "binary_expression": "children",
+ "call_expression": "children",
+ "cast_expression": "children",
+ "char_literal": "children",
+ "compound_literal_expression": "children",
+ "concatenated_string": "children",
+ "conditional_expression": "children",
+ "false": "children",
+ "field_expression": "children",
+ "generic_expression": "children",
+ "gnu_asm_expression": "children",
+ "identifier": "children",
+ "null": "children",
+ "number_literal": "children",
+ "offsetof_expression": "children",
+ "parenthesized_expression": "children",
+ "pointer_expression": "children",
+ "sizeof_expression": "children",
+ "string_literal": "children",
+ "subscript_expression": "children",
+ "true": "children",
+ "unary_expression": "children",
+ "update_expression": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "seh_except_clause": {
+ "type": "seh_except_clause",
+ "singleFieldNames": ["body", "filter"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "seh_finally_clause": {
+ "type": "seh_finally_clause",
+ "singleFieldNames": ["body"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "seh_leave_statement": {
+ "type": "seh_leave_statement",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "seh_try_statement": {
+ "type": "seh_try_statement",
+ "singleFieldNames": ["body"],
+ "nodeTypeToMultipleFieldName": {
+ "seh_except_clause": "children",
+ "seh_finally_clause": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "sized_type_specifier": {
+ "type": "sized_type_specifier",
+ "singleFieldNames": ["type"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "sizeof_expression": {
+ "type": "sizeof_expression",
+ "singleFieldNames": ["type", "value"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "storage_class_specifier": {
+ "type": "storage_class_specifier",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "string_literal": {
+ "type": "string_literal",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "escape_sequence": "children",
+ "string_content": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "struct_specifier": {
+ "type": "struct_specifier",
+ "singleFieldNames": ["body", "name"],
+ "nodeTypeToMultipleFieldName": {
+ "attribute_specifier": "children",
+ "ms_declspec_modifier": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "subscript_designator": {
+ "type": "subscript_designator",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "alignof_expression": "children",
+ "assignment_expression": "children",
+ "binary_expression": "children",
+ "call_expression": "children",
+ "cast_expression": "children",
+ "char_literal": "children",
+ "compound_literal_expression": "children",
+ "concatenated_string": "children",
+ "conditional_expression": "children",
+ "false": "children",
+ "field_expression": "children",
+ "generic_expression": "children",
+ "gnu_asm_expression": "children",
+ "identifier": "children",
+ "null": "children",
+ "number_literal": "children",
+ "offsetof_expression": "children",
+ "parenthesized_expression": "children",
+ "pointer_expression": "children",
+ "sizeof_expression": "children",
+ "string_literal": "children",
+ "subscript_expression": "children",
+ "true": "children",
+ "unary_expression": "children",
+ "update_expression": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "subscript_expression": {
+ "type": "subscript_expression",
+ "singleFieldNames": ["argument", "index"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "subscript_range_designator": {
+ "type": "subscript_range_designator",
+ "singleFieldNames": ["end", "start"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "switch_statement": {
+ "type": "switch_statement",
+ "singleFieldNames": ["body", "condition"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "translation_unit": {
+ "type": "translation_unit",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "attributed_statement": "children",
+ "break_statement": "children",
+ "case_statement": "children",
+ "compound_statement": "children",
+ "continue_statement": "children",
+ "declaration": "children",
+ "do_statement": "children",
+ "expression_statement": "children",
+ "for_statement": "children",
+ "function_definition": "children",
+ "goto_statement": "children",
+ "if_statement": "children",
+ "labeled_statement": "children",
+ "linkage_specification": "children",
+ "preproc_call": "children",
+ "preproc_def": "children",
+ "preproc_function_def": "children",
+ "preproc_if": "children",
+ "preproc_ifdef": "children",
+ "preproc_include": "children",
+ "return_statement": "children",
+ "switch_statement": "children",
+ "type_definition": "children",
+ "enum_specifier": "children",
+ "macro_type_specifier": "children",
+ "primitive_type": "children",
+ "sized_type_specifier": "children",
+ "struct_specifier": "children",
+ "type_identifier": "children",
+ "union_specifier": "children",
+ "while_statement": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "type_definition": {
+ "type": "type_definition",
+ "singleFieldNames": ["type"],
+ "nodeTypeToMultipleFieldName": {
+ "array_declarator": "declarator",
+ "attributed_declarator": "declarator",
+ "function_declarator": "declarator",
+ "parenthesized_declarator": "declarator",
+ "pointer_declarator": "declarator",
+ "primitive_type": "declarator",
+ "type_identifier": "declarator",
+ "attribute_specifier": "children",
+ "type_qualifier": "children"
+ },
+ "multipleOrChildrenFieldNames": ["declarator", "children"]
+ },
+ "type_descriptor": {
+ "type": "type_descriptor",
+ "singleFieldNames": ["declarator", "type"],
+ "nodeTypeToMultipleFieldName": {
+ "type_qualifier": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "type_qualifier": {
+ "type": "type_qualifier",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "alignas_qualifier": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "unary_expression": {
+ "type": "unary_expression",
+ "singleFieldNames": ["argument", "operator"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "union_specifier": {
+ "type": "union_specifier",
+ "singleFieldNames": ["body", "name"],
+ "nodeTypeToMultipleFieldName": {
+ "attribute_specifier": "children",
+ "ms_declspec_modifier": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "update_expression": {
+ "type": "update_expression",
+ "singleFieldNames": ["argument", "operator"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "variadic_parameter": {
+ "type": "variadic_parameter",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "while_statement": {
+ "type": "while_statement",
+ "singleFieldNames": ["body", "condition"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "!": {
+ "type": "!",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "!=": {
+ "type": "!=",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "%": {
+ "type": "%",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "%=": {
+ "type": "%=",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "&": {
+ "type": "&",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "&&": {
+ "type": "&&",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "&=": {
+ "type": "&=",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "*": {
+ "type": "*",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "*=": {
+ "type": "*=",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "+": {
+ "type": "+",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "++": {
+ "type": "++",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "+=": {
+ "type": "+=",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "-": {
+ "type": "-",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "--": {
+ "type": "--",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "-=": {
+ "type": "-=",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "->": {
+ "type": "->",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ ".": {
+ "type": ".",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "/": {
+ "type": "/",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "/=": {
+ "type": "/=",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "<": {
+ "type": "<",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "<<": {
+ "type": "<<",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "<<=": {
+ "type": "<<=",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "<=": {
+ "type": "<=",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "=": {
+ "type": "=",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "==": {
+ "type": "==",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ ">": {
+ "type": ">",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ ">=": {
+ "type": ">=",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ ">>": {
+ "type": ">>",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ ">>=": {
+ "type": ">>=",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "^": {
+ "type": "^",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "^=": {
+ "type": "^=",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "character": {
+ "type": "character",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "comment": {
+ "type": "comment",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "escape_sequence": {
+ "type": "escape_sequence",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "false": {
+ "type": "false",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "field_identifier": {
+ "type": "field_identifier",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "identifier": {
+ "type": "identifier",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "ms_restrict_modifier": {
+ "type": "ms_restrict_modifier",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "ms_signed_ptr_modifier": {
+ "type": "ms_signed_ptr_modifier",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "ms_unsigned_ptr_modifier": {
+ "type": "ms_unsigned_ptr_modifier",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "number_literal": {
+ "type": "number_literal",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "preproc_arg": {
+ "type": "preproc_arg",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "preproc_directive": {
+ "type": "preproc_directive",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "primitive_type": {
+ "type": "primitive_type",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "statement_identifier": {
+ "type": "statement_identifier",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "string_content": {
+ "type": "string_content",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "system_lib_string": {
+ "type": "system_lib_string",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "true": {
+ "type": "true",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "type_identifier": {
+ "type": "type_identifier",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "|": {
+ "type": "|",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "|=": {
+ "type": "|=",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "||": {
+ "type": "||",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "~": {
+ "type": "~",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ }
+}
diff --git a/packages/tree-sitter-port/output/tree-sitter-c/meta.json b/packages/tree-sitter-port/output/tree-sitter-c/meta.json
new file mode 100644
index 0000000..bba4b0f
--- /dev/null
+++ b/packages/tree-sitter-port/output/tree-sitter-c/meta.json
@@ -0,0 +1,5 @@
+{
+ "name": "tree-sitter-c",
+ "version": "0.21.4",
+ "generatedAt": "2024-06-26T15:41:27.820Z"
+}
diff --git a/packages/tree-sitter-port/output/tree-sitter-c/parser.wasm b/packages/tree-sitter-port/output/tree-sitter-c/parser.wasm
new file mode 100755
index 0000000..0a801e0
Binary files /dev/null and b/packages/tree-sitter-port/output/tree-sitter-c/parser.wasm differ
diff --git a/packages/tree-sitter-port/output/tree-sitter-lua/fields-meta.json b/packages/tree-sitter-port/output/tree-sitter-lua/fields-meta.json
new file mode 100644
index 0000000..fabde99
--- /dev/null
+++ b/packages/tree-sitter-port/output/tree-sitter-lua/fields-meta.json
@@ -0,0 +1,407 @@
+{
+ "arguments": {
+ "type": "arguments",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "binary_expression": "children",
+ "false": "children",
+ "function_call": "children",
+ "function_definition": "children",
+ "nil": "children",
+ "number": "children",
+ "parenthesized_expression": "children",
+ "string": "children",
+ "table_constructor": "children",
+ "true": "children",
+ "unary_expression": "children",
+ "vararg_expression": "children",
+ "bracket_index_expression": "children",
+ "dot_index_expression": "children",
+ "identifier": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "assignment_statement": {
+ "type": "assignment_statement",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "expression_list": "children",
+ "variable_list": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "attribute": {
+ "type": "attribute",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "identifier": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "binary_expression": {
+ "type": "binary_expression",
+ "singleFieldNames": ["left", "right"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "block": {
+ "type": "block",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "return_statement": "children",
+ "assignment_statement": "children",
+ "break_statement": "children",
+ "function_declaration": "children",
+ "variable_declaration": "children",
+ "do_statement": "children",
+ "empty_statement": "children",
+ "for_statement": "children",
+ "function_call": "children",
+ "goto_statement": "children",
+ "if_statement": "children",
+ "label_statement": "children",
+ "repeat_statement": "children",
+ "while_statement": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "bracket_index_expression": {
+ "type": "bracket_index_expression",
+ "singleFieldNames": ["field", "table"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "chunk": {
+ "type": "chunk",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "hash_bang_line": "children",
+ "return_statement": "children",
+ "assignment_statement": "children",
+ "break_statement": "children",
+ "function_declaration": "children",
+ "variable_declaration": "children",
+ "do_statement": "children",
+ "empty_statement": "children",
+ "for_statement": "children",
+ "function_call": "children",
+ "goto_statement": "children",
+ "if_statement": "children",
+ "label_statement": "children",
+ "repeat_statement": "children",
+ "while_statement": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "comment": {
+ "type": "comment",
+ "singleFieldNames": ["content", "end", "start"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "do_statement": {
+ "type": "do_statement",
+ "singleFieldNames": ["body"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "dot_index_expression": {
+ "type": "dot_index_expression",
+ "singleFieldNames": ["field", "table"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "else_statement": {
+ "type": "else_statement",
+ "singleFieldNames": ["body"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "elseif_statement": {
+ "type": "elseif_statement",
+ "singleFieldNames": ["condition", "consequence"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "empty_statement": {
+ "type": "empty_statement",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "expression_list": {
+ "type": "expression_list",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "binary_expression": "children",
+ "false": "children",
+ "function_call": "children",
+ "function_definition": "children",
+ "nil": "children",
+ "number": "children",
+ "parenthesized_expression": "children",
+ "string": "children",
+ "table_constructor": "children",
+ "true": "children",
+ "unary_expression": "children",
+ "vararg_expression": "children",
+ "bracket_index_expression": "children",
+ "dot_index_expression": "children",
+ "identifier": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "field": {
+ "type": "field",
+ "singleFieldNames": ["name", "value"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "for_generic_clause": {
+ "type": "for_generic_clause",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "expression_list": "children",
+ "variable_list": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "for_numeric_clause": {
+ "type": "for_numeric_clause",
+ "singleFieldNames": ["end", "name", "start", "step"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "for_statement": {
+ "type": "for_statement",
+ "singleFieldNames": ["body", "clause"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "function_call": {
+ "type": "function_call",
+ "singleFieldNames": ["arguments", "name"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "function_declaration": {
+ "type": "function_declaration",
+ "singleFieldNames": ["body", "name", "parameters"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "function_definition": {
+ "type": "function_definition",
+ "singleFieldNames": ["body", "parameters"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "goto_statement": {
+ "type": "goto_statement",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "identifier": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "if_statement": {
+ "type": "if_statement",
+ "singleFieldNames": ["condition", "consequence"],
+ "nodeTypeToMultipleFieldName": {
+ "else_statement": "alternative",
+ "elseif_statement": "alternative"
+ },
+ "multipleOrChildrenFieldNames": ["alternative"]
+ },
+ "label_statement": {
+ "type": "label_statement",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "identifier": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "method_index_expression": {
+ "type": "method_index_expression",
+ "singleFieldNames": ["method", "table"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "parameters": {
+ "type": "parameters",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "identifier": "name",
+ "vararg_expression": "children"
+ },
+ "multipleOrChildrenFieldNames": ["name", "children"]
+ },
+ "parenthesized_expression": {
+ "type": "parenthesized_expression",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "binary_expression": "children",
+ "false": "children",
+ "function_call": "children",
+ "function_definition": "children",
+ "nil": "children",
+ "number": "children",
+ "parenthesized_expression": "children",
+ "string": "children",
+ "table_constructor": "children",
+ "true": "children",
+ "unary_expression": "children",
+ "vararg_expression": "children",
+ "bracket_index_expression": "children",
+ "dot_index_expression": "children",
+ "identifier": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "repeat_statement": {
+ "type": "repeat_statement",
+ "singleFieldNames": ["body", "condition"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "return_statement": {
+ "type": "return_statement",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "expression_list": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "string": {
+ "type": "string",
+ "singleFieldNames": ["content", "end", "start"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "string_content": {
+ "type": "string_content",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "escape_sequence": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "table_constructor": {
+ "type": "table_constructor",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "field": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "unary_expression": {
+ "type": "unary_expression",
+ "singleFieldNames": ["operand"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "variable_declaration": {
+ "type": "variable_declaration",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "assignment_statement": "children",
+ "variable_list": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "variable_list": {
+ "type": "variable_list",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "attribute": "attribute",
+ "bracket_index_expression": "name",
+ "dot_index_expression": "name",
+ "identifier": "name"
+ },
+ "multipleOrChildrenFieldNames": ["attribute", "name"]
+ },
+ "while_statement": {
+ "type": "while_statement",
+ "singleFieldNames": ["body", "condition"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "--": {
+ "type": "--",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "[[": {
+ "type": "[[",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "]]": {
+ "type": "]]",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "break_statement": {
+ "type": "break_statement",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "comment_content": {
+ "type": "comment_content",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "escape_sequence": {
+ "type": "escape_sequence",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "false": {
+ "type": "false",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "hash_bang_line": {
+ "type": "hash_bang_line",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "identifier": {
+ "type": "identifier",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "nil": {
+ "type": "nil",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "number": {
+ "type": "number",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "true": {
+ "type": "true",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "vararg_expression": {
+ "type": "vararg_expression",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ }
+}
diff --git a/packages/tree-sitter-port/output/tree-sitter-lua/meta.json b/packages/tree-sitter-port/output/tree-sitter-lua/meta.json
new file mode 100644
index 0000000..6b94e7d
--- /dev/null
+++ b/packages/tree-sitter-port/output/tree-sitter-lua/meta.json
@@ -0,0 +1,5 @@
+{
+ "name": "tree-sitter-lua",
+ "version": "0.1.0",
+ "generatedAt": "2024-06-26T15:41:59.042Z"
+}
diff --git a/packages/tree-sitter-port/output/tree-sitter-lua/parser.wasm b/packages/tree-sitter-port/output/tree-sitter-lua/parser.wasm
new file mode 100755
index 0000000..9e28306
Binary files /dev/null and b/packages/tree-sitter-port/output/tree-sitter-lua/parser.wasm differ
diff --git a/packages/tree-sitter-port/output/tree-sitter-php/meta.json b/packages/tree-sitter-port/output/tree-sitter-php/meta.json
new file mode 100644
index 0000000..53dd175
--- /dev/null
+++ b/packages/tree-sitter-port/output/tree-sitter-php/meta.json
@@ -0,0 +1,5 @@
+{
+ "name": "tree-sitter-php",
+ "version": "0.22.5",
+ "generatedAt": "2024-06-26T15:42:10.851Z"
+}
diff --git a/packages/tree-sitter-port/output/tree-sitter-python/fields-meta.json b/packages/tree-sitter-port/output/tree-sitter-python/fields-meta.json
new file mode 100644
index 0000000..db41dd9
--- /dev/null
+++ b/packages/tree-sitter-port/output/tree-sitter-python/fields-meta.json
@@ -0,0 +1,2147 @@
+{
+ "aliased_import": {
+ "type": "aliased_import",
+ "singleFieldNames": ["alias", "name"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "argument_list": {
+ "type": "argument_list",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "dictionary_splat": "children",
+ "as_pattern": "children",
+ "boolean_operator": "children",
+ "comparison_operator": "children",
+ "conditional_expression": "children",
+ "lambda": "children",
+ "named_expression": "children",
+ "not_operator": "children",
+ "attribute": "children",
+ "await": "children",
+ "binary_operator": "children",
+ "call": "children",
+ "concatenated_string": "children",
+ "dictionary": "children",
+ "dictionary_comprehension": "children",
+ "ellipsis": "children",
+ "false": "children",
+ "float": "children",
+ "generator_expression": "children",
+ "identifier": "children",
+ "integer": "children",
+ "list": "children",
+ "list_comprehension": "children",
+ "list_splat": "children",
+ "none": "children",
+ "parenthesized_expression": "children",
+ "set": "children",
+ "set_comprehension": "children",
+ "string": "children",
+ "subscript": "children",
+ "true": "children",
+ "tuple": "children",
+ "unary_operator": "children",
+ "keyword_argument": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "as_pattern": {
+ "type": "as_pattern",
+ "singleFieldNames": ["alias"],
+ "nodeTypeToMultipleFieldName": {
+ "case_pattern": "children",
+ "as_pattern": "children",
+ "boolean_operator": "children",
+ "comparison_operator": "children",
+ "conditional_expression": "children",
+ "lambda": "children",
+ "named_expression": "children",
+ "not_operator": "children",
+ "attribute": "children",
+ "await": "children",
+ "binary_operator": "children",
+ "call": "children",
+ "concatenated_string": "children",
+ "dictionary": "children",
+ "dictionary_comprehension": "children",
+ "ellipsis": "children",
+ "false": "children",
+ "float": "children",
+ "generator_expression": "children",
+ "identifier": "children",
+ "integer": "children",
+ "list": "children",
+ "list_comprehension": "children",
+ "list_splat": "children",
+ "none": "children",
+ "parenthesized_expression": "children",
+ "set": "children",
+ "set_comprehension": "children",
+ "string": "children",
+ "subscript": "children",
+ "true": "children",
+ "tuple": "children",
+ "unary_operator": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "assert_statement": {
+ "type": "assert_statement",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "as_pattern": "children",
+ "boolean_operator": "children",
+ "comparison_operator": "children",
+ "conditional_expression": "children",
+ "lambda": "children",
+ "named_expression": "children",
+ "not_operator": "children",
+ "attribute": "children",
+ "await": "children",
+ "binary_operator": "children",
+ "call": "children",
+ "concatenated_string": "children",
+ "dictionary": "children",
+ "dictionary_comprehension": "children",
+ "ellipsis": "children",
+ "false": "children",
+ "float": "children",
+ "generator_expression": "children",
+ "identifier": "children",
+ "integer": "children",
+ "list": "children",
+ "list_comprehension": "children",
+ "list_splat": "children",
+ "none": "children",
+ "parenthesized_expression": "children",
+ "set": "children",
+ "set_comprehension": "children",
+ "string": "children",
+ "subscript": "children",
+ "true": "children",
+ "tuple": "children",
+ "unary_operator": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "assignment": {
+ "type": "assignment",
+ "singleFieldNames": ["left", "right", "type"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "attribute": {
+ "type": "attribute",
+ "singleFieldNames": ["attribute", "object"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "augmented_assignment": {
+ "type": "augmented_assignment",
+ "singleFieldNames": ["left", "operator", "right"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "binary_operator": {
+ "type": "binary_operator",
+ "singleFieldNames": ["left", "operator", "right"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "block": {
+ "type": "block",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "case_clause": "alternative",
+ "class_definition": "children",
+ "decorated_definition": "children",
+ "for_statement": "children",
+ "function_definition": "children",
+ "if_statement": "children",
+ "match_statement": "children",
+ "try_statement": "children",
+ "while_statement": "children",
+ "with_statement": "children",
+ "assert_statement": "children",
+ "break_statement": "children",
+ "continue_statement": "children",
+ "delete_statement": "children",
+ "exec_statement": "children",
+ "expression_statement": "children",
+ "future_import_statement": "children",
+ "global_statement": "children",
+ "import_from_statement": "children",
+ "import_statement": "children",
+ "nonlocal_statement": "children",
+ "pass_statement": "children",
+ "print_statement": "children",
+ "raise_statement": "children",
+ "return_statement": "children",
+ "type_alias_statement": "children"
+ },
+ "multipleOrChildrenFieldNames": ["alternative", "children"]
+ },
+ "boolean_operator": {
+ "type": "boolean_operator",
+ "singleFieldNames": ["left", "operator", "right"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "break_statement": {
+ "type": "break_statement",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "call": {
+ "type": "call",
+ "singleFieldNames": ["arguments", "function"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "case_clause": {
+ "type": "case_clause",
+ "singleFieldNames": ["consequence", "guard"],
+ "nodeTypeToMultipleFieldName": {
+ "case_pattern": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "case_pattern": {
+ "type": "case_pattern",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "as_pattern": "children",
+ "class_pattern": "children",
+ "complex_pattern": "children",
+ "concatenated_string": "children",
+ "dict_pattern": "children",
+ "dotted_name": "children",
+ "false": "children",
+ "float": "children",
+ "integer": "children",
+ "keyword_pattern": "children",
+ "list_pattern": "children",
+ "none": "children",
+ "splat_pattern": "children",
+ "string": "children",
+ "true": "children",
+ "tuple_pattern": "children",
+ "union_pattern": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "chevron": {
+ "type": "chevron",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "as_pattern": "children",
+ "boolean_operator": "children",
+ "comparison_operator": "children",
+ "conditional_expression": "children",
+ "lambda": "children",
+ "named_expression": "children",
+ "not_operator": "children",
+ "attribute": "children",
+ "await": "children",
+ "binary_operator": "children",
+ "call": "children",
+ "concatenated_string": "children",
+ "dictionary": "children",
+ "dictionary_comprehension": "children",
+ "ellipsis": "children",
+ "false": "children",
+ "float": "children",
+ "generator_expression": "children",
+ "identifier": "children",
+ "integer": "children",
+ "list": "children",
+ "list_comprehension": "children",
+ "list_splat": "children",
+ "none": "children",
+ "parenthesized_expression": "children",
+ "set": "children",
+ "set_comprehension": "children",
+ "string": "children",
+ "subscript": "children",
+ "true": "children",
+ "tuple": "children",
+ "unary_operator": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "class_definition": {
+ "type": "class_definition",
+ "singleFieldNames": ["body", "name", "superclasses", "type_parameters"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "class_pattern": {
+ "type": "class_pattern",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "case_pattern": "children",
+ "dotted_name": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "comparison_operator": {
+ "type": "comparison_operator",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "!=": "operators",
+ "<": "operators",
+ "<=": "operators",
+ "<>": "operators",
+ "==": "operators",
+ ">": "operators",
+ ">=": "operators",
+ "in": "operators",
+ "is": "operators",
+ "is not": "operators",
+ "not in": "operators",
+ "attribute": "children",
+ "await": "children",
+ "binary_operator": "children",
+ "call": "children",
+ "concatenated_string": "children",
+ "dictionary": "children",
+ "dictionary_comprehension": "children",
+ "ellipsis": "children",
+ "false": "children",
+ "float": "children",
+ "generator_expression": "children",
+ "identifier": "children",
+ "integer": "children",
+ "list": "children",
+ "list_comprehension": "children",
+ "list_splat": "children",
+ "none": "children",
+ "parenthesized_expression": "children",
+ "set": "children",
+ "set_comprehension": "children",
+ "string": "children",
+ "subscript": "children",
+ "true": "children",
+ "tuple": "children",
+ "unary_operator": "children"
+ },
+ "multipleOrChildrenFieldNames": ["operators", "children"]
+ },
+ "complex_pattern": {
+ "type": "complex_pattern",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "float": "children",
+ "integer": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "concatenated_string": {
+ "type": "concatenated_string",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "string": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "conditional_expression": {
+ "type": "conditional_expression",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "as_pattern": "children",
+ "boolean_operator": "children",
+ "comparison_operator": "children",
+ "conditional_expression": "children",
+ "lambda": "children",
+ "named_expression": "children",
+ "not_operator": "children",
+ "attribute": "children",
+ "await": "children",
+ "binary_operator": "children",
+ "call": "children",
+ "concatenated_string": "children",
+ "dictionary": "children",
+ "dictionary_comprehension": "children",
+ "ellipsis": "children",
+ "false": "children",
+ "float": "children",
+ "generator_expression": "children",
+ "identifier": "children",
+ "integer": "children",
+ "list": "children",
+ "list_comprehension": "children",
+ "list_splat": "children",
+ "none": "children",
+ "parenthesized_expression": "children",
+ "set": "children",
+ "set_comprehension": "children",
+ "string": "children",
+ "subscript": "children",
+ "true": "children",
+ "tuple": "children",
+ "unary_operator": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "constrained_type": {
+ "type": "constrained_type",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "type": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "continue_statement": {
+ "type": "continue_statement",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "decorated_definition": {
+ "type": "decorated_definition",
+ "singleFieldNames": ["definition"],
+ "nodeTypeToMultipleFieldName": {
+ "decorator": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "decorator": {
+ "type": "decorator",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "as_pattern": "children",
+ "boolean_operator": "children",
+ "comparison_operator": "children",
+ "conditional_expression": "children",
+ "lambda": "children",
+ "named_expression": "children",
+ "not_operator": "children",
+ "attribute": "children",
+ "await": "children",
+ "binary_operator": "children",
+ "call": "children",
+ "concatenated_string": "children",
+ "dictionary": "children",
+ "dictionary_comprehension": "children",
+ "ellipsis": "children",
+ "false": "children",
+ "float": "children",
+ "generator_expression": "children",
+ "identifier": "children",
+ "integer": "children",
+ "list": "children",
+ "list_comprehension": "children",
+ "list_splat": "children",
+ "none": "children",
+ "parenthesized_expression": "children",
+ "set": "children",
+ "set_comprehension": "children",
+ "string": "children",
+ "subscript": "children",
+ "true": "children",
+ "tuple": "children",
+ "unary_operator": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "default_parameter": {
+ "type": "default_parameter",
+ "singleFieldNames": ["name", "value"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "delete_statement": {
+ "type": "delete_statement",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "as_pattern": "children",
+ "boolean_operator": "children",
+ "comparison_operator": "children",
+ "conditional_expression": "children",
+ "lambda": "children",
+ "named_expression": "children",
+ "not_operator": "children",
+ "attribute": "children",
+ "await": "children",
+ "binary_operator": "children",
+ "call": "children",
+ "concatenated_string": "children",
+ "dictionary": "children",
+ "dictionary_comprehension": "children",
+ "ellipsis": "children",
+ "false": "children",
+ "float": "children",
+ "generator_expression": "children",
+ "identifier": "children",
+ "integer": "children",
+ "list": "children",
+ "list_comprehension": "children",
+ "list_splat": "children",
+ "none": "children",
+ "parenthesized_expression": "children",
+ "set": "children",
+ "set_comprehension": "children",
+ "string": "children",
+ "subscript": "children",
+ "true": "children",
+ "tuple": "children",
+ "unary_operator": "children",
+ "expression_list": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "dict_pattern": {
+ "type": "dict_pattern",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "case_pattern": "value",
+ "splat_pattern": "children",
+ "-": "children",
+ "_": "children",
+ "class_pattern": "children",
+ "complex_pattern": "children",
+ "concatenated_string": "children",
+ "dict_pattern": "children",
+ "dotted_name": "children",
+ "false": "children",
+ "float": "children",
+ "integer": "children",
+ "list_pattern": "children",
+ "none": "children",
+ "string": "children",
+ "true": "children",
+ "tuple_pattern": "children",
+ "union_pattern": "children"
+ },
+ "multipleOrChildrenFieldNames": ["value", "children"]
+ },
+ "dictionary": {
+ "type": "dictionary",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "dictionary_splat": "children",
+ "pair": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "dictionary_comprehension": {
+ "type": "dictionary_comprehension",
+ "singleFieldNames": ["body"],
+ "nodeTypeToMultipleFieldName": {
+ "for_in_clause": "children",
+ "if_clause": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "dictionary_splat": {
+ "type": "dictionary_splat",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "as_pattern": "children",
+ "boolean_operator": "children",
+ "comparison_operator": "children",
+ "conditional_expression": "children",
+ "lambda": "children",
+ "named_expression": "children",
+ "not_operator": "children",
+ "attribute": "children",
+ "await": "children",
+ "binary_operator": "children",
+ "call": "children",
+ "concatenated_string": "children",
+ "dictionary": "children",
+ "dictionary_comprehension": "children",
+ "ellipsis": "children",
+ "false": "children",
+ "float": "children",
+ "generator_expression": "children",
+ "identifier": "children",
+ "integer": "children",
+ "list": "children",
+ "list_comprehension": "children",
+ "list_splat": "children",
+ "none": "children",
+ "parenthesized_expression": "children",
+ "set": "children",
+ "set_comprehension": "children",
+ "string": "children",
+ "subscript": "children",
+ "true": "children",
+ "tuple": "children",
+ "unary_operator": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "dictionary_splat_pattern": {
+ "type": "dictionary_splat_pattern",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "attribute": "children",
+ "identifier": "children",
+ "subscript": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "dotted_name": {
+ "type": "dotted_name",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "identifier": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "elif_clause": {
+ "type": "elif_clause",
+ "singleFieldNames": ["condition", "consequence"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "else_clause": {
+ "type": "else_clause",
+ "singleFieldNames": ["body"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "except_clause": {
+ "type": "except_clause",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "block": "children",
+ "as_pattern": "children",
+ "boolean_operator": "children",
+ "comparison_operator": "children",
+ "conditional_expression": "children",
+ "lambda": "children",
+ "named_expression": "children",
+ "not_operator": "children",
+ "attribute": "children",
+ "await": "children",
+ "binary_operator": "children",
+ "call": "children",
+ "concatenated_string": "children",
+ "dictionary": "children",
+ "dictionary_comprehension": "children",
+ "ellipsis": "children",
+ "false": "children",
+ "float": "children",
+ "generator_expression": "children",
+ "identifier": "children",
+ "integer": "children",
+ "list": "children",
+ "list_comprehension": "children",
+ "list_splat": "children",
+ "none": "children",
+ "parenthesized_expression": "children",
+ "set": "children",
+ "set_comprehension": "children",
+ "string": "children",
+ "subscript": "children",
+ "true": "children",
+ "tuple": "children",
+ "unary_operator": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "except_group_clause": {
+ "type": "except_group_clause",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "block": "children",
+ "as_pattern": "children",
+ "boolean_operator": "children",
+ "comparison_operator": "children",
+ "conditional_expression": "children",
+ "lambda": "children",
+ "named_expression": "children",
+ "not_operator": "children",
+ "attribute": "children",
+ "await": "children",
+ "binary_operator": "children",
+ "call": "children",
+ "concatenated_string": "children",
+ "dictionary": "children",
+ "dictionary_comprehension": "children",
+ "ellipsis": "children",
+ "false": "children",
+ "float": "children",
+ "generator_expression": "children",
+ "identifier": "children",
+ "integer": "children",
+ "list": "children",
+ "list_comprehension": "children",
+ "list_splat": "children",
+ "none": "children",
+ "parenthesized_expression": "children",
+ "set": "children",
+ "set_comprehension": "children",
+ "string": "children",
+ "subscript": "children",
+ "true": "children",
+ "tuple": "children",
+ "unary_operator": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "exec_statement": {
+ "type": "exec_statement",
+ "singleFieldNames": ["code"],
+ "nodeTypeToMultipleFieldName": {
+ "as_pattern": "children",
+ "boolean_operator": "children",
+ "comparison_operator": "children",
+ "conditional_expression": "children",
+ "lambda": "children",
+ "named_expression": "children",
+ "not_operator": "children",
+ "attribute": "children",
+ "await": "children",
+ "binary_operator": "children",
+ "call": "children",
+ "concatenated_string": "children",
+ "dictionary": "children",
+ "dictionary_comprehension": "children",
+ "ellipsis": "children",
+ "false": "children",
+ "float": "children",
+ "generator_expression": "children",
+ "identifier": "children",
+ "integer": "children",
+ "list": "children",
+ "list_comprehension": "children",
+ "list_splat": "children",
+ "none": "children",
+ "parenthesized_expression": "children",
+ "set": "children",
+ "set_comprehension": "children",
+ "string": "children",
+ "subscript": "children",
+ "true": "children",
+ "tuple": "children",
+ "unary_operator": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "expression_list": {
+ "type": "expression_list",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "as_pattern": "children",
+ "boolean_operator": "children",
+ "comparison_operator": "children",
+ "conditional_expression": "children",
+ "lambda": "children",
+ "named_expression": "children",
+ "not_operator": "children",
+ "attribute": "children",
+ "await": "children",
+ "binary_operator": "children",
+ "call": "children",
+ "concatenated_string": "children",
+ "dictionary": "children",
+ "dictionary_comprehension": "children",
+ "ellipsis": "children",
+ "false": "children",
+ "float": "children",
+ "generator_expression": "children",
+ "identifier": "children",
+ "integer": "children",
+ "list": "children",
+ "list_comprehension": "children",
+ "list_splat": "children",
+ "none": "children",
+ "parenthesized_expression": "children",
+ "set": "children",
+ "set_comprehension": "children",
+ "string": "children",
+ "subscript": "children",
+ "true": "children",
+ "tuple": "children",
+ "unary_operator": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "expression_statement": {
+ "type": "expression_statement",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "assignment": "children",
+ "augmented_assignment": "children",
+ "as_pattern": "children",
+ "boolean_operator": "children",
+ "comparison_operator": "children",
+ "conditional_expression": "children",
+ "lambda": "children",
+ "named_expression": "children",
+ "not_operator": "children",
+ "attribute": "children",
+ "await": "children",
+ "binary_operator": "children",
+ "call": "children",
+ "concatenated_string": "children",
+ "dictionary": "children",
+ "dictionary_comprehension": "children",
+ "ellipsis": "children",
+ "false": "children",
+ "float": "children",
+ "generator_expression": "children",
+ "identifier": "children",
+ "integer": "children",
+ "list": "children",
+ "list_comprehension": "children",
+ "list_splat": "children",
+ "none": "children",
+ "parenthesized_expression": "children",
+ "set": "children",
+ "set_comprehension": "children",
+ "string": "children",
+ "subscript": "children",
+ "true": "children",
+ "tuple": "children",
+ "unary_operator": "children",
+ "yield": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "finally_clause": {
+ "type": "finally_clause",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "block": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "for_in_clause": {
+ "type": "for_in_clause",
+ "singleFieldNames": ["left"],
+ "nodeTypeToMultipleFieldName": {
+ ",": "right",
+ "as_pattern": "right",
+ "boolean_operator": "right",
+ "comparison_operator": "right",
+ "conditional_expression": "right",
+ "lambda": "right",
+ "named_expression": "right",
+ "not_operator": "right",
+ "attribute": "right",
+ "await": "right",
+ "binary_operator": "right",
+ "call": "right",
+ "concatenated_string": "right",
+ "dictionary": "right",
+ "dictionary_comprehension": "right",
+ "ellipsis": "right",
+ "false": "right",
+ "float": "right",
+ "generator_expression": "right",
+ "identifier": "right",
+ "integer": "right",
+ "list": "right",
+ "list_comprehension": "right",
+ "list_splat": "right",
+ "none": "right",
+ "parenthesized_expression": "right",
+ "set": "right",
+ "set_comprehension": "right",
+ "string": "right",
+ "subscript": "right",
+ "true": "right",
+ "tuple": "right",
+ "unary_operator": "right"
+ },
+ "multipleOrChildrenFieldNames": ["right"]
+ },
+ "for_statement": {
+ "type": "for_statement",
+ "singleFieldNames": ["alternative", "body", "left", "right"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "format_expression": {
+ "type": "format_expression",
+ "singleFieldNames": ["expression", "format_specifier", "type_conversion"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "format_specifier": {
+ "type": "format_specifier",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "format_expression": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "function_definition": {
+ "type": "function_definition",
+ "singleFieldNames": [
+ "body",
+ "name",
+ "parameters",
+ "return_type",
+ "type_parameters"
+ ],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "future_import_statement": {
+ "type": "future_import_statement",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "aliased_import": "name",
+ "dotted_name": "name"
+ },
+ "multipleOrChildrenFieldNames": ["name"]
+ },
+ "generator_expression": {
+ "type": "generator_expression",
+ "singleFieldNames": ["body"],
+ "nodeTypeToMultipleFieldName": {
+ "for_in_clause": "children",
+ "if_clause": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "generic_type": {
+ "type": "generic_type",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "identifier": "children",
+ "type_parameter": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "global_statement": {
+ "type": "global_statement",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "identifier": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "if_clause": {
+ "type": "if_clause",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "as_pattern": "children",
+ "boolean_operator": "children",
+ "comparison_operator": "children",
+ "conditional_expression": "children",
+ "lambda": "children",
+ "named_expression": "children",
+ "not_operator": "children",
+ "attribute": "children",
+ "await": "children",
+ "binary_operator": "children",
+ "call": "children",
+ "concatenated_string": "children",
+ "dictionary": "children",
+ "dictionary_comprehension": "children",
+ "ellipsis": "children",
+ "false": "children",
+ "float": "children",
+ "generator_expression": "children",
+ "identifier": "children",
+ "integer": "children",
+ "list": "children",
+ "list_comprehension": "children",
+ "list_splat": "children",
+ "none": "children",
+ "parenthesized_expression": "children",
+ "set": "children",
+ "set_comprehension": "children",
+ "string": "children",
+ "subscript": "children",
+ "true": "children",
+ "tuple": "children",
+ "unary_operator": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "if_statement": {
+ "type": "if_statement",
+ "singleFieldNames": ["condition", "consequence"],
+ "nodeTypeToMultipleFieldName": {
+ "elif_clause": "alternative",
+ "else_clause": "alternative"
+ },
+ "multipleOrChildrenFieldNames": ["alternative"]
+ },
+ "import_from_statement": {
+ "type": "import_from_statement",
+ "singleFieldNames": ["module_name"],
+ "nodeTypeToMultipleFieldName": {
+ "aliased_import": "name",
+ "dotted_name": "name",
+ "wildcard_import": "children"
+ },
+ "multipleOrChildrenFieldNames": ["name", "children"]
+ },
+ "import_prefix": {
+ "type": "import_prefix",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "import_statement": {
+ "type": "import_statement",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "aliased_import": "name",
+ "dotted_name": "name"
+ },
+ "multipleOrChildrenFieldNames": ["name"]
+ },
+ "interpolation": {
+ "type": "interpolation",
+ "singleFieldNames": ["expression", "format_specifier", "type_conversion"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "keyword_argument": {
+ "type": "keyword_argument",
+ "singleFieldNames": ["name", "value"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "keyword_pattern": {
+ "type": "keyword_pattern",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "class_pattern": "children",
+ "complex_pattern": "children",
+ "concatenated_string": "children",
+ "dict_pattern": "children",
+ "dotted_name": "children",
+ "false": "children",
+ "float": "children",
+ "identifier": "children",
+ "integer": "children",
+ "list_pattern": "children",
+ "none": "children",
+ "splat_pattern": "children",
+ "string": "children",
+ "true": "children",
+ "tuple_pattern": "children",
+ "union_pattern": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "keyword_separator": {
+ "type": "keyword_separator",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "lambda_parameters": {
+ "type": "lambda_parameters",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "default_parameter": "children",
+ "dictionary_splat_pattern": "children",
+ "identifier": "children",
+ "keyword_separator": "children",
+ "list_splat_pattern": "children",
+ "positional_separator": "children",
+ "tuple_pattern": "children",
+ "typed_default_parameter": "children",
+ "typed_parameter": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "list": {
+ "type": "list",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "as_pattern": "children",
+ "boolean_operator": "children",
+ "comparison_operator": "children",
+ "conditional_expression": "children",
+ "lambda": "children",
+ "named_expression": "children",
+ "not_operator": "children",
+ "attribute": "children",
+ "await": "children",
+ "binary_operator": "children",
+ "call": "children",
+ "concatenated_string": "children",
+ "dictionary": "children",
+ "dictionary_comprehension": "children",
+ "ellipsis": "children",
+ "false": "children",
+ "float": "children",
+ "generator_expression": "children",
+ "identifier": "children",
+ "integer": "children",
+ "list": "children",
+ "list_comprehension": "children",
+ "list_splat": "children",
+ "none": "children",
+ "parenthesized_expression": "children",
+ "set": "children",
+ "set_comprehension": "children",
+ "string": "children",
+ "subscript": "children",
+ "true": "children",
+ "tuple": "children",
+ "unary_operator": "children",
+ "parenthesized_list_splat": "children",
+ "yield": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "list_comprehension": {
+ "type": "list_comprehension",
+ "singleFieldNames": ["body"],
+ "nodeTypeToMultipleFieldName": {
+ "for_in_clause": "children",
+ "if_clause": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "list_pattern": {
+ "type": "list_pattern",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "case_pattern": "children",
+ "attribute": "children",
+ "identifier": "children",
+ "list_pattern": "children",
+ "list_splat_pattern": "children",
+ "subscript": "children",
+ "tuple_pattern": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "list_splat": {
+ "type": "list_splat",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "attribute": "children",
+ "as_pattern": "children",
+ "boolean_operator": "children",
+ "comparison_operator": "children",
+ "conditional_expression": "children",
+ "lambda": "children",
+ "named_expression": "children",
+ "not_operator": "children",
+ "await": "children",
+ "binary_operator": "children",
+ "call": "children",
+ "concatenated_string": "children",
+ "dictionary": "children",
+ "dictionary_comprehension": "children",
+ "ellipsis": "children",
+ "false": "children",
+ "float": "children",
+ "generator_expression": "children",
+ "identifier": "children",
+ "integer": "children",
+ "list": "children",
+ "list_comprehension": "children",
+ "list_splat": "children",
+ "none": "children",
+ "parenthesized_expression": "children",
+ "set": "children",
+ "set_comprehension": "children",
+ "string": "children",
+ "subscript": "children",
+ "true": "children",
+ "tuple": "children",
+ "unary_operator": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "list_splat_pattern": {
+ "type": "list_splat_pattern",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "attribute": "children",
+ "identifier": "children",
+ "subscript": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "match_statement": {
+ "type": "match_statement",
+ "singleFieldNames": ["body"],
+ "nodeTypeToMultipleFieldName": {
+ "as_pattern": "subject",
+ "boolean_operator": "subject",
+ "comparison_operator": "subject",
+ "conditional_expression": "subject",
+ "lambda": "subject",
+ "named_expression": "subject",
+ "not_operator": "subject",
+ "attribute": "subject",
+ "await": "subject",
+ "binary_operator": "subject",
+ "call": "subject",
+ "concatenated_string": "subject",
+ "dictionary": "subject",
+ "dictionary_comprehension": "subject",
+ "ellipsis": "subject",
+ "false": "subject",
+ "float": "subject",
+ "generator_expression": "subject",
+ "identifier": "subject",
+ "integer": "subject",
+ "list": "subject",
+ "list_comprehension": "subject",
+ "list_splat": "subject",
+ "none": "subject",
+ "parenthesized_expression": "subject",
+ "set": "subject",
+ "set_comprehension": "subject",
+ "string": "subject",
+ "subscript": "subject",
+ "true": "subject",
+ "tuple": "subject",
+ "unary_operator": "subject"
+ },
+ "multipleOrChildrenFieldNames": ["subject"]
+ },
+ "member_type": {
+ "type": "member_type",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "identifier": "children",
+ "type": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "module": {
+ "type": "module",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "class_definition": "children",
+ "decorated_definition": "children",
+ "for_statement": "children",
+ "function_definition": "children",
+ "if_statement": "children",
+ "match_statement": "children",
+ "try_statement": "children",
+ "while_statement": "children",
+ "with_statement": "children",
+ "assert_statement": "children",
+ "break_statement": "children",
+ "continue_statement": "children",
+ "delete_statement": "children",
+ "exec_statement": "children",
+ "expression_statement": "children",
+ "future_import_statement": "children",
+ "global_statement": "children",
+ "import_from_statement": "children",
+ "import_statement": "children",
+ "nonlocal_statement": "children",
+ "pass_statement": "children",
+ "print_statement": "children",
+ "raise_statement": "children",
+ "return_statement": "children",
+ "type_alias_statement": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "named_expression": {
+ "type": "named_expression",
+ "singleFieldNames": ["name", "value"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "nonlocal_statement": {
+ "type": "nonlocal_statement",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "identifier": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "not_operator": {
+ "type": "not_operator",
+ "singleFieldNames": ["argument"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "pair": {
+ "type": "pair",
+ "singleFieldNames": ["key", "value"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "parameters": {
+ "type": "parameters",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "default_parameter": "children",
+ "dictionary_splat_pattern": "children",
+ "identifier": "children",
+ "keyword_separator": "children",
+ "list_splat_pattern": "children",
+ "positional_separator": "children",
+ "tuple_pattern": "children",
+ "typed_default_parameter": "children",
+ "typed_parameter": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "parenthesized_expression": {
+ "type": "parenthesized_expression",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "as_pattern": "children",
+ "boolean_operator": "children",
+ "comparison_operator": "children",
+ "conditional_expression": "children",
+ "lambda": "children",
+ "named_expression": "children",
+ "not_operator": "children",
+ "attribute": "children",
+ "await": "children",
+ "binary_operator": "children",
+ "call": "children",
+ "concatenated_string": "children",
+ "dictionary": "children",
+ "dictionary_comprehension": "children",
+ "ellipsis": "children",
+ "false": "children",
+ "float": "children",
+ "generator_expression": "children",
+ "identifier": "children",
+ "integer": "children",
+ "list": "children",
+ "list_comprehension": "children",
+ "list_splat": "children",
+ "none": "children",
+ "parenthesized_expression": "children",
+ "set": "children",
+ "set_comprehension": "children",
+ "string": "children",
+ "subscript": "children",
+ "true": "children",
+ "tuple": "children",
+ "unary_operator": "children",
+ "yield": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "parenthesized_list_splat": {
+ "type": "parenthesized_list_splat",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "list_splat": "children",
+ "parenthesized_expression": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "pass_statement": {
+ "type": "pass_statement",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "pattern_list": {
+ "type": "pattern_list",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "attribute": "children",
+ "identifier": "children",
+ "list_pattern": "children",
+ "list_splat_pattern": "children",
+ "subscript": "children",
+ "tuple_pattern": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "positional_separator": {
+ "type": "positional_separator",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "print_statement": {
+ "type": "print_statement",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "as_pattern": "argument",
+ "boolean_operator": "argument",
+ "comparison_operator": "argument",
+ "conditional_expression": "argument",
+ "lambda": "argument",
+ "named_expression": "argument",
+ "not_operator": "argument",
+ "attribute": "argument",
+ "await": "argument",
+ "binary_operator": "argument",
+ "call": "argument",
+ "concatenated_string": "argument",
+ "dictionary": "argument",
+ "dictionary_comprehension": "argument",
+ "ellipsis": "argument",
+ "false": "argument",
+ "float": "argument",
+ "generator_expression": "argument",
+ "identifier": "argument",
+ "integer": "argument",
+ "list": "argument",
+ "list_comprehension": "argument",
+ "list_splat": "argument",
+ "none": "argument",
+ "parenthesized_expression": "argument",
+ "set": "argument",
+ "set_comprehension": "argument",
+ "string": "argument",
+ "subscript": "argument",
+ "true": "argument",
+ "tuple": "argument",
+ "unary_operator": "argument",
+ "chevron": "children"
+ },
+ "multipleOrChildrenFieldNames": ["argument", "children"]
+ },
+ "raise_statement": {
+ "type": "raise_statement",
+ "singleFieldNames": ["cause"],
+ "nodeTypeToMultipleFieldName": {
+ "as_pattern": "children",
+ "boolean_operator": "children",
+ "comparison_operator": "children",
+ "conditional_expression": "children",
+ "lambda": "children",
+ "named_expression": "children",
+ "not_operator": "children",
+ "attribute": "children",
+ "await": "children",
+ "binary_operator": "children",
+ "call": "children",
+ "concatenated_string": "children",
+ "dictionary": "children",
+ "dictionary_comprehension": "children",
+ "ellipsis": "children",
+ "false": "children",
+ "float": "children",
+ "generator_expression": "children",
+ "identifier": "children",
+ "integer": "children",
+ "list": "children",
+ "list_comprehension": "children",
+ "list_splat": "children",
+ "none": "children",
+ "parenthesized_expression": "children",
+ "set": "children",
+ "set_comprehension": "children",
+ "string": "children",
+ "subscript": "children",
+ "true": "children",
+ "tuple": "children",
+ "unary_operator": "children",
+ "expression_list": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "relative_import": {
+ "type": "relative_import",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "dotted_name": "children",
+ "import_prefix": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "return_statement": {
+ "type": "return_statement",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "as_pattern": "children",
+ "boolean_operator": "children",
+ "comparison_operator": "children",
+ "conditional_expression": "children",
+ "lambda": "children",
+ "named_expression": "children",
+ "not_operator": "children",
+ "attribute": "children",
+ "await": "children",
+ "binary_operator": "children",
+ "call": "children",
+ "concatenated_string": "children",
+ "dictionary": "children",
+ "dictionary_comprehension": "children",
+ "ellipsis": "children",
+ "false": "children",
+ "float": "children",
+ "generator_expression": "children",
+ "identifier": "children",
+ "integer": "children",
+ "list": "children",
+ "list_comprehension": "children",
+ "list_splat": "children",
+ "none": "children",
+ "parenthesized_expression": "children",
+ "set": "children",
+ "set_comprehension": "children",
+ "string": "children",
+ "subscript": "children",
+ "true": "children",
+ "tuple": "children",
+ "unary_operator": "children",
+ "expression_list": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "set": {
+ "type": "set",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "as_pattern": "children",
+ "boolean_operator": "children",
+ "comparison_operator": "children",
+ "conditional_expression": "children",
+ "lambda": "children",
+ "named_expression": "children",
+ "not_operator": "children",
+ "attribute": "children",
+ "await": "children",
+ "binary_operator": "children",
+ "call": "children",
+ "concatenated_string": "children",
+ "dictionary": "children",
+ "dictionary_comprehension": "children",
+ "ellipsis": "children",
+ "false": "children",
+ "float": "children",
+ "generator_expression": "children",
+ "identifier": "children",
+ "integer": "children",
+ "list": "children",
+ "list_comprehension": "children",
+ "list_splat": "children",
+ "none": "children",
+ "parenthesized_expression": "children",
+ "set": "children",
+ "set_comprehension": "children",
+ "string": "children",
+ "subscript": "children",
+ "true": "children",
+ "tuple": "children",
+ "unary_operator": "children",
+ "parenthesized_list_splat": "children",
+ "yield": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "set_comprehension": {
+ "type": "set_comprehension",
+ "singleFieldNames": ["body"],
+ "nodeTypeToMultipleFieldName": {
+ "for_in_clause": "children",
+ "if_clause": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "slice": {
+ "type": "slice",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "as_pattern": "children",
+ "boolean_operator": "children",
+ "comparison_operator": "children",
+ "conditional_expression": "children",
+ "lambda": "children",
+ "named_expression": "children",
+ "not_operator": "children",
+ "attribute": "children",
+ "await": "children",
+ "binary_operator": "children",
+ "call": "children",
+ "concatenated_string": "children",
+ "dictionary": "children",
+ "dictionary_comprehension": "children",
+ "ellipsis": "children",
+ "false": "children",
+ "float": "children",
+ "generator_expression": "children",
+ "identifier": "children",
+ "integer": "children",
+ "list": "children",
+ "list_comprehension": "children",
+ "list_splat": "children",
+ "none": "children",
+ "parenthesized_expression": "children",
+ "set": "children",
+ "set_comprehension": "children",
+ "string": "children",
+ "subscript": "children",
+ "true": "children",
+ "tuple": "children",
+ "unary_operator": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "splat_pattern": {
+ "type": "splat_pattern",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "identifier": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "splat_type": {
+ "type": "splat_type",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "identifier": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "string": {
+ "type": "string",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "interpolation": "children",
+ "string_content": "children",
+ "string_end": "children",
+ "string_start": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "string_content": {
+ "type": "string_content",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "escape_interpolation": "children",
+ "escape_sequence": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "subscript": {
+ "type": "subscript",
+ "singleFieldNames": ["value"],
+ "nodeTypeToMultipleFieldName": {
+ "as_pattern": "subscript",
+ "boolean_operator": "subscript",
+ "comparison_operator": "subscript",
+ "conditional_expression": "subscript",
+ "lambda": "subscript",
+ "named_expression": "subscript",
+ "not_operator": "subscript",
+ "attribute": "subscript",
+ "await": "subscript",
+ "binary_operator": "subscript",
+ "call": "subscript",
+ "concatenated_string": "subscript",
+ "dictionary": "subscript",
+ "dictionary_comprehension": "subscript",
+ "ellipsis": "subscript",
+ "false": "subscript",
+ "float": "subscript",
+ "generator_expression": "subscript",
+ "identifier": "subscript",
+ "integer": "subscript",
+ "list": "subscript",
+ "list_comprehension": "subscript",
+ "list_splat": "subscript",
+ "none": "subscript",
+ "parenthesized_expression": "subscript",
+ "set": "subscript",
+ "set_comprehension": "subscript",
+ "string": "subscript",
+ "subscript": "subscript",
+ "true": "subscript",
+ "tuple": "subscript",
+ "unary_operator": "subscript",
+ "slice": "subscript"
+ },
+ "multipleOrChildrenFieldNames": ["subscript"]
+ },
+ "try_statement": {
+ "type": "try_statement",
+ "singleFieldNames": ["body"],
+ "nodeTypeToMultipleFieldName": {
+ "else_clause": "children",
+ "except_clause": "children",
+ "except_group_clause": "children",
+ "finally_clause": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "tuple": {
+ "type": "tuple",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "as_pattern": "children",
+ "boolean_operator": "children",
+ "comparison_operator": "children",
+ "conditional_expression": "children",
+ "lambda": "children",
+ "named_expression": "children",
+ "not_operator": "children",
+ "attribute": "children",
+ "await": "children",
+ "binary_operator": "children",
+ "call": "children",
+ "concatenated_string": "children",
+ "dictionary": "children",
+ "dictionary_comprehension": "children",
+ "ellipsis": "children",
+ "false": "children",
+ "float": "children",
+ "generator_expression": "children",
+ "identifier": "children",
+ "integer": "children",
+ "list": "children",
+ "list_comprehension": "children",
+ "list_splat": "children",
+ "none": "children",
+ "parenthesized_expression": "children",
+ "set": "children",
+ "set_comprehension": "children",
+ "string": "children",
+ "subscript": "children",
+ "true": "children",
+ "tuple": "children",
+ "unary_operator": "children",
+ "parenthesized_list_splat": "children",
+ "yield": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "tuple_pattern": {
+ "type": "tuple_pattern",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "case_pattern": "children",
+ "attribute": "children",
+ "identifier": "children",
+ "list_pattern": "children",
+ "list_splat_pattern": "children",
+ "subscript": "children",
+ "tuple_pattern": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "type_alias_statement": {
+ "type": "type_alias_statement",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "type": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "type_parameter": {
+ "type": "type_parameter",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "type": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "typed_default_parameter": {
+ "type": "typed_default_parameter",
+ "singleFieldNames": ["name", "type", "value"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "typed_parameter": {
+ "type": "typed_parameter",
+ "singleFieldNames": ["type"],
+ "nodeTypeToMultipleFieldName": {
+ "dictionary_splat_pattern": "children",
+ "identifier": "children",
+ "list_splat_pattern": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "unary_operator": {
+ "type": "unary_operator",
+ "singleFieldNames": ["argument", "operator"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "union_pattern": {
+ "type": "union_pattern",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "class_pattern": "children",
+ "complex_pattern": "children",
+ "concatenated_string": "children",
+ "dict_pattern": "children",
+ "dotted_name": "children",
+ "false": "children",
+ "float": "children",
+ "integer": "children",
+ "list_pattern": "children",
+ "none": "children",
+ "splat_pattern": "children",
+ "string": "children",
+ "true": "children",
+ "tuple_pattern": "children",
+ "union_pattern": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "union_type": {
+ "type": "union_type",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "type": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "while_statement": {
+ "type": "while_statement",
+ "singleFieldNames": ["alternative", "body", "condition"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "wildcard_import": {
+ "type": "wildcard_import",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "with_clause": {
+ "type": "with_clause",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {
+ "with_item": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "with_item": {
+ "type": "with_item",
+ "singleFieldNames": ["value"],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "with_statement": {
+ "type": "with_statement",
+ "singleFieldNames": ["body"],
+ "nodeTypeToMultipleFieldName": {
+ "with_clause": "children"
+ },
+ "multipleOrChildrenFieldNames": ["children"]
+ },
+ "!=": {
+ "type": "!=",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "%": {
+ "type": "%",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "%=": {
+ "type": "%=",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "&": {
+ "type": "&",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "&=": {
+ "type": "&=",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "*": {
+ "type": "*",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "**": {
+ "type": "**",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "**=": {
+ "type": "**=",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "*=": {
+ "type": "*=",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "+": {
+ "type": "+",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "+=": {
+ "type": "+=",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "-": {
+ "type": "-",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "-=": {
+ "type": "-=",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "/": {
+ "type": "/",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "//": {
+ "type": "//",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "//=": {
+ "type": "//=",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "/=": {
+ "type": "/=",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "<": {
+ "type": "<",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "<<": {
+ "type": "<<",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "<<=": {
+ "type": "<<=",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "<=": {
+ "type": "<=",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "<>": {
+ "type": "<>",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "==": {
+ "type": "==",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ ">": {
+ "type": ">",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ ">=": {
+ "type": ">=",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ ">>": {
+ "type": ">>",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ ">>=": {
+ "type": ">>=",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "@": {
+ "type": "@",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "@=": {
+ "type": "@=",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "^": {
+ "type": "^",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "^=": {
+ "type": "^=",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "_": {
+ "type": "_",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "and": {
+ "type": "and",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "ellipsis": {
+ "type": "ellipsis",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "escape_interpolation": {
+ "type": "escape_interpolation",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "escape_sequence": {
+ "type": "escape_sequence",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "false": {
+ "type": "false",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "float": {
+ "type": "float",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "identifier": {
+ "type": "identifier",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "in": {
+ "type": "in",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "integer": {
+ "type": "integer",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "is": {
+ "type": "is",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "is not": {
+ "type": "is not",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "line_continuation": {
+ "type": "line_continuation",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "none": {
+ "type": "none",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "not in": {
+ "type": "not in",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "or": {
+ "type": "or",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "string_end": {
+ "type": "string_end",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "string_start": {
+ "type": "string_start",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "true": {
+ "type": "true",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "type_conversion": {
+ "type": "type_conversion",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "|": {
+ "type": "|",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "|=": {
+ "type": "|=",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ },
+ "~": {
+ "type": "~",
+ "singleFieldNames": [],
+ "nodeTypeToMultipleFieldName": {},
+ "multipleOrChildrenFieldNames": []
+ }
+}
diff --git a/packages/tree-sitter-port/output/tree-sitter-python/meta.json b/packages/tree-sitter-port/output/tree-sitter-python/meta.json
new file mode 100644
index 0000000..82f0b62
--- /dev/null
+++ b/packages/tree-sitter-port/output/tree-sitter-python/meta.json
@@ -0,0 +1,5 @@
+{
+ "name": "tree-sitter-python",
+ "version": "0.21.0",
+ "generatedAt": "2024-06-26T15:41:11.470Z"
+}
diff --git a/packages/tree-sitter-port/output/tree-sitter-python/parser.wasm b/packages/tree-sitter-port/output/tree-sitter-python/parser.wasm
new file mode 100755
index 0000000..132a88c
Binary files /dev/null and b/packages/tree-sitter-port/output/tree-sitter-python/parser.wasm differ
diff --git a/packages/tree-sitter-port/package.json b/packages/tree-sitter-port/package.json
new file mode 100644
index 0000000..237c5e7
--- /dev/null
+++ b/packages/tree-sitter-port/package.json
@@ -0,0 +1,32 @@
+{
+ "name": "@codeque/tree-sitter-port",
+ "description": "Multiline code search for every language. Structural code search for JavaScript, TypeScript, HTML and CSS",
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/codeque-co/codeque"
+ },
+ "bugs": {
+ "url": "https://github.com/codeque-co/codeque/issues"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "version": "0.1.0",
+ "scripts": {
+ "parsers-upgrade": "ts-node ./src/upgradeParsers.ts",
+ "build-wasm-and-generate-mappings": "ts-node ./src/buildWasmAndGenerateMappings.ts",
+ "copy-files": "ts-node ./src/copyFiles.ts",
+ "lint": "eslint src --ext ts && eslint output --ext json",
+ "test": "echo 0",
+ "typecheck": "tsc --project tsconfig.json --noEmit"
+ },
+ "devDependencies": {
+ "@codeque/core": "^0.6.0",
+ "@types/node": "16.x",
+ "eslint": "^8.18.0",
+ "tree-sitter-cli": "^0.20.8",
+ "ts-node": "^10.9.1",
+ "typescript": "5.9.3"
+ },
+ "dependencies": {}
+}
diff --git a/packages/tree-sitter-port/src/buildWasmAndGenerateMappings.ts b/packages/tree-sitter-port/src/buildWasmAndGenerateMappings.ts
new file mode 100644
index 0000000..1b9ac05
--- /dev/null
+++ b/packages/tree-sitter-port/src/buildWasmAndGenerateMappings.ts
@@ -0,0 +1,91 @@
+import { parsersSettings, inputDirPath, outputDirPath } from './settings'
+import { execSync } from 'child_process'
+import path from 'path'
+import { logger as log } from './log'
+
+import fs from 'fs'
+import { prepareNodeTypes } from './prepareNodeTypes'
+
+const userSelectedParsers = process.argv.slice(2)
+
+const selectedParsers =
+ userSelectedParsers.length > 0
+ ? parsersSettings.filter(({ parserType, parserName }) => {
+ return (
+ userSelectedParsers.includes(parserType) ||
+ userSelectedParsers.includes(parserName)
+ )
+ })
+ : parsersSettings
+
+for (const parserSettings of selectedParsers) {
+ const parserLogName = `${parserSettings.parserType} (${parserSettings.parserName})`
+ const localLogger = log.info('Generating for ' + parserLogName)
+
+ try {
+ const parserInputsDir = path.join(inputDirPath, parserSettings.parserName)
+
+ const parserOutputsDir = path.join(outputDirPath, parserSettings.parserName)
+
+ execSync(`rm -rf ${parserOutputsDir}`)
+
+ execSync(`mkdir ${parserOutputsDir}`)
+
+ const packageJson = JSON.parse(
+ fs.readFileSync(path.join(parserInputsDir, 'package.json')).toString(),
+ )
+
+ fs.writeFileSync(
+ path.join(parserOutputsDir, 'meta.json'),
+ JSON.stringify(
+ {
+ name: parserSettings.parserName,
+ version: packageJson.version,
+ generatedAt: new Date(),
+ },
+ null,
+ 2,
+ ) + '\n',
+ )
+
+ execSync(`npx tree-sitter build-wasm ${parserInputsDir}`)
+
+ const parserGeneratedFileName = `tree-sitter-${parserSettings.parserName
+ .replace('tree-sitter-', '')
+ .replace(/-/g, '_')}.wasm`
+
+ execSync(
+ `mv ${parserGeneratedFileName} ${path.join(
+ parserOutputsDir,
+ 'parser.wasm',
+ )}`,
+ )
+
+ localLogger.success('Wasm file generated')
+
+ const typesGroupedByFiledType = prepareNodeTypes({
+ nodeTypesToIgnore: parserSettings.nodeTypesToIgnore,
+ nodeTypesFilePath: path.join(
+ parserInputsDir,
+ parserSettings.nodeTypesLocation,
+ ),
+ conflictResolvers: parserSettings.conflictResolvers,
+ log: localLogger.info,
+ })
+
+ fs.writeFileSync(
+ path.join(parserOutputsDir, './fields-meta.json'),
+ JSON.stringify(typesGroupedByFiledType, null, 2) + '\n',
+ )
+
+ localLogger.success('fields meta file generated')
+ } catch (e: unknown) {
+ localLogger.error((e as Error)?.message)
+ }
+}
+
+const nestedLogger = log.info('Linting files...')
+
+execSync(`yarn lint --fix`)
+
+nestedLogger.success('Done')
diff --git a/packages/tree-sitter-port/src/copyFiles.ts b/packages/tree-sitter-port/src/copyFiles.ts
new file mode 100644
index 0000000..939ad1f
--- /dev/null
+++ b/packages/tree-sitter-port/src/copyFiles.ts
@@ -0,0 +1,54 @@
+import { parsersSettings, inputDirPath, outputDirPath } from './settings'
+import { execSync } from 'child_process'
+import path from 'path'
+import { logger as log } from './log'
+import { ParserType } from '@codeque/core'
+
+const parsersToCopy: Array = ['python', 'lua', 'csharp']
+
+const filteredParserSettings = parsersSettings.filter(({ parserType }) =>
+ parsersToCopy.includes(parserType),
+)
+
+execSync(`rm -rf ../core/dist-tree-sitter`)
+execSync(`rm -rf ../vscode/dist-tree-sitter`)
+
+execSync(`mkdir ../core/dist-tree-sitter`)
+execSync(`mkdir ../vscode/dist-tree-sitter`)
+
+execSync(
+ `cp ../../node_modules/web-tree-sitter/tree-sitter.wasm ../core/dist-tree-sitter/tree-sitter.wasm`,
+)
+
+execSync(
+ `cp ../../node_modules/web-tree-sitter/tree-sitter.wasm ../vscode/dist-tree-sitter/tree-sitter.wasm`,
+)
+
+log.success('Prepared directories and copied tree-sitter.wasm')
+
+for (const parserSettings of filteredParserSettings) {
+ const parserLogName = `${parserSettings.parserType} (${parserSettings.parserName})`
+ const localLogger = log.info('Copying ' + parserLogName + ' parser')
+ const outputDir = path.join(outputDirPath, parserSettings.parserName)
+
+ const coreDirName = path.join(
+ process.cwd(),
+ '../core/dist-tree-sitter',
+ parserSettings.parserName,
+ )
+ const vscodeDirName = path.join(
+ process.cwd(),
+ '../vscode/dist-tree-sitter',
+ parserSettings.parserName,
+ )
+
+ try {
+ execSync(`cp -r ${outputDir} ${coreDirName}`)
+
+ execSync(`cp -r ${outputDir} ${vscodeDirName}`)
+
+ localLogger.success('Copied ' + parserLogName + ' parser')
+ } catch (e: unknown) {
+ localLogger.error((e as Error).message)
+ }
+}
diff --git a/packages/tree-sitter-port/src/log.ts b/packages/tree-sitter-port/src/log.ts
new file mode 100644
index 0000000..c34f7c0
--- /dev/null
+++ b/packages/tree-sitter-port/src/log.ts
@@ -0,0 +1,31 @@
+const info = (msg: string, prefix = '') => {
+ process.stdout.write(prefix + 'ℹ️ ' + msg + '\n')
+}
+
+const success = (msg: string, prefix = '') => {
+ process.stdout.write(prefix + '✅ ' + msg + '\n')
+}
+
+const error = (msg: string, prefix = '') => {
+ process.stdout.write(prefix + '❌ ' + msg + '\n')
+}
+
+const createLogger = (prefix: string) => ({
+ info: (msg: string) => {
+ info(`${prefix}${msg}`, prefix)
+
+ return createLogger(' ')
+ },
+ success: (msg: string) => {
+ success(`${prefix}${msg}`, prefix)
+
+ return createLogger(' ')
+ },
+ error: (msg: string) => {
+ error(`${prefix}${msg}`, prefix)
+
+ return createLogger(' ')
+ },
+})
+
+export const logger = createLogger('')
diff --git a/packages/tree-sitter-port/src/prepareNodeTypes.ts b/packages/tree-sitter-port/src/prepareNodeTypes.ts
new file mode 100644
index 0000000..781e21f
--- /dev/null
+++ b/packages/tree-sitter-port/src/prepareNodeTypes.ts
@@ -0,0 +1,297 @@
+const fs = require('fs')
+
+type NodeTypes = Array<{
+ type: string
+ named: boolean
+ fields?: Record<
+ string,
+ {
+ multiple: boolean
+ required: boolean
+ types: Array<{
+ type: string
+ named: boolean
+ }>
+ }
+ >
+ children?: {
+ multiple: boolean
+ required: boolean
+ types: Array<{
+ type: string
+ named: boolean
+ }>
+ }
+
+ subtypes?: Array<{
+ type: string
+ named: boolean
+ }>
+}>
+
+type FieldsMeta = {
+ type: string
+ singleFieldNames: string[]
+ nodeTypeToMultipleFieldName: Record
+ multipleOrChildrenFieldNames: string[]
+}
+
+export type ConflictResolver = {
+ nodeType: string
+ fields: [string, string]
+ mergeToField: string
+}
+
+export const prepareNodeTypes = ({
+ nodeTypesToIgnore,
+ nodeTypesFilePath,
+ conflictResolvers = [],
+ log,
+}: {
+ nodeTypesToIgnore: string[]
+ nodeTypesFilePath: string
+ conflictResolvers?: Array
+ log: (msg: string) => void
+}) => {
+ const nodeTypes: NodeTypes = JSON.parse(
+ fs.readFileSync(nodeTypesFilePath).toString(),
+ )
+
+ const types: Record<
+ string,
+ {
+ named: boolean
+ type: string
+ fieldsMeta: null | Record<
+ string,
+ {
+ multipleOrChildren: boolean
+ nodeTypes: string[]
+ }
+ >
+ }
+ > = {}
+
+ /**
+ * Not named types are usually some keywords or language constants.
+ * We don't care about them unless they two or more of not named types can occur in the same place in tree.
+ * We capture that when processing nested node types and filter out all Not named except those relevant.
+ */
+ const notNamedNodeTypesToInclude: string[] = []
+
+ const nodeTypesWithSubTypes = nodeTypes.filter(({ subtypes }) => subtypes)
+
+ const subTypesMap = Object.fromEntries(
+ nodeTypesWithSubTypes.map(({ type, subtypes }) => [
+ type,
+ subtypes?.map(({ type }) => type),
+ ]),
+ )
+
+ /**
+ * Some subtypes are nested, hence recursion
+ * */
+ const extrapolateBySubtype = (nodeType: string): string[] =>
+ subTypesMap[nodeType]
+ ? subTypesMap[nodeType]?.map(extrapolateBySubtype)?.flat() ?? []
+ : [nodeType]
+
+ nodeTypes.forEach((nodeType) => {
+ const fieldsRaw = nodeType.fields ?? {}
+
+ if (nodeType.children) {
+ fieldsRaw.children = nodeType.children
+ }
+
+ const fieldsMeta = fieldsRaw
+ ? Object.fromEntries(
+ Object.entries(fieldsRaw).map(([fieldName, value]) => {
+ const notNamedNodeTypesInField = value.types
+ .filter(({ named }) => !named)
+ .map(({ type }) => type)
+ notNamedNodeTypesToInclude.push(...notNamedNodeTypesInField)
+
+ return [
+ fieldName,
+ {
+ multipleOrChildren: value.multiple || fieldName === 'children',
+ /*
+ * Some types are just aliases for types group, eg. "expression" can be "boolean_operator" "primary_expression" and others
+ * Some subtypes are nested so we do recursion, hence we have to flat.
+ */
+ nodeTypes: value.types
+ .map(({ type }) => extrapolateBySubtype(type))
+ .flat(1),
+ },
+ ]
+ }),
+ )
+ : null
+
+ if (fieldsMeta) {
+ const entries = Object.entries(fieldsMeta)
+
+ const multipleOrChildren = entries.filter(
+ ([, value]) => value.multipleOrChildren,
+ )
+ let conflict: {
+ nodeType: string
+ fieldNameA: string
+ fieldNameB: string
+ conflictingNodeType: string
+ nodeTypesFilePath: string
+ } | null = null
+
+ if (multipleOrChildren.length > 1) {
+ for (let a = 0; a < multipleOrChildren.length && !conflict; a++) {
+ for (let b = a + 1; b < multipleOrChildren.length && !conflict; b++) {
+ const fieldNameA = multipleOrChildren[a][0]
+ const fieldNameB = multipleOrChildren[b][0]
+
+ const typesA = multipleOrChildren[a][1].nodeTypes
+ const typesB = multipleOrChildren[b][1].nodeTypes
+
+ const hasConflict = typesA.some((typeA) => typesB.includes(typeA))
+
+ if (hasConflict) {
+ let conflictingNodeType = null
+
+ for (let i = 0; i < typesA.length && !conflictingNodeType; i++) {
+ const typeAIndex = typesB.indexOf(typesA[i])
+
+ if (typeAIndex > -1) {
+ conflictingNodeType = typesA[i]
+ }
+ }
+
+ if (
+ conflictingNodeType &&
+ !nodeTypesToIgnore.includes(conflictingNodeType)
+ ) {
+ /*
+ * Conflict is when two or more fields with multiple children can have node of the same type within.
+ * In this case we won't be able to properly assign nodes by type to given named field.
+ * If conflict would occur for other parsers, we should put all node types from conflicting fields into common "children" field, as we cannot do anything better in this case.
+ *
+ * We don't care about conflicts between ignored node types, as they will not be processed anyway
+ */
+ conflict = {
+ nodeType: nodeType.type,
+ fieldNameA,
+ fieldNameB,
+ conflictingNodeType,
+ nodeTypesFilePath,
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (conflict !== null) {
+ const conflictObj = conflict // TS is freaking out
+
+ const conflictJsonString = JSON.stringify(conflictObj, null, 2)
+ const resolver = conflictResolvers.find(({ fields, nodeType }) => {
+ return (
+ fields.includes(conflictObj.fieldNameA) &&
+ fields.includes(conflictObj.fieldNameB) &&
+ nodeType === conflictObj.nodeType
+ )
+ })
+
+ if (resolver) {
+ const mergeSourceFieldName = [
+ conflictObj.fieldNameA,
+ conflictObj.fieldNameB,
+ ].filter((fieldName) => fieldName !== resolver.mergeToField)[0]
+
+ fieldsMeta[resolver.mergeToField].nodeTypes = uniq([
+ ...fieldsMeta[resolver.mergeToField].nodeTypes,
+ ...fieldsMeta[mergeSourceFieldName].nodeTypes,
+ ])
+
+ delete fieldsMeta[mergeSourceFieldName]
+
+ log('Resolved conflict ' + conflictJsonString)
+ } else {
+ throw new Error('Node types conflict: ' + conflictJsonString)
+ }
+ }
+ }
+
+ const data = {
+ named: nodeType.named,
+ type: nodeType.type,
+ fieldsMeta,
+ }
+
+ types[nodeType.type] = data
+ })
+
+ const uniqueNotNamedNodeTypesToInclude = new Set(notNamedNodeTypesToInclude)
+
+ const typesEntriesWithoutSomeNotNamed = Object.entries(types).filter(
+ ([, { named, type }]) =>
+ (named || uniqueNotNamedNodeTypesToInclude.has(type)) &&
+ !subTypesMap[type],
+ )
+
+ const typesEntriesWithoutSomeNotNamedAndIgnoredTypes: typeof typesEntriesWithoutSomeNotNamed =
+ typesEntriesWithoutSomeNotNamed.filter(
+ ([, { named, type }]) => !nodeTypesToIgnore.includes(type),
+ )
+
+ const typesEntriesGroupedByFiledType: Array<[string, FieldsMeta]> =
+ typesEntriesWithoutSomeNotNamedAndIgnoredTypes.map(
+ ([nodeType, nodeData]) => {
+ if (nodeData.fieldsMeta === null) {
+ return [
+ nodeType,
+ {
+ type: nodeData.type,
+ singleFieldNames: [],
+ nodeTypeToMultipleFieldName: {},
+ multipleOrChildrenFieldNames: [],
+ },
+ ]
+ }
+
+ const fieldsMetaEntries = Object.entries(nodeData.fieldsMeta)
+ const multipleOrChildrenFieldEntries = fieldsMetaEntries.filter(
+ ([, fieldMeta]) => fieldMeta.multipleOrChildren,
+ )
+
+ const nodeTypeToMultipleFieldNameEntries =
+ multipleOrChildrenFieldEntries
+ .map(([fieldName, { nodeTypes }]) =>
+ nodeTypes.map((nodeType) => [nodeType, fieldName]),
+ )
+ .flat(1)
+
+ return [
+ nodeType,
+ {
+ type: nodeData.type,
+ singleFieldNames: fieldsMetaEntries
+ .filter(([, fieldMeta]) => !fieldMeta.multipleOrChildren)
+ .map(([fieldName]) => fieldName),
+ nodeTypeToMultipleFieldName: Object.fromEntries(
+ nodeTypeToMultipleFieldNameEntries,
+ ),
+ multipleOrChildrenFieldNames: multipleOrChildrenFieldEntries.map(
+ ([fieldName]) => fieldName,
+ ),
+ },
+ ]
+ },
+ )
+
+ const typesGroupedByFiledType = Object.fromEntries(
+ typesEntriesGroupedByFiledType,
+ )
+
+ return typesGroupedByFiledType
+}
+
+const uniq = (arr: T[]) => [...new Set(arr)]
diff --git a/packages/tree-sitter-port/src/settings.ts b/packages/tree-sitter-port/src/settings.ts
new file mode 100644
index 0000000..a500e30
--- /dev/null
+++ b/packages/tree-sitter-port/src/settings.ts
@@ -0,0 +1,76 @@
+import { ParserType } from '@codeque/core'
+
+import path from 'path'
+import { ConflictResolver } from './prepareNodeTypes'
+type ParserSettings = {
+ parserType: ParserType
+ parserName: string
+ repoUrl: string
+ nodeTypesLocation: string
+ buildWasmCommand: string
+ nodeTypesToIgnore: string[]
+ conflictResolvers?: ConflictResolver[]
+}
+
+export const inputDirPath = path.join(process.cwd(), 'input')
+export const outputDirPath = path.join(process.cwd(), 'output')
+
+const getWasmBuildCommand = (treeSitterDirName: string) =>
+ `npx tree-sitter build-wasm ${path.join(inputDirPath, treeSitterDirName)}`
+
+export const parsersSettings: ParserSettings[] = [
+ {
+ parserType: 'python',
+ parserName: 'tree-sitter-python',
+ repoUrl: 'https://github.com/tree-sitter/tree-sitter-python.git',
+ nodeTypesLocation: 'src/node-types.json',
+ buildWasmCommand: getWasmBuildCommand('tree-sitter-python'),
+ nodeTypesToIgnore: [',', 'comment'],
+ conflictResolvers: [
+ {
+ nodeType: 'dict_pattern',
+ fields: ['key', 'children'],
+ mergeToField: 'children',
+ },
+ ],
+ },
+ {
+ parserType: 'babel', // temporary for test
+ parserName: 'tree-sitter-c',
+ repoUrl: 'https://github.com/tree-sitter/tree-sitter-c.git',
+ nodeTypesLocation: 'src/node-types.json',
+ buildWasmCommand: getWasmBuildCommand('tree-sitter-c'),
+ nodeTypesToIgnore: [],
+ },
+ {
+ parserType: 'csharp',
+ parserName: 'tree-sitter-c-sharp',
+ repoUrl: 'https://github.com/tree-sitter/tree-sitter-c-sharp.git',
+ nodeTypesLocation: 'src/node-types.json',
+ buildWasmCommand: getWasmBuildCommand('tree-sitter-c-sharp'),
+ nodeTypesToIgnore: [','],
+ },
+ {
+ parserType: 'lua', // temporary for test
+ parserName: 'tree-sitter-lua',
+ repoUrl: 'https://github.com/MunifTanjim/tree-sitter-lua.git',
+ nodeTypesLocation: 'src/node-types.json',
+ buildWasmCommand: getWasmBuildCommand('tree-sitter-lua'),
+ nodeTypesToIgnore: ["'", '"'],
+ conflictResolvers: [
+ {
+ nodeType: 'expression_list',
+ fields: ['value', 'children'],
+ mergeToField: 'children',
+ },
+ ],
+ },
+ {
+ parserType: 'babel', // temporary for test
+ parserName: 'tree-sitter-php',
+ repoUrl: 'https://github.com/tree-sitter/tree-sitter-php.git',
+ nodeTypesLocation: 'src/node-types.json',
+ buildWasmCommand: getWasmBuildCommand('tree-sitter-php'),
+ nodeTypesToIgnore: [],
+ },
+]
diff --git a/packages/tree-sitter-port/src/upgradeParsers.ts b/packages/tree-sitter-port/src/upgradeParsers.ts
new file mode 100644
index 0000000..a52c5a7
--- /dev/null
+++ b/packages/tree-sitter-port/src/upgradeParsers.ts
@@ -0,0 +1,37 @@
+import { parsersSettings, inputDirPath } from './settings'
+import { execSync } from 'child_process'
+import path from 'path'
+import { logger as log } from './log'
+
+const userSelectedParsers = process.argv.slice(2)
+
+const selectedParsers =
+ userSelectedParsers.length > 0
+ ? parsersSettings.filter(({ parserType, parserName }) => {
+ return (
+ userSelectedParsers.includes(parserType) ||
+ userSelectedParsers.includes(parserName)
+ )
+ })
+ : parsersSettings
+
+for (const parserSettings of selectedParsers) {
+ const parserLogName = `${parserSettings.parserType} (${parserSettings.parserName})`
+ const localLogger = log.info('Fetching ' + parserLogName + ' parser')
+ try {
+ const parserDir = path.join(inputDirPath, parserSettings.parserName)
+
+ execSync(`rm -rf ${parserDir}`)
+
+ execSync(
+ `git clone ${parserSettings.repoUrl} ${path.join(
+ inputDirPath,
+ parserSettings.parserName,
+ )}`,
+ )
+
+ localLogger.success('Fetched ' + parserLogName + ' parser')
+ } catch (e: unknown) {
+ localLogger.error((e as Error).message)
+ }
+}
diff --git a/packages/tree-sitter-port/tsconfig.json b/packages/tree-sitter-port/tsconfig.json
new file mode 100644
index 0000000..10c6e50
--- /dev/null
+++ b/packages/tree-sitter-port/tsconfig.json
@@ -0,0 +1,9 @@
+{
+ "extends": "../../tsconfig.json",
+ "compilerOptions": {
+ "baseUrl": "./src",
+ "skipLibCheck": true,
+ "declaration": false
+ },
+ "exclude": ["dist", "node_modules", "output", "input"]
+}
diff --git a/packages/vscode/.gitignore b/packages/vscode/.gitignore
index 41bcfe0..cdbfa64 100644
--- a/packages/vscode/.gitignore
+++ b/packages/vscode/.gitignore
@@ -1,2 +1,4 @@
dist-webviews
-*.vsix
\ No newline at end of file
+*.vsix
+builds
+tsconfig.tsbuildinfo
\ No newline at end of file
diff --git a/packages/vscode/CHANGELOG.md b/packages/vscode/CHANGELOG.md
deleted file mode 100644
index e593e9d..0000000
--- a/packages/vscode/CHANGELOG.md
+++ /dev/null
@@ -1,9 +0,0 @@
-# Change Log
-
-All notable changes to the "codeque" extension will be documented in this file.
-
-Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file.
-
-## [Unreleased]
-
-- Initial release
\ No newline at end of file
diff --git a/packages/vscode/InternalReadme.md b/packages/vscode/InternalReadme.md
index d201b54..7a06c88 100644
--- a/packages/vscode/InternalReadme.md
+++ b/packages/vscode/InternalReadme.md
@@ -1,5 +1,7 @@
## Development
+Make sure to build core package first `yarn workspace @codeque/core build`
+
Run `yarn watch:extension` and `yarn watch:webviews`
Open Vscode and run `Run extension` configuration in debugger
@@ -8,14 +10,35 @@ While in VSCode with extension host run `> Reload Extension` to refresh webview
To refresh extension backed re-run debugger configuration.
-## Publish
+## Testing production build locally
+Make sure to build core package first `yarn workspace @codeque/core build`
+
+Then change version in package.json to include `-local` suffix, eg. `0.35.1-local`.
+
+Otherwise vscode will confuse locally installed version and you won't be able to download published version with the same version code, unless you uninstall local version manually
+
+Package the extension into vsix file `cd packages/vscode && vsce package`
+
+Command runs checks, run webpack build and package extension into `vsix` (kind of archive file)
+
+You will get file `codeque-.vsix`
+
+The install extension from command pallette in vscode `cmd+p` -> `install from VSIX` -> select generated file -> Hit "Restart Extensions" button
+
+## Publish to official Visual Studio Code Marketplace
Bump version manually in package.json
And just run
-`vsce publish`
+`vsce publish -p `
`vsce` will automatically run pre-publish hooks from script `vscode:prepublish` to run checks and build package
-You might be asked to [get new PAT](https://code.visualstudio.com/api/working-with-extensions/publishing-extension#get-a-personal-access-token)
\ No newline at end of file
+You might be asked to [get new PAT](https://code.visualstudio.com/api/working-with-extensions/publishing-extension#get-a-personal-access-token)
+
+## Publish to Open VSX registry
+
+Same procedure as above, but run
+
+`ovsx publish -p `
diff --git a/packages/vscode/README.md b/packages/vscode/README.md
index 9e9010a..77078ef 100644
--- a/packages/vscode/README.md
+++ b/packages/vscode/README.md
@@ -1,57 +1,104 @@
+
+
+
+
+
+
+
+
-
-
+
+
- Home Page |
- Docs |
- Roadmap |
- Mission |
- Playground
+ Website •
+ Docs •
+ Roadmap •
+ Mission •
+ Playground
-# CodeQue - Multiline Structural Search for Visual Studio Code
+Find and lint complex code patterns effortlessly
-CodeQue is code search engine that understands the code syntax.
+---
-It matches structure rather than plain text, which makes it very effective for complex queries.
+# What is CodeQue?
-VSCode extension aims to improve code search and navigation experience.
+CodeQue is semantic code search engine that understands the code syntax.
-Advanced search options and todo-like list of accurate search results makes it your new super power.
+It matches code structurally which makes it excellent for more complex queries.
-It's one of the tools in the ecosystem. There is also [CLI tool](https://www.npmjs.com/package/@codeque/cli) and [ESLint plugin](https://www.npmjs.com/package/@codeque/eslint-plugin) for creating custom rules in zero time.
+Query language offers wildcards, partial matching and ignores code formatting.
-CodeQue supports multiline search for any programming language and structural search for JavaScript and TypeScript.
+Structural code search is available for JavaScript, TypesScript, HTML, CSS, Python, Lua, C# and more soon.
-Structural search support for other programming languages will be added soon.
+Text code search with handy wildcards is available for **every language** and covers common regex search use cases.
-
+Give it a try in
+ playground
-Watch extension in action (external link) 👇
+Just paste code snippet to start searching, no installation needed!
-
-
-
+**Integrations**
+
+CodeQue is available as:
+
+- [VSCode extension](https://marketplace.visualstudio.com/items?itemName=CodeQue.codeque) for delightful code search and navigation experience.
+- [ESLint integration](https://www.npmjs.com/package/@codeque/eslint-plugin) for creating custom linting rules in zero time.
+- [CLI tool](https://www.npmjs.com/package/@codeque/cli) for searching code and more including headless environments.
+
+All CodeQue tools work offline hence code never leaves your local environment.
+
+**Coming soon**
+
+CodeQue will be soon available as:
-## Benefits of using CodeQue VSCode extension
+- Duplicated code identification
+- Batch code refactoring
+- Advanced ESLint rule creator
-CodeQue is more than just a search tool - it's a refactoring tool as well.
+🔔 Get notified about updates 🔔
-It addresses the problems of standard search by providing multiline support and an easy way to add gaps or use wildcards into the query.
+
-You don't need to have any knowledge of Regular Expressions to query complex code patterns.
+
-It helps developers with code refactoring, speeds up project discovery, and makes it easy to find duplicated or similar code. patterns.
+
+
+## Visual Studio Code Extension 🔮
+
+VScode extension aims to make your workflow more efficient.
+
+It addresses the problems of standard search by providing multiline support and offers an easy way to add gaps or use wildcards in the query.
+
+You don't need to have any Regex knowledge to query complex code patterns.
With CodeQue, you can easily navigate and modify your codebase, making your development process faster and more efficient.
-## Overview
+It will help you with code refactoring, speed up project discovery, and make it easy to find duplicated or similar code patterns.
+
+Advanced code search options and todo-like list of accurate search results will streamline your workflow.
+
+
+
+Watch extension in action in 1 minute (external link) 👇
+
+
+
+
+
+
+
+
+
+## About
+
One of the main strengths of CodeQue is its easy-to-use query language, but it also offers several additional features that make it a great support tool for your daily work.
**Features**
+
- [Query language](#query-language)
- [Search modes](#search-modes)
- [Searching by file imports](#searching-by-file-imports)
@@ -62,6 +109,7 @@ One of the main strengths of CodeQue is its easy-to-use query language, but it a
- [Search errors](#search-errors)
**Example Queries**
+
- [All usages of `console` object](#all-usages-of-console-object)
- [Object with given key and value](#object-with-given-key-and-value)
- [React component with specific props combination](#react-component-with-specific-props-combination)
@@ -75,7 +123,7 @@ One of the main strengths of CodeQue is its easy-to-use query language, but it a
### Query language
The beauty of CodeQue query language is that the query has to be valid source code.
-You don't have to learn anything new!
+You don't have to learn anything new!
Except the fact there are a few types of wildcards.
@@ -85,7 +133,7 @@ It matches all identifiers, JSX identifiers, types identifiers, function names a
`$$$` is an statement/expression wildcard.
-It matches any statement or expression. Think of it as 'match anything'.
+It matches any statement or expression. Think of it as 'match anything'.
There a few quirks there. It's good to have general understanding of how code is represented in AST (Abstract Syntax Tree) for more complex queries.
More technically `$$$` wildcard is matching any node with all it's children.
@@ -100,7 +148,7 @@ Strings have their's own wildcards
#### Number wildcard
-`0x0`- matches any number
+`0x0`- matches any number
Here is an example of query which finds all types of logs which includes word `test` in parameter 👇
@@ -111,6 +159,7 @@ Here is an example of query which finds all types of logs which includes word `t
### Search modes
CodeQue offers the following search modes
+
- include
- text
- exact
@@ -118,13 +167,13 @@ CodeQue offers the following search modes
-The most useful mode is `include`. As the name suggest the matched code has to include the code from query, but it can also contain other statements. It performs structural comparison.
+The most useful mode is `include`. As the name suggest the matched code has to include the code from query, but it can also contain other statements. It performs structural comparison.
[Learn more about `include` search mode](https://codeque.co/docs#include-search-mode)
-`text` search mode is good replacement of build-in vscode search. It acts like a normal text search, but it's big advantage is that it allows for matching multiline statements. It also offers it's own types of wildcards.
+`text` search mode is good replacement of build-in vscode search. It acts like a normal text search, but it's big advantage is that it allows for matching multiline statements. It also offers it's own types of wildcards.
[Learn more about `text` search mode](https://codeque.co/docs#include-search-mode)
@@ -136,13 +185,13 @@ Sometimes you might want to find the code that matches exactly your query. Here
-Last but not least, `include-with-order` search mode can be useful in some rare cases. Same like `include` mode it matches code structurally and allows for missing parts, but in addition, it require the order to match.
+Last but not least, `include-with-order` search mode can be useful in some rare cases. Same like `include` mode it matches code structurally and allows for missing parts, but in addition, it require the order to match.
[Learn more about `include-with-order` search mode](https://codeque.co/docs#include-w-ith-order-search-mode)
-Here is the example of `include` mode matching function body containing statements from query 👇
+Here is the example of `include` mode matching function body containing statements from query 👇
@@ -183,6 +232,7 @@ You can define glob patters to either include or exclude files from the list.
By default CodeQue is not searching in files ignored by `.gitignore`
Enable the following flags with caution, as they might significantly downgrade search performance for lager projects.
+
- Search ignored files
- Search `node_modules` (for most projects to search node_modules you have to also enable searching by ignored files)
- Search files above 100kb (these are usually bundled files which are structurally heavy due to their size and amount of information)
@@ -195,7 +245,7 @@ Example files list settings 👇
### Case sensitivity
-You can choose whether to compare identifier persisting their original case or do case insensitive match.
+You can choose whether to compare identifier persisting their original case or do case insensitive match.
### Search errors
@@ -207,7 +257,7 @@ You can check search error details in tooltip available after click the error co
## Query examples
-CodeQue is general purpose search tool. The examples list could be endless. Here are some of them for you to get a glimpse of what's possible. Those are relatively simple, you definitely would find some more complex during day to day work.
+CodeQue is general purpose code search tool. The examples list could be endless. Here are some of them for you to get a glimpse of what's possible. Those are relatively simple, you will definitely find some more complex during day to day work.
> Don't know how to write a query? [Open an issue on GitHub](https://github.com/codeque-co/codeque/issues) !
@@ -225,17 +275,18 @@ console.$$()
CodeQue ability to match parts of the objects might be very useful, especially for searching patterns in large JSONs.
-This query will match part of an object literal in file or JSON (depending on file extension) regardless of how deeply nested the object is in the structure.
+This query will match part of an object literal in file or JSON (depending on file extension) regardless of how deeply nested the object is in the structure.
More specifically it will match all objects with at least one address entry with country specified to `PL` and phone number which is non empty string.
-
```ts
-({
- addresses: [{
- country: 'PL'
- }],
- phoneNumber: "$$$"
+;({
+ addresses: [
+ {
+ country: 'PL',
+ },
+ ],
+ phoneNumber: '$$$',
})
```
@@ -243,14 +294,10 @@ More specifically it will match all objects with at least one address entry with
### React component with specific props combination
-I found it very useful to find props with specific props combination. Sometimes props depends on each other and we might want to refactor some of them, but how do we determine whether they are used together? We can review long list of results for basic search, but who has time for that 😉
+I found it very useful to find props with specific props combination. Sometimes props depends on each other and we might want to refactor some of them, but how do we determine whether they are used together? We can review long list of results for basic code search, but who has time for that 😉
```tsx
-
+
```
### React bad patterns
@@ -260,9 +307,7 @@ This quite simple query highlights usage of object literal as a prop. It could b
Assuming we use `include` mode, the object can have 0 or more properties with any values.
```tsx
-<$$
- $$={{}}
-/>
+<$$ $$={{}} />
```
This query finds places where a given array is mapped directly in JSX. It could be memoized to make the array reference stable and reduce re-renders.
@@ -270,27 +315,18 @@ This query finds places where a given array is mapped directly in JSX. It could
> In `include` search mode query `<$$/>` will match components with and without children!
```tsx
-<$$
- $$={
- $$$.map(() => ($$$))
- }
-/>
+<$$ $$={$$$.map(() => $$$)} />
```
One last example is another variation of the above, this time with inline function that should be memoized using `useCallback` hook.
-> Note that we used `() => $$$`, not `() => {}`.
-Triple wildcard will match both function body as a block, but also as an expression.
+> Note that we used `() => $$$`, not `() => {}`.
+> Triple wildcard will match both function body as a block, but also as an expression.
```tsx
-<$$
- $$={
- () => $$$
- }
-/>
+<$$ $$={() => $$$} />
```
-
### Conditionally set parameter of a function
This query was posted by one of CodeQue users. They wanted to find all conditionally set apiMethod parameter of `useRequest` hook.
@@ -299,23 +335,49 @@ We use `$$$` to be more generic for matching parts of conditional expression.
```ts
useRequest({
- apiMethod: $$$ ? $$$ : $$$
+ apiMethod: $$$ ? $$$ : $$$,
})
```
+### Unstable hook reference
+
+Some 3rd party hooks are not implemented correctly and return non-memoized variables.
+
+Let's assume you've found out that `confirm` callback from `useAsyncDialog` is unstable.
+
+You can use the snipped below to search for all similar places across the codebase and fix then if necessary.
+
+This is interesting example that links together two statements in the same code block, that does not necessarily have to directly follow each other.
+
+```ts
+const { confirm } = useAsyncDialog()
+const $$ = useCallback($$$, [confirm])
+```
+
+## Telemetry
+
+Extension collects anonymous telemetry to help me get insights about usage.
-## Support, Feedback and more
+It's implemented using `@vscode/extension-telemetry` and respects you editor telemetry settings.
+Learn more about [telemetry](https://codeque.co/docs/telemetry#vs-code-extension)
-Bugs, feature requests, help 👉 [Github Issues](https://github.com/codeque-co/codeque/issues)
+## Support and feedback
-Documentation 👉 [codeque.co/docs](https://codeque.co/docs)
+Feel free to use [Github Issues](https://github.com/codeque-co/codeque/issues)
+to
-Roadmap 👉 [codeque.co/roadmap](https://codeque.co/roadmap)
+- ask for help with writing a query
+- report a bug or doubt
+- suggest feature or improvement
-Mission 👉 [codeque.co/mission](https://codeque.co/mission)
+
-Playground 👉 [codeque.co/playground](https://codeque.co/playground)
+## Support and feedback
-Wanna contribute 👉 [Internal readme](./InternalReadme.md)
+Feel free to use [Github Issues](https://github.com/codeque-co/codeque/issues)
+to
+- ask for help with writing a query
+- report a bug or doubt
+- suggest feature or improvement
diff --git a/packages/vscode/declarations.d.ts b/packages/vscode/declarations.d.ts
new file mode 100644
index 0000000..2df47c9
--- /dev/null
+++ b/packages/vscode/declarations.d.ts
@@ -0,0 +1,3 @@
+declare module '@babel/eslint-parser'
+declare module 'espree'
+declare module '@angular-eslint/template-parser'
diff --git a/packages/vscode/package.json b/packages/vscode/package.json
index 4a47137..9b85985 100644
--- a/packages/vscode/package.json
+++ b/packages/vscode/package.json
@@ -1,157 +1,192 @@
{
- "name": "codeque",
- "publisher": "CodeQue",
- "displayName": "Multiline Structural Search - CodeQue",
- "description": "Multiline search for any language. Structural search for TypeScript and JavaScript",
- "repository": {
- "type": "git",
- "url": "https://github.com/codeque-co/codeque"
- },
- "bugs": {
- "url": "https://github.com/codeque-co/codeque/issues"
- },
- "version": "0.21.0",
- "engines": {
- "vscode": "^1.68.0",
- "node": ">=14"
- },
- "categories": [
- "Other"
- ],
- "keywords": [
- "typescript",
- "javascript",
- "search",
- "find",
- "match",
- "multiline",
- "structural",
- "replace",
- "regexp",
- "json"
- ],
- "activationEvents": [
- "onStartupFinished"
- ],
- "license": "SEE LICENSE IN LICENSE.md",
- "main": "./dist/extension.js",
- "icon": "media/logoShort_search.png",
- "galleryBanner": {
- "color": "#f3e2f9",
- "theme": "light"
- },
- "contributes": {
- "viewsContainers": {
- "activitybar": [
- {
- "id": "codeque-sidebar-view",
- "title": "CodeQue",
- "icon": "media/logoShort2.png"
- }
- ]
- },
- "views": {
- "codeque-sidebar-view": [
- {
- "type": "webview",
- "id": "codeque-sidebar",
- "name": "CodeQue",
- "icon": "media/logoShort2.png",
- "contextualTitle": "CodeQue"
- }
- ]
- },
- "commands": [
- {
- "command": "codeque.searchWithOptionalQuerySelectionFromEditor",
- "title": "CQ: Open Search"
- },
- {
- "command": "codeque.searchByEntryPoint",
- "title": "CQ: Search by Entry Point"
- },
- {
- "command": "codeque.searchInFolder",
- "title": "CQ: Search in Folder"
- },
- {
- "command": "codeque.refresh",
- "title": "CQ: Refresh extension"
- }
- ],
- "menus": {
- "explorer/context": [
- {
- "command": "codeque.searchByEntryPoint",
- "group": "4_search",
- "when": "!explorerResourceIsFolder"
- },
- {
- "command": "codeque.searchInFolder",
- "group": "4_search",
- "when": "explorerResourceIsFolder"
- }
- ],
- "editor/context": [
- {
- "group": "navigation",
- "command": "codeque.searchWithOptionalQuerySelectionFromEditor",
- "when": "editorHasSelection"
- },
- {
- "group": "navigation",
- "command": "codeque.searchByEntryPoint"
- }
- ]
- }
- },
- "scripts": {
- "vscode:prepublish": "yarn lint && yarn typecheck && yarn run package",
- "compile": "webpack",
- "watch:extension": "webpack --config webpack.extension.config.js --watch",
- "package:extension": "webpack --config webpack.extension.config.js --mode production",
- "watch:webviews": "webpack --config webpack.webviews.config.js --watch",
- "package:webviews": "webpack --config webpack.webviews.config.js --mode production",
- "package": "yarn package:extension && yarn package:webviews",
- "compile-tests": "tsc -p . --outDir out",
- "watch-tests": "tsc -p . -w --outDir out",
- "pretest": "yarn run compile-tests && yarn run compile && yarn run lint",
- "lint": "eslint src --ext ts",
- "test": "node ./out/test/runTest.js",
- "typecheck": "tsc --project tsconfig.json --noEmit"
- },
- "devDependencies": {
- "@types/glob": "^7.2.0",
- "@types/mocha": "^9.1.1",
- "@types/node": "16.x",
- "@types/vscode": "^1.68.0",
- "@typescript-eslint/eslint-plugin": "^5.30.0",
- "@typescript-eslint/parser": "^5.30.0",
- "@vscode/test-electron": "^2.1.5",
- "eslint": "^8.18.0",
- "glob": "^8.0.3",
- "mocha": "^10.0.0",
- "process": "^0.11.10",
- "ts-loader": "^9.3.1",
- "typescript": "^4.7.4",
- "webpack": "^5.73.0",
- "webpack-cli": "^4.10.0"
- },
- "dependencies": {
- "@chakra-ui/react": "^2.2.4",
- "@codeque/core": "^0.4.0",
- "@emotion/react": "^11.9.3",
- "@emotion/styled": "^11.9.3",
- "@types/react": "^18.0.15",
- "@types/react-dom": "^18.0.6",
- "copy-to-clipboard": "^3.3.2",
- "dedent": "^0.7.0",
- "framer-motion": "^6.5.1",
- "prism-react-renderer": "^1.3.5",
- "react": "^18.2.0",
- "react-dom": "^18.2.0",
- "react-icons": "^4.4.0",
- "react-select": "^5.4.0",
- "react-simple-code-editor": "^0.11.2"
- }
-}
\ No newline at end of file
+ "name": "codeque",
+ "publisher": "CodeQue",
+ "displayName": "Multiline & Structural Code Search",
+ "description": "Multiline code search for every language. Structural code search for JavaScript, TypeScript, HTML, CSS, Python and Lua",
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/codeque-co/codeque"
+ },
+ "bugs": {
+ "url": "https://github.com/codeque-co/codeque/issues"
+ },
+ "version": "0.37.0",
+ "engines": {
+ "vscode": "^1.68.0",
+ "node": ">=14"
+ },
+ "categories": [
+ "Programming Languages",
+ "Linters",
+ "Snippets",
+ "Other"
+ ],
+ "keywords": [
+ "typescript",
+ "javascript",
+ "json",
+ "html",
+ "css",
+ "python",
+ "lua",
+ "csharp",
+ "code search",
+ "find",
+ "match",
+ "multiline",
+ "structural",
+ "regexp",
+ "pattern",
+ "matching",
+ "ast",
+ "semantic",
+ "static",
+ "analysis",
+ "syntax",
+ "syntax aware",
+ "refactor",
+ "refactoring",
+ "replace",
+ "rewrite",
+ "rewriting",
+ "navigation",
+ "multiline search",
+ "structural search",
+ "search and replace",
+ "regexp search",
+ "json search"
+ ],
+ "activationEvents": [
+ "onStartupFinished"
+ ],
+ "license": "SEE LICENSE IN LICENSE.md",
+ "main": "./dist/extension.js",
+ "icon": "media/logoShort_search.png",
+ "galleryBanner": {
+ "color": "#f3e2f9",
+ "theme": "light"
+ },
+ "contributes": {
+ "viewsContainers": {
+ "activitybar": [
+ {
+ "id": "codeque-sidebar-view",
+ "title": "CodeQue",
+ "icon": "media/logoShort2.png"
+ }
+ ]
+ },
+ "views": {
+ "codeque-sidebar-view": [
+ {
+ "type": "webview",
+ "id": "codeque-sidebar",
+ "name": "CodeQue",
+ "icon": "media/logoShort2.png",
+ "contextualTitle": "CodeQue"
+ }
+ ]
+ },
+ "commands": [
+ {
+ "command": "codeque.searchWithOptionalQuerySelectionFromEditor",
+ "title": "CQ (CodeQue): Open Search"
+ },
+ {
+ "command": "codeque.searchByEntryPoint",
+ "title": "CQ (CodeQue): Search by Entry Point"
+ },
+ {
+ "command": "codeque.searchInFolder",
+ "title": "CQ (CodeQue): Search in Folder"
+ },
+ {
+ "command": "codeque.refresh",
+ "title": "CQ (CodeQue): Refresh extension"
+ },
+ {
+ "command": "codeque.activateProLicense",
+ "title": "CQ (CodeQue): Activate Pro license"
+ },
+ {
+ "command": "codeque.getProLicense",
+ "title": "CQ (CodeQue): Get Pro license"
+ }
+ ],
+ "menus": {
+ "explorer/context": [
+ {
+ "command": "codeque.searchByEntryPoint",
+ "group": "4_search",
+ "when": "!explorerResourceIsFolder"
+ },
+ {
+ "command": "codeque.searchInFolder",
+ "group": "4_search",
+ "when": "explorerResourceIsFolder"
+ }
+ ],
+ "editor/context": [
+ {
+ "group": "navigation",
+ "command": "codeque.searchWithOptionalQuerySelectionFromEditor",
+ "when": "editorHasSelection"
+ },
+ {
+ "group": "navigation",
+ "command": "codeque.searchByEntryPoint"
+ }
+ ]
+ }
+ },
+ "scripts": {
+ "vscode:prepublish": "yarn lint && yarn typecheck && yarn run package",
+ "compile": "webpack",
+ "watch:extension": "webpack --config webpack.extension.config.js --watch",
+ "package:extension": "webpack --config webpack.extension.config.js --mode production ",
+ "watch:webviews": "webpack --config webpack.webviews.config.js --watch",
+ "package:webviews": "webpack --config webpack.webviews.config.js --mode production",
+ "package": "yarn package:extension && yarn package:webviews",
+ "compile-tests": "tsc -p . --outDir out",
+ "watch-tests": "tsc -p . -w --outDir out",
+ "lint": "eslint src --ext ts",
+ "test": "echo 0",
+ "typecheck": "tsc --project tsconfig.json --noEmit"
+ },
+ "devDependencies": {
+ "@types/glob": "^7.2.0",
+ "@types/mocha": "^9.1.1",
+ "@types/node": "16.x",
+ "@types/vscode": "^1.68.0",
+ "@typescript-eslint/eslint-plugin": "^5.30.0",
+ "@typescript-eslint/parser": "^5.30.0",
+ "@vscode/test-electron": "^2.1.5",
+ "eslint": "^8.18.0",
+ "glob": "^8.0.3",
+ "mocha": "^10.0.0",
+ "process": "^0.11.10",
+ "ts-loader": "^9.3.1",
+ "typescript": "5.9.3",
+ "webpack": "^5.73.0",
+ "webpack-cli": "^4.10.0"
+ },
+ "dependencies": {
+ "@chakra-ui/react": "^2.2.4",
+ "@codeque/core": "^0.6.1",
+ "@emotion/react": "^11.9.3",
+ "@emotion/styled": "^11.9.3",
+ "@types/react": "^18.0.15",
+ "@types/react-dom": "^18.0.6",
+ "@vscode/extension-telemetry": "^0.8.0",
+ "copy-to-clipboard": "^3.3.2",
+ "dedent": "^0.7.0",
+ "framer-motion": "^6.5.1",
+ "node-fetch": "^3.3.2",
+ "prism-react-renderer": "^1.3.5",
+ "react": "^18.2.0",
+ "react-dom": "^18.2.0",
+ "react-icons": "^4.4.0",
+ "react-select": "^5.4.0",
+ "react-simple-code-editor": "^0.11.2"
+ }
+}
diff --git a/packages/vscode/readme-media/intro.gif b/packages/vscode/readme-media/intro.gif
new file mode 100644
index 0000000..4a18c0a
Binary files /dev/null and b/packages/vscode/readme-media/intro.gif differ
diff --git a/packages/vscode/src/EventBus.ts b/packages/vscode/src/EventBus.ts
index 47ad9e6..9e15349 100644
--- a/packages/vscode/src/EventBus.ts
+++ b/packages/vscode/src/EventBus.ts
@@ -1,6 +1,7 @@
-import { StateShape } from './StateManager'
-import { Match } from '@codeque/core'
-import { ExtendedSearchResults } from './types'
+import { SearchStateShape } from './SearchStateManager'
+import { Match, SearchInFileError } from '@codeque/core'
+import { Banner, ExtendedSearchResults } from './types'
+import { UserStateShape } from './UserStateManager'
type ResultsEventData = {
results: ExtendedSearchResults
@@ -14,21 +15,39 @@ type EventTypes = {
'results-panel-opened': null
'results-panel-visibility': boolean
'show-results-panel': null
- 'set-settings': Partial
- 'initial-settings': StateShape
+ 'set-search-settings': Partial
+ 'initial-search-settings': SearchStateShape
+ 'search-settings-changed': Partial
+ 'set-user-settings': Partial
+ 'initial-user-settings': UserStateShape
+ 'user-settings-changed': Partial
'open-file': {
filePath: string
- location?: Match['loc']
+ locationsToSelect?: Array
+ locationsToDecorate?: Array
}
'open-search-from-selection': null
'start-search': null
'search-started': string
'have-results': ResultsEventData
'have-partial-results': ResultsEventData
- 'settings-changed': Partial
'set-query-in-settings': string | null
+ 'set-replacement-in-settings': string | null
'set-query-on-ui': string
'stop-search': null
+ 'start-replace': null
+ 'replace-started': null
+ 'replace-progress': number | null
+ 'replace-finished': { time: number }
+ 'replace-errors': { errors: Array }
+ 'search-progress': number | null
+ 'fetch:banners:start': null
+ 'fetch:banners:response': Banner[]
+ 'banner:close': string
+ 'banner:clicked-link': string
+ 'pro-modal:closed': null
+ 'pro-modal:subscribe_clicked': null
+ 'pro-modal:twitter_handler_clicked': null
}
type EventObjectTypes = {
@@ -50,11 +69,11 @@ export class EventBus {
'results-panel-opened': [],
'show-results-panel': [],
'results-panel-visibility': [],
- 'initial-settings': [],
- 'set-settings': [],
+ 'initial-search-settings': [],
+ 'set-search-settings': [],
+ 'search-settings-changed': [],
'set-query-in-settings': [],
'set-query-on-ui': [],
- 'settings-changed': [],
'open-file': [],
'open-search-from-selection': [],
'start-search': [],
@@ -62,6 +81,23 @@ export class EventBus {
'have-results': [],
'have-partial-results': [],
'stop-search': [],
+ 'replace-finished': [],
+ 'replace-started': [],
+ 'replace-errors': [],
+ 'start-replace': [],
+ 'set-replacement-in-settings': [],
+ 'replace-progress': [],
+ 'search-progress': [],
+ 'set-user-settings': [],
+ 'initial-user-settings': [],
+ 'user-settings-changed': [],
+ 'fetch:banners:start': [],
+ 'fetch:banners:response': [],
+ 'banner:close': [],
+ 'banner:clicked-link': [],
+ 'pro-modal:closed': [],
+ 'pro-modal:subscribe_clicked': [],
+ 'pro-modal:twitter_handler_clicked': [],
}
public env = 'extension'
@@ -108,7 +144,11 @@ export class EventBus {
data?: EventTypes[T],
dispatchThroughTransports = true,
) => {
- // console.log(`dispatch:${this.env}`, eventType, data)
+ if (process.env.NODE_ENV !== 'production') {
+ //eslint-disable-next-line
+ console.log('event', eventType, data)
+ }
+
try {
await Promise.all(
this.listeners[eventType].map((callback) => callback(data)),
diff --git a/packages/vscode/src/SearchManager.ts b/packages/vscode/src/SearchManager.ts
index 287ba56..5a617e7 100644
--- a/packages/vscode/src/SearchManager.ts
+++ b/packages/vscode/src/SearchManager.ts
@@ -9,14 +9,31 @@ import {
filterIncludeExclude,
SearchInFileError,
typeScriptFamilyExtensionTester,
+ cssExtensionTester,
+ htmlFamilyExtensionTester,
filterExtensions,
+ pythonExtensionTester,
+ luaExtensionTester,
+ csharpExtensionTester,
+ __internal,
} from '@codeque/core'
-import { sanitizeFsPath } from './nodeUtils'
+import {
+ getMainSearchExtensionFromFilesList,
+ sanitizeFsPath,
+} from './nodeUtils'
import path from 'path'
import * as vscode from 'vscode'
import { eventBusInstance } from './EventBus'
-import { StateManager, StateShape } from './StateManager'
-import { simpleDebounce } from './utils'
+import { SearchStateManager, SearchStateShape } from './SearchStateManager'
+import {
+ simpleDebounce,
+ fileTypeToParserMap,
+ nonSearchableExtensions,
+} from './utils'
+import { TelemetryModule } from './telemetry'
+import { isQueryRestricted } from './restrictedQueries'
+import { UserStateManager } from './UserStateManager'
+import { SearchFileType } from 'types'
type FilesLists = {
files: string[]
@@ -25,6 +42,16 @@ type FilesLists = {
type Root = { path: string; name?: string }
+const extensionTesterMap: Record = {
+ all: /\.(.)+$/,
+ html: htmlFamilyExtensionTester,
+ 'js-ts-json': typeScriptFamilyExtensionTester,
+ css: cssExtensionTester,
+ python: pythonExtensionTester,
+ lua: luaExtensionTester,
+ csharp: csharpExtensionTester,
+}
+
export class SearchManager {
private isWorkspace: boolean | undefined
private roots: Root[] | undefined
@@ -42,15 +69,25 @@ export class SearchManager {
}[],
workspaceFoldersChangeListener: undefined as vscode.Disposable | undefined,
}
- private lastSearchSettings: StateShape | undefined
-
- constructor(private readonly stateManager: StateManager) {
+ private lastSearchSettings: SearchStateShape | undefined
+ private telemetryReporter: TelemetryModule
+ private extensionSourceRootPath: string
+
+ constructor(
+ private readonly searchStateManager: SearchStateManager,
+ private readonly userStateManager: UserStateManager,
+ telemetryReporter: TelemetryModule,
+ extensionSourceRootPath: string,
+ ) {
eventBusInstance.addListener('start-search', this.startSearch)
+ eventBusInstance.addListener('start-replace', this.startStubReplace)
eventBusInstance.addListener('stop-search', this.stopCurrentSearch)
this.initializeSearchRoots()
this.maybeStartWatchingFilesList()
this.watchWorkspaceChanges()
+ this.telemetryReporter = telemetryReporter
+ this.extensionSourceRootPath = extensionSourceRootPath
}
private determineRoots() {
@@ -189,7 +226,15 @@ export class SearchManager {
}
private startSearch = () => {
- this.performSearch(this.stateManager.getState())
+ const state = this.searchStateManager.getState()
+
+ if (!isQueryRestricted(state.query, state.fileType, state.mode)) {
+ this.performSearch(state)
+ }
+ }
+
+ private startStubReplace = () => {
+ this.telemetryReporter.reportStubReplaceClick()
}
private stopCurrentSearch = () => {
@@ -283,7 +328,7 @@ export class SearchManager {
return adjustedEntryPoint
}
- public performSearch = async (settings: StateShape) => {
+ public performSearch = async (settings: SearchStateShape) => {
this.lastSearchSettings = settings
if (this.roots === undefined) {
@@ -401,45 +446,97 @@ export class SearchManager {
}
}
- const finalFilesList =
- settings.mode === 'text'
- ? files
- : filterExtensions(files, typeScriptFamilyExtensionTester)
-
- // We start search in next tick so not block events delivery and UI update
- setTimeout(
- (async () => {
- const results = await searchMultiThread({
- filePaths: finalFilesList,
- queryCodes: [settings.query],
- mode: settings.mode,
- caseInsensitive: settings.caseType === 'insensitive',
- onPartialResult: reportPartialResults,
- hardStopFlag: this.currentSearchHardStopFlag,
- maxResultsLimit: this.maxResultsLimit,
- })
- const searchEnd = Date.now()
+ const extensionTester = extensionTesterMap[settings.fileType]
- eventBusInstance.dispatch('have-results', {
- results: this.processSearchResults(
- { ...results, matches: allPartialMatches },
- roots,
- isWorkspace,
- ),
- time: (searchEnd - searchStart) / 1000,
- files: finalFilesList,
- isWorkspace,
- })
-
- this.searchRunning = false
- this.currentFilesGetHardStopFlag?.destroy()
- this.currentSearchHardStopFlag?.destroy()
- this.currentFilesGetHardStopFlag = undefined
- this.currentSearchHardStopFlag = undefined
- }).bind(this),
- 0,
+ const filesListFilteredByExtension = filterExtensions(
+ files,
+ extensionTester,
+ ).filter(
+ (filePath) =>
+ !nonSearchableExtensions.some((nonSearchableExtension) =>
+ filePath.endsWith(nonSearchableExtension),
+ ),
)
+ const parser = fileTypeToParserMap[settings.fileType]
+
+ await new Promise((resolve, reject) => {
+ // We start search in next tick so not block events delivery and UI update
+ setTimeout(
+ (async () => {
+ try {
+ this.searchStateManager.setState({ searchFinished: false })
+ const results = await searchMultiThread({
+ parser,
+ filePaths: filesListFilteredByExtension,
+ queryCodes: [settings.query],
+ mode: settings.mode,
+ caseInsensitive: settings.caseType === 'insensitive',
+ onPartialResult: reportPartialResults,
+ hardStopFlag: this.currentSearchHardStopFlag,
+ maxResultsLimit: this.maxResultsLimit,
+ parserFilesBasePath: this.extensionSourceRootPath,
+ })
+
+ const searchEnd = Date.now()
+
+ const searchTime = (searchEnd - searchStart) / 1000
+
+ const processedResults = this.processSearchResults(
+ { ...results, matches: allPartialMatches },
+ roots,
+ isWorkspace,
+ )
+
+ eventBusInstance.dispatch('have-results', {
+ results: processedResults,
+ time: searchTime,
+ files: filesListFilteredByExtension,
+ isWorkspace,
+ })
+
+ if (processedResults.matches.length > 0) {
+ const searchesWithResultsCount =
+ this.userStateManager.getState().searchesWithResultsCount
+
+ this.userStateManager.setState({
+ searchesWithResultsCount: searchesWithResultsCount + 1,
+ })
+ }
+
+ this.searchStateManager.setState({ searchFinished: true })
+ this.searchRunning = false
+ this.currentFilesGetHardStopFlag?.destroy()
+ this.currentSearchHardStopFlag?.destroy()
+ this.currentFilesGetHardStopFlag = undefined
+ this.currentSearchHardStopFlag = undefined
+
+ const mainExt = getMainSearchExtensionFromFilesList(
+ filesListFilteredByExtension,
+ )
+
+ this.telemetryReporter.reportSearch({
+ mode: settings.mode,
+ caseType: settings.caseType,
+ fileType: settings.fileType,
+ isWorkspace: isWorkspace ? 'true' : 'false',
+ queryLength: settings.query.length,
+ searchTime: searchTime,
+ resultsCount: processedResults.matches.length,
+ errorsCount: processedResults.errors.length,
+ searchedFilesCount: filesListFilteredByExtension.length,
+ mainExt: mainExt,
+ })
+
+ resolve()
+ } catch (e) {
+ reject(e)
+ }
+ }).bind(this),
+ 0,
+ )
+ })
+
// console.log(
// 'files:',
// (getFilesEnd - searchStart) / 1000,
@@ -461,7 +558,9 @@ export class SearchManager {
'Search error: ' + error?.message + '\n\nStack:\n' + error?.stack,
)
- console.error(error)
+ console.error(typeof error, error, error.stack, error.message)
+
+ const searchTime = (Date.now() - searchStart) / 1000
eventBusInstance.dispatch('have-results', {
results: {
@@ -472,12 +571,21 @@ export class SearchManager {
groupedMatches: {},
workspacesMap: {},
},
- time: (Date.now() - searchStart) / 1000,
+ time: searchTime,
files: [],
isWorkspace: isWorkspace ?? false,
})
this.searchRunning = false
+
+ this.telemetryReporter.reportSearchError({
+ mode: settings.mode,
+ caseType: settings.caseType,
+ fileType: settings.fileType,
+ isWorkspace: isWorkspace ? 'true' : 'false',
+ queryLength: settings.query.length,
+ searchTime,
+ })
}
}
public dispose() {
@@ -488,6 +596,7 @@ export class SearchManager {
this.filesListState.workspaceFoldersChangeListener?.dispose()
eventBusInstance.removeListener('start-search', this.startSearch)
+ eventBusInstance.removeListener('start-replace', this.startStubReplace)
eventBusInstance.removeListener('stop-search', this.stopCurrentSearch)
}
}
diff --git a/packages/vscode/src/SearchResultsPanel.ts b/packages/vscode/src/SearchResultsPanel.ts
index 381aa4a..3f868ef 100644
--- a/packages/vscode/src/SearchResultsPanel.ts
+++ b/packages/vscode/src/SearchResultsPanel.ts
@@ -3,8 +3,12 @@ import dedent from 'dedent'
import * as vscode from 'vscode'
import { eventBusInstance } from './EventBus'
import { getNonce } from './getNonce'
-import { StateManager } from './StateManager'
+import { SearchStateManager } from './SearchStateManager'
+import {
+ getMatchHighlightStyle,
+ getMatchHighlightStyleSecondary,
+} from './codeHighlightSettings'
export class SearchResultsPanel {
/**
* Track the currently panel. Only allow a single panel to exist at a time.
@@ -15,12 +19,12 @@ export class SearchResultsPanel {
private readonly _panel: vscode.WebviewPanel
private readonly _extensionUri: vscode.Uri
- private readonly stateManager: StateManager
+ private readonly searchStateManager: SearchStateManager
private _disposables: vscode.Disposable[] = []
public static createOrShow(
extensionUri: vscode.Uri,
- stateManager: StateManager,
+ searchStateManager: SearchStateManager,
) {
const column = vscode.window.activeTextEditor
? vscode.window.activeTextEditor.viewColumn
@@ -47,6 +51,7 @@ export class SearchResultsPanel {
localResourceRoots: [
vscode.Uri.joinPath(extensionUri, 'media'),
vscode.Uri.joinPath(extensionUri, 'dist-webviews'),
+ vscode.Uri.joinPath(extensionUri, 'dist-tree-sitter'),
],
},
)
@@ -63,7 +68,7 @@ export class SearchResultsPanel {
SearchResultsPanel.currentPanel = new SearchResultsPanel(
panel,
extensionUri,
- stateManager,
+ searchStateManager,
)
}
@@ -76,23 +81,23 @@ export class SearchResultsPanel {
public static revive(
panel: vscode.WebviewPanel,
extensionUri: vscode.Uri,
- stateManager: StateManager,
+ searchStateManager: SearchStateManager,
) {
SearchResultsPanel.currentPanel = new SearchResultsPanel(
panel,
extensionUri,
- stateManager,
+ searchStateManager,
)
}
private constructor(
panel: vscode.WebviewPanel,
extensionUri: vscode.Uri,
- stateManager: StateManager,
+ searchStateManager: SearchStateManager,
) {
this._panel = panel
this._extensionUri = extensionUri
- this.stateManager = stateManager
+ this.searchStateManager = searchStateManager
const webview = this._panel.webview
// Set the webview's initial html content
this._update()
@@ -117,6 +122,12 @@ export class SearchResultsPanel {
)
eventBusInstance.addListener('set-query-in-settings', this.setQueryData)
+
+ eventBusInstance.addListener(
+ 'set-replacement-in-settings',
+ this.setReplacementData,
+ )
+
eventBusInstance.addListener('open-file', this.openFile)
eventBusInstance.addListenerOnce('results-panel-opened', () => {
@@ -134,6 +145,11 @@ export class SearchResultsPanel {
this.setQueryData,
)
+ eventBusInstance.removeListener(
+ 'set-replacement-in-settings',
+ this.setReplacementData,
+ )
+
eventBusInstance.removeListener('open-file', this.openFile)
eventBusInstance.removeTransport(postMessage)
@@ -143,39 +159,121 @@ export class SearchResultsPanel {
}
private setQueryData = (query: string | null) => {
- this.stateManager.setState({ query: query ?? '' })
+ this.searchStateManager.setState({ query: query ?? '' })
+ }
+
+ private setReplacementData = (replacement: string | null) => {
+ this.searchStateManager.setState({ replacement: replacement ?? '' })
}
private sendInitialDataToWebview = () => {
- eventBusInstance.dispatch('initial-settings', this.stateManager.getState())
+ eventBusInstance.dispatch(
+ 'initial-search-settings',
+ this.searchStateManager.getState(),
+ )
+ }
+
+ private getPositionsFromMatchLocation = (matchLocation: Match['loc']) => {
+ const startPos = new vscode.Position(
+ matchLocation.start.line - 1, // API has 0-based indexes
+ matchLocation.start.column,
+ )
+ const endPos = new vscode.Position(
+ matchLocation.end.line - 1, // API has 0-based indexes
+ matchLocation.end.column,
+ )
+
+ return [startPos, endPos] as const
}
private openFile = ({
filePath,
- location,
+ locationsToSelect,
+ locationsToDecorate,
}: {
filePath: string
- location?: Match['loc']
+ locationsToSelect?: Array
+ locationsToDecorate?: Array
}) => {
const setting: vscode.Uri = vscode.Uri.file(filePath)
vscode.workspace.openTextDocument(setting).then(
- (textDoc: vscode.TextDocument) => {
- let selection = undefined
-
- if (location) {
- const startPos = new vscode.Position(
- location.start.line - 1, // API has 0-based indexes
- location.start.column,
- )
- const endPos = new vscode.Position(
- location.end.line - 1, // API has 0-based indexes
- location.end.column,
- )
- selection = new vscode.Range(startPos, endPos)
+ async (textDoc: vscode.TextDocument) => {
+ let mainSelection = undefined
+
+ if (locationsToSelect?.[0]) {
+ mainSelection = {
+ selection: new vscode.Range(
+ ...this.getPositionsFromMatchLocation(locationsToSelect?.[0]),
+ ),
+ }
}
- return vscode.window.showTextDocument(textDoc, { selection })
+ const selectLikeCodeDecoration =
+ vscode.window.createTextEditorDecorationType({
+ light: getMatchHighlightStyle(false),
+ dark: getMatchHighlightStyle(true),
+ })
+
+ const selectLikeCodeDecorationSecondary =
+ vscode.window.createTextEditorDecorationType({
+ light: getMatchHighlightStyleSecondary(false),
+ dark: getMatchHighlightStyleSecondary(true),
+ })
+
+ return vscode.window
+ .showTextDocument(textDoc, mainSelection)
+ .then(() => {
+ if (vscode.window.activeTextEditor) {
+ const selections = locationsToSelect
+ ? locationsToSelect.map(
+ (locationToSelect) =>
+ new vscode.Selection(
+ ...this.getPositionsFromMatchLocation(locationToSelect),
+ ),
+ )
+ : []
+
+ const selectionDecorations: vscode.DecorationOptions[] = []
+ const secondaryDecorations: vscode.DecorationOptions[] = []
+
+ locationsToDecorate?.forEach((locationToDecorate) => {
+ const rangeToDecorate = new vscode.Range(
+ ...this.getPositionsFromMatchLocation(locationToDecorate),
+ )
+ const hasMatchingSelection = selections.some((selection) =>
+ selection.isEqual(rangeToDecorate),
+ )
+
+ if (hasMatchingSelection) {
+ selectionDecorations.push({
+ range: rangeToDecorate,
+ })
+ } else {
+ secondaryDecorations.push({ range: rangeToDecorate })
+ }
+ })
+
+ if (secondaryDecorations.length > 0) {
+ vscode.window.activeTextEditor.setDecorations(
+ selectLikeCodeDecorationSecondary,
+ secondaryDecorations,
+ )
+ }
+
+ // Apply selectionDecorations after secondary, so selection overlaps in case of intersection of ranges
+ if (selectionDecorations.length > 0) {
+ vscode.window.activeTextEditor.setDecorations(
+ selectLikeCodeDecoration,
+ selectionDecorations,
+ )
+ }
+
+ if (locationsToSelect && locationsToSelect.length > 1) {
+ vscode.window.activeTextEditor.selections = selections
+ }
+ }
+ })
},
(error: any) => {
console.error('error opening file', filePath)
@@ -223,10 +321,6 @@ export class SearchResultsPanel {
vscode.Uri.joinPath(this._extensionUri, 'media', 'vscode.css'),
)
- const cssUri = webview.asWebviewUri(
- vscode.Uri.joinPath(this._extensionUri, 'out', 'compiled/swiper.css'),
- )
-
const nonce = getNonce()
return dedent`
@@ -234,14 +328,14 @@ export class SearchResultsPanel {
-
+
-