@esportsplus/typescript 0.9.2 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,9 +1,27 @@
1
- name: bump
1
+ name: bump version
2
2
 
3
3
  on:
4
4
  push:
5
5
  branches: '**' # only trigger on branches, not on tags
6
+ workflow_call:
7
+
8
+ concurrency:
9
+ group: ${{ github.workflow }}-${{ github.ref }}
10
+ cancel-in-progress: true
11
+
12
+ permissions:
13
+ contents: write
6
14
 
7
15
  jobs:
8
16
  bump:
9
- uses: esportsplus/workflows/.github/workflows/bump.yml@main
17
+ runs-on: ubuntu-latest
18
+ steps:
19
+ - name: checkout repo
20
+ uses: actions/checkout@v4
21
+ with:
22
+ fetch-depth: 0
23
+ - name: bump version
24
+ uses: jpb06/bump-package@latest
25
+ with:
26
+ minor-keywords: feat,minor,refactor
27
+ patch-keywords: fix,chore
@@ -3,10 +3,56 @@ name: dependabot automerge
3
3
  on:
4
4
  pull_request:
5
5
  types: [opened, synchronize, labeled]
6
- workflow_dispatch:
6
+ workflow_call:
7
+ secrets:
8
+ NPM_TOKEN:
9
+ required: true
10
+
11
+ concurrency:
12
+ group: ${{ github.workflow }}-${{ github.ref }}
13
+ cancel-in-progress: true
14
+
15
+ permissions:
16
+ contents: write
17
+ pull-requests: write
7
18
 
8
19
  jobs:
20
+ build:
21
+ runs-on: ubuntu-latest
22
+ steps:
23
+ - uses: actions/checkout@v4
24
+ - uses: pnpm/action-setup@v4
25
+ name: Install pnpm
26
+ with:
27
+ run_install: false
28
+ version: latest
29
+ - uses: actions/setup-node@v4
30
+ with:
31
+ cache: 'pnpm'
32
+ node-version: 'latest'
33
+ registry-url: 'https://registry.npmjs.org'
34
+ - run: pnpm i && pnpm build
35
+ env:
36
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
37
+
9
38
  automerge:
10
- secrets:
11
- NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
12
- uses: esportsplus/workflows/.github/workflows/dependabot.yml@main
39
+ needs: build
40
+ permissions:
41
+ pull-requests: write
42
+ contents: write
43
+ runs-on: ubuntu-latest
44
+ if: ${{ github.actor == 'dependabot[bot]' && github.event_name == 'pull_request' }}
45
+ steps:
46
+ - uses: dependabot/fetch-metadata@v2
47
+ id: metadata
48
+ with:
49
+ alert-lookup: true
50
+ compat-lookup: true
51
+ github-token: ${{ secrets.GITHUB_TOKEN }}
52
+ - name: Approve and merge Dependabot PR
53
+ run: |
54
+ gh pr review --approve "$PR_URL"
55
+ gh pr merge --squash --auto "$PR_URL"
56
+ env:
57
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
58
+ PR_URL: ${{ github.event.pull_request.html_url }}
@@ -3,14 +3,41 @@ name: publish to npm
3
3
  on:
4
4
  release:
5
5
  types: [published]
6
+ workflow_call:
7
+ secrets:
8
+ NPM_TOKEN:
9
+ required: true
6
10
  workflow_dispatch:
7
11
  workflow_run:
8
- workflows: [bump]
12
+ workflows: [bump version]
9
13
  types:
10
14
  - completed
11
15
 
16
+ concurrency:
17
+ group: ${{ github.workflow }}-${{ github.ref }}
18
+ cancel-in-progress: true
19
+
12
20
  jobs:
