From 9fd682749249fb8b2b0f19dff09ea581de8ea422 Mon Sep 17 00:00:00 2001 From: bendtherules Date: Fri, 3 Jan 2020 01:05:35 +0530 Subject: [PATCH 1/4] match-identifier-by-symbol - Add example transformer --- .../match-identifier-by-symbol/source.ts | 6 +++ .../transformed/source.js | 6 +++ .../match-identifier-by-symbol/transformer.ts | 45 +++++++++++++++++++ .../match-identifier-by-symbol/tsconfig.json | 8 ++++ 4 files changed, 65 insertions(+) create mode 100644 example-transformers/match-identifier-by-symbol/source.ts create mode 100644 example-transformers/match-identifier-by-symbol/transformed/source.js create mode 100644 example-transformers/match-identifier-by-symbol/transformer.ts create mode 100644 example-transformers/match-identifier-by-symbol/tsconfig.json diff --git a/example-transformers/match-identifier-by-symbol/source.ts b/example-transformers/match-identifier-by-symbol/source.ts new file mode 100644 index 0000000..59480c6 --- /dev/null +++ b/example-transformers/match-identifier-by-symbol/source.ts @@ -0,0 +1,6 @@ +let foo = 1; +foo = 2; +{ + const foo = 'abcd'; +} +foo = 3; diff --git a/example-transformers/match-identifier-by-symbol/transformed/source.js b/example-transformers/match-identifier-by-symbol/transformed/source.js new file mode 100644 index 0000000..9a5467c --- /dev/null +++ b/example-transformers/match-identifier-by-symbol/transformed/source.js @@ -0,0 +1,6 @@ +let foo = 1; +foo = 2; +{ + const foo = 'abcd'; +} +foo = 3; diff --git a/example-transformers/match-identifier-by-symbol/transformer.ts b/example-transformers/match-identifier-by-symbol/transformer.ts new file mode 100644 index 0000000..0353218 --- /dev/null +++ b/example-transformers/match-identifier-by-symbol/transformer.ts @@ -0,0 +1,45 @@ +import * as ts from 'typescript'; + +const transformerProgram = (program: ts.Program) => { + const typeChecker = program.getTypeChecker(); + + // Create array of found symbols + const foundSymbols = new Array(); + + const transformerFactory: ts.TransformerFactory = context => { + return sourceFile => { + const visitor = (node: ts.Node): ts.Node => { + if (ts.isIdentifier(node)) { + const relatedSymbol = typeChecker.getSymbolAtLocation(node); + + // Check if set already contains same symbol - check by reference + if (foundSymbols.includes(relatedSymbol)) { + const foundIndex = foundSymbols.indexOf(relatedSymbol); + console.log( + `Found existing symbol at position = ${foundIndex} and name = "${relatedSymbol.name}"` + ); + } else { + // If not found, Add it to array + foundSymbols.push(relatedSymbol); + + console.log( + `Found new symbol with name = "${ + relatedSymbol.name + }". Added at positon = ${foundSymbols.length - 1}` + ); + } + + return node; + } + + return ts.visitEachChild(node, visitor, context); + }; + + return ts.visitNode(sourceFile, visitor); + }; + }; + + return transformerFactory; +}; + +export default transformerProgram; diff --git a/example-transformers/match-identifier-by-symbol/tsconfig.json b/example-transformers/match-identifier-by-symbol/tsconfig.json new file mode 100644 index 0000000..c7f3beb --- /dev/null +++ b/example-transformers/match-identifier-by-symbol/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../tsconfig.json", + "compilerOptions": { + "outDir": "transformed", + "plugins": [{ "transform": "./transformer.ts" }] + }, + "files": ["source.ts"] +} From 9161e16a982558ab4f2fffa4ffcb164d9c9cbfc4 Mon Sep 17 00:00:00 2001 From: bendtherules Date: Fri, 3 Jan 2020 01:17:04 +0530 Subject: [PATCH 2/4] docs - Add "identifiers having same symbol" part --- translations/en/transformer-handbook.md | 74 ++++++++++++++++++++++++- 1 file changed, 71 insertions(+), 3 deletions(-) diff --git a/translations/en/transformer-handbook.md b/translations/en/transformer-handbook.md index 29f87b6..aa51219 100644 --- a/translations/en/transformer-handbook.md +++ b/translations/en/transformer-handbook.md @@ -41,7 +41,7 @@ This document covers how to write a [Typescript](https://typescriptlang.org/) [T - [Transformation operations](#transformation-operations) - [Visiting](#visiting-1) - [Checking a node is a certain type](#checking-a-node-is-a-certain-type) - - [Check if an identifier is referenced](#check-if-an-identifier-is-referenced) + - [Check if two identifiers refer to the same symbol](#check-if-two-identifiers-refer-to-the-same-symbol) - [Find a specific parent](#find-a-specific-parent) - [Stopping traversal](#stopping-traversal) - [Manipulation](#manipulation) @@ -879,9 +879,77 @@ const visitor = (node: ts.Node): ts.Node => { }; ``` -#### Check if an identifier is referenced +#### Check if two identifiers refer to the same symbol -> **TODO** - Is this possible? +Identifiers are created by the parser and are always unique. +Say, if you create a variable `foo` and use it in another line, it will create 2 separate identifiers with the same text `foo`. + +Then, the linker runs through these identifiers and connects the identifiers referring to the same variable with a common symbol (while considering scope and shadowing). Think of symbols as what we intuitively think as variables. + +So, to check if two identifiers refer to the same symbol - just get the symbols related to the identifier and check if they are the same (by reference). + +Short example - + +```ts +const symbol1 = typeChecker.getSymbolAtLocation(node1); +const symbol2 = typeChecker.getSymbolAtLocation(node2); + +symbol1 === symbol2 // check by reference +``` + +Full example - + +This will log all repeating symbols. + +```ts +import * as ts from 'typescript'; + +const transformerProgram = (program: ts.Program) => { + const typeChecker = program.getTypeChecker(); + + // Create array of found symbols + const foundSymbols = new Array(); + + const transformerFactory: ts.TransformerFactory = context => { + return sourceFile => { + const visitor = (node: ts.Node): ts.Node => { + if (ts.isIdentifier(node)) { + const relatedSymbol = typeChecker.getSymbolAtLocation(node); + + // Check if set already contains same symbol - check by reference + if (foundSymbols.includes(relatedSymbol)) { + const foundIndex = foundSymbols.indexOf(relatedSymbol); + console.log( + `Found existing symbol at position = ${foundIndex} and name = "${relatedSymbol.name}"` + ); + } else { + // If not found, Add it to array + foundSymbols.push(relatedSymbol); + + console.log( + `Found new symbol with name = "${ + relatedSymbol.name + }". Added at positon = ${foundSymbols.length - 1}` + ); + } + + return node; + } + + return ts.visitEachChild(node, visitor, context); + }; + + return ts.visitNode(sourceFile, visitor); + }; + }; + + return transformerFactory; +}; + +export default transformerProgram; +``` + +> **Tip** - You can see the source for this at [/example-transformers/match-identifier-by-symbol](/example-transformers/match-identifier-by-symbol) #### Find a specific parent From a5af891527d281e6c83300443cc1f9750d553312 Mon Sep 17 00:00:00 2001 From: bendtherules Date: Fri, 3 Jan 2020 01:23:45 +0530 Subject: [PATCH 3/4] match-identifier-by-symbol - Fix comment typo --- example-transformers/match-identifier-by-symbol/transformer.ts | 2 +- translations/en/transformer-handbook.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/example-transformers/match-identifier-by-symbol/transformer.ts b/example-transformers/match-identifier-by-symbol/transformer.ts index 0353218..602ae5a 100644 --- a/example-transformers/match-identifier-by-symbol/transformer.ts +++ b/example-transformers/match-identifier-by-symbol/transformer.ts @@ -12,7 +12,7 @@ const transformerProgram = (program: ts.Program) => { if (ts.isIdentifier(node)) { const relatedSymbol = typeChecker.getSymbolAtLocation(node); - // Check if set already contains same symbol - check by reference + // Check if array already contains same symbol - check by reference if (foundSymbols.includes(relatedSymbol)) { const foundIndex = foundSymbols.indexOf(relatedSymbol); console.log( diff --git a/translations/en/transformer-handbook.md b/translations/en/transformer-handbook.md index aa51219..b233992 100644 --- a/translations/en/transformer-handbook.md +++ b/translations/en/transformer-handbook.md @@ -916,7 +916,7 @@ const transformerProgram = (program: ts.Program) => { if (ts.isIdentifier(node)) { const relatedSymbol = typeChecker.getSymbolAtLocation(node); - // Check if set already contains same symbol - check by reference + // Check if array already contains same symbol - check by reference if (foundSymbols.includes(relatedSymbol)) { const foundIndex = foundSymbols.indexOf(relatedSymbol); console.log( From 6da83404b503db90954f9bce412171843f325875 Mon Sep 17 00:00:00 2001 From: bendtherules Date: Fri, 3 Jan 2020 01:25:31 +0530 Subject: [PATCH 4/4] match-identifier-by-symbol - Mark example text bold --- translations/en/transformer-handbook.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/translations/en/transformer-handbook.md b/translations/en/transformer-handbook.md index b233992..c2aebd7 100644 --- a/translations/en/transformer-handbook.md +++ b/translations/en/transformer-handbook.md @@ -888,7 +888,7 @@ Then, the linker runs through these identifiers and connects the identifiers ref So, to check if two identifiers refer to the same symbol - just get the symbols related to the identifier and check if they are the same (by reference). -Short example - +**Short example** - ```ts const symbol1 = typeChecker.getSymbolAtLocation(node1); @@ -897,7 +897,7 @@ const symbol2 = typeChecker.getSymbolAtLocation(node2); symbol1 === symbol2 // check by reference ``` -Full example - +**Full example** - This will log all repeating symbols.