13
- publish:
14
- secrets:
15
- NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN_PUBLISHING }}
16
- uses: esportsplus/workflows/.github/workflows/publish.yml@main
21
+ build:
22
+ runs-on: ubuntu-latest
23
+ permissions:
24
+ contents: read
25
+ id-token: write
26
+ steps:
27
+ - uses: actions/checkout@v4
28
+ - uses: pnpm/action-setup@v4
29
+ name: Install pnpm
30
+ with:
31
+ run_install: false
32
+ version: latest
33
+ - uses: actions/setup-node@v4
34
+ with:
35
+ cache: 'pnpm'
36
+ node-version: 'latest'
37
+ registry-url: 'https://registry.npmjs.org'
38
+ - run: pnpm config delete always-auth
39
+ - run: pnpm i
40
+ env:
41
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
42
+ - run: pnpm build
43
+ - run: pnpm publish --provenance --no-git-checks
@@ -0,0 +1,9 @@
1
+ name: bump version
2
+
3
+ on:
4
+ push:
5
+ branches: '**' # only trigger on branches, not on tags
6
+
7
+ jobs:
8
+ bump:
9
+ uses: esportsplus/typescript/.github/workflows/bump.yml@main
@@ -0,0 +1,12 @@
1
+ name: dependabot automerge
2
+
3
+ on:
4
+ pull_request:
5
+ types: [opened, synchronize, labeled]
6
+ workflow_dispatch:
7
+
8
+ jobs:
9
+ automerge:
10
+ secrets:
11
+ NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
12
+ uses: esportsplus/typescript/.github/workflows/dependabot.yml@main
@@ -0,0 +1,16 @@
1
+ name: publish to npm
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+ workflow_dispatch:
7
+ workflow_run:
8
+ workflows: [bump version]
9
+ types:
10
+ - completed
11
+
12
+ jobs:
13
+ publish:
14
+ secrets:
15
+ NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
16
+ uses: esportsplus/typescript/.github/workflows/publish.yml@main
@@ -0,0 +1,4 @@
1
+ declare const BRACES_CONTENT_REGEX: RegExp;
2
+ declare const REGEX_ESCAPE_PATTERN: RegExp;
3
+ declare const UUID_DASH_REGEX: RegExp;
4
+ export { BRACES_CONTENT_REGEX, REGEX_ESCAPE_PATTERN, UUID_DASH_REGEX };
@@ -0,0 +1,4 @@
1
+ const BRACES_CONTENT_REGEX = /\{([^}]*)\}/;
2
+ const REGEX_ESCAPE_PATTERN = /[.*+?^${}()|[\]\\]/g;
3
+ const UUID_DASH_REGEX = /-/g;
4
+ export { BRACES_CONTENT_REGEX, REGEX_ESCAPE_PATTERN, UUID_DASH_REGEX };
@@ -0,0 +1,13 @@
1
+ import ts from 'typescript';
2
+ import type { ImportModification, NodeMatch, QuickCheckPattern, Replacement, VisitorCallback, VisitorPredicate } from './types.js';
3
+ declare const addImport: (code: string, module: string, specifiers: string[]) => string;
4
+ declare const applyReplacements: (code: string, replacements: Replacement[]) => string;
5
+ declare const applyReplacementsReverse: (code: string, replacements: Replacement[]) => string;
6
+ declare const collectNodes: <T>(sourceFile: ts.SourceFile, predicate: (node: ts.Node) => T | null) => NodeMatch<T>[];
7
+ declare const mightNeedTransform: (code: string, check: QuickCheckPattern) => boolean;
8
+ declare const uid: (prefix?: string) => string;
9
+ declare const updateImports: (code: string, modification: ImportModification) => string;
10
+ declare const visitAst: <T>(sourceFile: ts.SourceFile, callback: VisitorCallback<T>, state: T, predicate?: VisitorPredicate) => T;
11
+ declare const visitAstWithDepth: <T>(sourceFile: ts.SourceFile, callback: (node: ts.Node, depth: number, state: T) => void, state: T, depthTrigger: (node: ts.Node) => boolean) => T;
12
+ export { addImport, applyReplacements, applyReplacementsReverse, collectNodes, mightNeedTransform, uid, updateImports, visitAst, visitAstWithDepth };
13
+ export type { ImportModification, NodeMatch, QuickCheckPattern, Replacement, VisitorCallback, VisitorPredicate };
@@ -0,0 +1,157 @@
1
+ import { uuid } from '@esportsplus/utilities';
2
+ import ts from 'typescript';
3
+ import { BRACES_CONTENT_REGEX, REGEX_ESCAPE_PATTERN, UUID_DASH_REGEX } from './constants.js';
4
+ function buildImportRegex(escapedModule) {
5
+ return new RegExp(`(import\\s*\\{[^}]*\\}\\s*from\\s*['"]${escapedModule}['"])`);
6
+ }
7
+ function mergeAndSort(a, b) {
8
+ let combined = new Array(a.length + b.size), idx = 0, n = a.length;
9
+ for (let i = 0; i < n; i++) {
10
+ if (a[i]) {
11
+ combined[idx++] = a[i];
12
+ }
13
+ }
14
+ for (let item of b) {
15
+ if (item) {
16
+ combined[idx++] = item;
17
+ }
18
+ }
19
+ combined.length = idx;
20
+ combined.sort();
21
+ return combined.join(', ');
22
+ }
23
+ function parseSpecifiers(str) {
24
+ let parts = str.split(','), result = new Set();
25
+ for (let i = 0, n = parts.length; i < n; i++) {
26
+ let trimmed = parts[i].trim();
27
+ if (trimmed) {
28
+ result.add(trimmed);
29
+ }
30
+ }
31
+ return result;
32
+ }
33
+ function updateImportsWithRegex(code, specifiers, importRegex) {
34
+ let match = code.match(importRegex);
35
+ if (!match) {
36
+ return code;
37
+ }
38
+ let bracesMatch = match[1].match(BRACES_CONTENT_REGEX), existing = bracesMatch?.[1] ? parseSpecifiers(bracesMatch[1]) : new Set(), toAdd = [];
39
+ for (let spec of specifiers) {
40
+ if (!existing.has(spec)) {
41
+ toAdd.push(spec);
42
+ }
43
+ }
44
+ if (toAdd.length === 0) {
45
+ return code;
46
+ }
47
+ return code.replace(match[1], match[1].replace(BRACES_CONTENT_REGEX, `{ ${mergeAndSort(toAdd, existing)} }`));
48
+ }
49
+ const addImport = (code, module, specifiers) => {
50
+ if (specifiers.length === 0) {
51
+ return code;
52
+ }
53
+ let regex = buildImportRegex(module.replace(REGEX_ESCAPE_PATTERN, '\\$&'));
54
+ if (regex.test(code)) {
55
+ return updateImportsWithRegex(code, new Set(specifiers), regex);
56
+ }
57
+ let adding = `import { ${specifiers.sort().join(', ')} } from '${module}';\n`, first = code.indexOf('import ');
58
+ if (first === -1) {
59
+ return adding + code;
60
+ }
61
+ return code.substring(0, first) + adding + code.substring(first);
62
+ };
63
+ const applyReplacements = (code, replacements) => {
64
+ if (replacements.length === 0) {
65
+ return code;
66
+ }
67
+ replacements.sort((a, b) => a.start - b.start);
68
+ let parts = [], pos = 0;
69
+ for (let i = 0, n = replacements.length; i < n; i++) {
70
+ let r = replacements[i];
71
+ if (r.start > pos) {
72
+ parts.push(code.substring(pos, r.start));
73
+ }
74
+ parts.push(r.newText);
75
+ pos = r.end;
76
+ }
77
+ if (pos < code.length) {
78
+ parts.push(code.substring(pos));
79
+ }
80
+ return parts.join('');
81
+ };
82
+ const applyReplacementsReverse = (code, replacements) => {
83
+ if (replacements.length === 0) {
84
+ return code;
85
+ }
86
+ replacements.sort((a, b) => b.start - a.start);
87
+ let result = code;
88
+ for (let i = 0, n = replacements.length; i < n; i++) {
89
+ let r = replacements[i];
90
+ result = result.substring(0, r.start) + r.newText + result.substring(r.end);
91
+ }
92
+ return result;
93
+ };
94
+ const collectNodes = (sourceFile, predicate) => {
95
+ let matches = [];
96
+ function visit(node) {
97
+ let data = predicate(node);
98
+ if (data !== null) {
99
+ matches.push({
100
+ data,
101
+ end: node.end,
102
+ node,
103
+ start: node.getStart(sourceFile)
104
+ });
105
+ }
106
+ ts.forEachChild(node, visit);
107
+ }
108
+ visit(sourceFile);
109
+ return matches;
110
+ };
111
+ const mightNeedTransform = (code, check) => {
112
+ if (check.regex) {
113
+ return check.regex.test(code);
114
+ }
115
+ if (check.patterns) {
116
+ for (let i = 0, n = check.patterns.length; i < n; i++) {
117
+ if (code.indexOf(check.patterns[i]) !== -1) {
118
+ return true;
119
+ }
120
+ }
121
+ }
122
+ return false;
123
+ };
124
+ const uid = (prefix) => {
125
+ return (prefix ? prefix + '_' : '_') + uuid().replace(UUID_DASH_REGEX, '_');
126
+ };
127
+ const updateImports = (code, modification) => {
128
+ let { module, specifiers } = modification;
129
+ if (specifiers.size === 0) {
130
+ return code;
131
+ }
132
+ let escapedModule = module.replace(REGEX_ESCAPE_PATTERN, '\\$&'), importRegex = buildImportRegex(escapedModule);
133
+ return updateImportsWithRegex(code, specifiers, importRegex);
134
+ };
135
+ const visitAst = (sourceFile, callback, state, predicate) => {
136
+ function visit(node) {
137
+ if (!predicate || predicate(node)) {
138
+ callback(node, state);
139
+ }
140
+ ts.forEachChild(node, visit);
141
+ }
142
+ visit(sourceFile);
143
+ return state;
144
+ };
145
+ const visitAstWithDepth = (sourceFile, callback, state, depthTrigger) => {
146
+ let depthStack = [0];
147
+ function visit(node) {
148
+ let depth = depthStack[depthStack.length - 1], nextDepth = depthTrigger(node) ? depth + 1 : depth;
149
+ callback(node, depth, state);
150
+ depthStack.push(nextDepth);
151
+ ts.forEachChild(node, visit);
152
+ depthStack.pop();
153
+ }
154
+ visit(sourceFile);
155
+ return state;
156
+ };
157
+ export { addImport, applyReplacements, applyReplacementsReverse, collectNodes, mightNeedTransform, uid, updateImports, visitAst, visitAstWithDepth };
@@ -0,0 +1,23 @@
1
+ import ts from 'typescript';
2
+ type ImportModification = {
3
+ module: string;
4
+ specifiers: Set<string>;
5
+ };
6
+ type NodeMatch<T> = {
7
+ data: T;
8
+ end: number;
9
+ node: ts.Node;
10
+ start: number;
11
+ };
12
+ type QuickCheckPattern = {
13
+ patterns?: string[];
14
+ regex?: RegExp;
15
+ };
16
+ type Replacement = {
17
+ end: number;
18
+ newText: string;
19
+ start: number;
20
+ };
21
+ type VisitorCallback<T> = (node: ts.Node, state: T) => void;
22
+ type VisitorPredicate = (node: ts.Node) => boolean;
23
+ export type { ImportModification, NodeMatch, QuickCheckPattern, Replacement, VisitorCallback, VisitorPredicate };
@@ -0,0 +1 @@
1
+ export {};
package/package.json CHANGED
@@ -5,15 +5,20 @@
5
5
  "tsc-alias": "./bin/tsc-alias"
6
6
  },
7
7
  "dependencies": {
8
- "@esportsplus/cli-passthrough": "^0.0.10",
8
+ "@esportsplus/cli-passthrough": "^0.0.12",
9
+ "@esportsplus/utilities": "^0.27.2",
9
10
  "tsc-alias": "^1.8.16",
10
- "typescript": "^5.8.3"
11
+ "typescript": "^5.9.3"
11
12
  },
12
13
  "exports": {
13
14
  "./package.json": "./package.json",
14
15
  "./tsconfig.browser.json": "./tsconfig.browser.json",
15
16
  "./tsconfig.node.json": "./tsconfig.node.json",
16
17
  "./tsconfig.package.json": "./tsconfig.package.json",
18
+ "./transformer": {
19
+ "types": "./build/transformer/index.d.ts",
20
+ "default": "./build/transformer/index.js"
21
+ },
17
22
  ".": {
18
23
  "types": "./build/index.d.ts",
19
24
  "default": "./build/index.js"
@@ -22,9 +27,13 @@
22
27
  "main": "build/index.js",
23
28
  "name": "@esportsplus/typescript",
24
29
  "private": false,
30
+ "repository": {
31
+ "type": "git",
32
+ "url": "https://github.com/esportsplus/typescript"
33
+ },
25
34
  "type": "module",
26
35
  "types": "build/index.d.ts",
27
- "version": "0.9.2",
36
+ "version": "0.11.0",
28
37
  "scripts": {
29
38
  "build": "tsc && tsc-alias",
30
39
  "-": "-"
@@ -0,0 +1,8 @@
1
+ const BRACES_CONTENT_REGEX = /\{([^}]*)\}/;
2
+
3
+ const REGEX_ESCAPE_PATTERN = /[.*+?^${}()|[\]\\]/g;
4
+
5
+ const UUID_DASH_REGEX = /-/g;
6
+
7
+
8
+ export { BRACES_CONTENT_REGEX, REGEX_ESCAPE_PATTERN, UUID_DASH_REGEX };
@@ -0,0 +1,244 @@
1
+ import { uuid } from '@esportsplus/utilities';
2
+ import ts from 'typescript';
3
+ import { BRACES_CONTENT_REGEX, REGEX_ESCAPE_PATTERN, UUID_DASH_REGEX } from './constants.js';
4
+ import type { ImportModification, NodeMatch, QuickCheckPattern, Replacement, VisitorCallback, VisitorPredicate } from './types.js';
5
+
6
+
7
+ function buildImportRegex(escapedModule: string): RegExp {
8
+ return new RegExp(`(import\\s*\\{[^}]*\\}\\s*from\\s*['"]${escapedModule}['"])`);
9
+ }
10
+
11
+ function mergeAndSort(a: string[], b: Set<string>): string {
12
+ let combined = new Array<string>(a.length + b.size),
13
+ idx = 0,
14
+ n = a.length;
15
+
16
+ for (let i = 0; i < n; i++) {
17
+ if (a[i]) {
18
+ combined[idx++] = a[i];
19
+ }
20
+ }
21
+
22
+ for (let item of b) {
23
+ if (item) {
24
+ combined[idx++] = item;
25
+ }
26
+ }
27
+
28
+ combined.length = idx;
29
+ combined.sort();
30
+
31
+ return combined.join(', ');
32
+ }
33
+
34
+ function parseSpecifiers(str: string): Set<string> {
35
+ let parts = str.split(','),
36
+ result = new Set<string>();
37
+
38
+ for (let i = 0, n = parts.length; i < n; i++) {
39
+ let trimmed = parts[i].trim();
40
+
41
+ if (trimmed) {
42
+ result.add(trimmed);
43
+ }
44
+ }
45
+
46
+ return result;
47
+ }
48
+
49
+ function updateImportsWithRegex(code: string, specifiers: Set<string>, importRegex: RegExp): string {
50
+ let match = code.match(importRegex);
51
+
52
+ if (!match) {
53
+ return code;
54
+ }
55
+
56
+ let bracesMatch = match[1].match(BRACES_CONTENT_REGEX),
57
+ existing = bracesMatch?.[1] ? parseSpecifiers(bracesMatch[1]) : new Set<string>(),
58
+ toAdd: string[] = [];
59
+
60
+ for (let spec of specifiers) {
61
+ if (!existing.has(spec)) {
62
+ toAdd.push(spec);
63
+ }
64
+ }
65
+
66
+ if (toAdd.length === 0) {
67
+ return code;
68
+ }
69
+
70
+ return code.replace(
71
+ match[1],
72
+ match[1].replace(BRACES_CONTENT_REGEX, `{ ${mergeAndSort(toAdd, existing)} }`)
73
+ );
74
+ }
75
+
76
+
77
+ const addImport = (code: string, module: string, specifiers: string[]): string => {
78
+ if (specifiers.length === 0) {
79
+ return code;
80
+ }
81
+
82
+ let regex = buildImportRegex( module.replace(REGEX_ESCAPE_PATTERN, '\\$&') );
83
+
84
+ if (regex.test(code)) {
85
+ return updateImportsWithRegex(code, new Set(specifiers), regex);
86
+ }
87
+
88
+ let adding = `import { ${specifiers.sort().join(', ')} } from '${module}';\n`,
89
+ first = code.indexOf('import ');
90
+
91
+ if (first === -1) {
92
+ return adding + code;
93
+ }
94
+
95
+ return code.substring(0, first) + adding + code.substring(first);
96
+ };
97
+
98
+ const applyReplacements = (code: string, replacements: Replacement[]): string => {
99
+ if (replacements.length === 0) {
100
+ return code;
101
+ }
102
+
103
+ replacements.sort((a, b) => a.start - b.start);
104
+
105
+ let parts: string[] = [],
106
+ pos = 0;
107
+
108
+ for (let i = 0, n = replacements.length; i < n; i++) {
109
+ let r = replacements[i];
110
+
111
+ if (r.start > pos) {
112
+ parts.push(code.substring(pos, r.start));
113
+ }
114
+
115
+ parts.push(r.newText);
116
+ pos = r.end;
117
+ }
118
+
119
+ if (pos < code.length) {
120
+ parts.push(code.substring(pos));
121
+ }
122
+
123
+ return parts.join('');
124
+ };
125
+
126
+ const applyReplacementsReverse = (code: string, replacements: Replacement[]): string => {
127
+ if (replacements.length === 0) {
128
+ return code;
129
+ }
130
+
131
+ replacements.sort((a, b) => b.start - a.start);
132
+
133
+ let result = code;
134
+
135
+ for (let i = 0, n = replacements.length; i < n; i++) {
136
+ let r = replacements[i];
137
+
138
+ result = result.substring(0, r.start) + r.newText + result.substring(r.end);
139
+ }
140
+
141
+ return result;
142
+ };
143
+
144
+ const collectNodes = <T>(sourceFile: ts.SourceFile, predicate: (node: ts.Node) => T | null): NodeMatch<T>[] => {
145
+ let matches: NodeMatch<T>[] = [];
146
+
147
+ function visit(node: ts.Node): void {
148
+ let data = predicate(node);
149
+
150
+ if (data !== null) {
151
+ matches.push({
152
+ data,
153
+ end: node.end,
154
+ node,
155
+ start: node.getStart(sourceFile)
156
+ });
157
+ }
158
+
159
+ ts.forEachChild(node, visit);
160
+ }
161
+
162
+ visit(sourceFile);
163
+
164
+ return matches;
165
+ };
166
+
167
+ const mightNeedTransform = (code: string, check: QuickCheckPattern): boolean => {
168
+ if (check.regex) {
169
+ return check.regex.test(code);
170
+ }
171
+
172
+ if (check.patterns) {
173
+ for (let i = 0, n = check.patterns.length; i < n; i++) {
174
+ if (code.indexOf(check.patterns[i]) !== -1) {
175
+ return true;
176
+ }
177
+ }
178
+ }
179
+
180
+ return false;
181
+ };
182
+
183
+ const uid = (prefix?: string): string => {
184
+ return (prefix ? prefix + '_' : '_') + uuid().replace(UUID_DASH_REGEX, '_');
185
+ };
186
+
187
+ const updateImports = (code: string, modification: ImportModification): string => {
188
+ let { module, specifiers } = modification;
189
+
190
+ if (specifiers.size === 0) {
191
+ return code;
192
+ }
193
+
194
+ let escapedModule = module.replace(REGEX_ESCAPE_PATTERN, '\\$&'),
195
+ importRegex = buildImportRegex(escapedModule);
196
+
197
+ return updateImportsWithRegex(code, specifiers, importRegex);
198
+ };
199
+
200
+ const visitAst = <T>(
201
+ sourceFile: ts.SourceFile,
202
+ callback: VisitorCallback<T>,
203
+ state: T,
204
+ predicate?: VisitorPredicate
205
+ ): T => {
206
+ function visit(node: ts.Node): void {
207
+ if (!predicate || predicate(node)) {
208
+ callback(node, state);
209
+ }
210
+
211
+ ts.forEachChild(node, visit);
212
+ }
213
+
214
+ visit(sourceFile);
215
+
216
+ return state;
217
+ };
218
+
219
+ const visitAstWithDepth = <T>(
220
+ sourceFile: ts.SourceFile,
221
+ callback: (node: ts.Node, depth: number, state: T) => void,
222
+ state: T,
223
+ depthTrigger: (node: ts.Node) => boolean
224
+ ): T => {
225
+ let depthStack: number[] = [0];
226
+
227
+ function visit(node: ts.Node): void {
228
+ let depth = depthStack[depthStack.length - 1],
229
+ nextDepth = depthTrigger(node) ? depth + 1 : depth;
230
+
231
+ callback(node, depth, state);
232
+ depthStack.push(nextDepth);
233
+ ts.forEachChild(node, visit);
234
+ depthStack.pop();
235
+ }
236
+
237
+ visit(sourceFile);
238
+
239
+ return state;
240
+ };
241
+
242
+
243
+ export { addImport, applyReplacements, applyReplacementsReverse, collectNodes, mightNeedTransform, uid, updateImports, visitAst, visitAstWithDepth };
244
+ export type { ImportModification, NodeMatch, QuickCheckPattern, Replacement, VisitorCallback, VisitorPredicate };
@@ -0,0 +1,38 @@
1
+ import ts from 'typescript';
2
+
3
+
4
+ type ImportModification = {
5
+ module: string;
6
+ specifiers: Set<string>;
7
+ };
8
+
9
+ type NodeMatch<T> = {
10
+ data: T;
11
+ end: number;
12
+ node: ts.Node;
13
+ start: number;
14
+ };
15
+
16
+ type QuickCheckPattern = {
17
+ patterns?: string[];
18
+ regex?: RegExp;
19
+ };
20
+
21
+ type Replacement = {
22
+ end: number;
23
+ newText: string;
24
+ start: number;
25
+ };
26
+
27
+ type VisitorCallback<T> = (node: ts.Node, state: T) => void;
28
+
29
+ type VisitorPredicate = (node: ts.Node) => boolean;
30
+
31
+
32
+ export type {
33
+ ImportModification,
34
+ NodeMatch,
35
+ QuickCheckPattern,
36
+ Replacement,
37
+ VisitorCallback, VisitorPredicate
38
+ };