Skip to content

Commit 77d4250

Browse files
committed
generate deparsers
1 parent 580de19 commit 77d4250

File tree

10 files changed

+309
-9
lines changed

10 files changed

+309
-9
lines changed
File renamed without changes.

packages/deparser/scripts/make-fixtures-ast.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import * as fs from 'fs';
44
import { sync as globSync } from 'glob';
55
import { parse } from 'libpg-query';
66
import { ParseResult, RawStmt } from '@pgsql/types';
7-
import { cleanTree } from '../src/utils';
7+
import { cleanTree } from './clean-utils';
88

99
const FIXTURE_DIR = path.join(__dirname, '../../../__fixtures__/legacy');
1010
const OUT_DIR = path.join(__dirname, '../../../__fixtures__/generated/asts');

packages/deparser/scripts/make-fixtures.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import * as path from 'path';
33
import * as fs from 'fs';
44
import { sync as globSync } from 'glob';
55
import { parse } from 'libpg-query';
6-
import { splitStatements, generateStatementKey } from '../src/utils/statement-splitter';
6+
import { splitStatements, generateStatementKey } from './statement-splitter';
77

88
const FIXTURE_DIR = path.join(__dirname, '../../../__fixtures__/kitchen-sink');
99
const OUT_DIR = path.join(__dirname, '../../../__fixtures__/generated');

packages/deparser/scripts/make-upstream-diff.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ import { sync as globSync } from 'glob';
55
import { parse, deparse } from 'libpg-query';
66
import { ParseResult, RawStmt } from '@pgsql/types';
77
import { deparse as ourDeparse } from '../src';
8-
import { cleanTree } from '../src/utils';
9-
import { splitStatements, generateStatementKey } from '../src/utils/statement-splitter';
8+
import { cleanTree } from './clean-utils';
9+
import { splitStatements, generateStatementKey } from './statement-splitter';
1010

1111
const FIXTURE_DIR = path.join(__dirname, '../../../__fixtures__/kitchen-sink');
1212
const OUT_DIR = path.join(__dirname, '../../../__fixtures__/generated');

packages/deparser/test-utils/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { parse } from 'libpg-query';
22
import { deparseSync as deparse, DeparserOptions } from '../src';
3-
import { cleanTree } from '../src/utils';
3+
import { cleanTree } from '../scripts/clean-utils';
44
import { readFileSync } from 'fs';
55
import * as path from 'path';
66
import { expect } from '@jest/globals';

packages/transform/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
"build:proto": "ts-node scripts/pg-proto-parser",
2929
"strip-types": "ts-node scripts/strip-transformer-types.ts",
3030
"strip-direct-types": "ts-node scripts/strip-direct-transformer-types.ts",
31+
"strip-deparser-types": "ts-node scripts/strip-deparser-types.ts",
3132
"strip-all-types": "npm run strip-types && npm run strip-direct-types",
3233
"generate-deparsers": "ts-node scripts/generate-version-deparsers.ts",
3334
"organize-versions": "ts-node scripts/organize-transformers-by-version.ts",

packages/transform/scripts/generate-version-deparsers.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,12 @@ function generateDeparserIndex(config: VersionConfig): string {
4343
* Auto-generated by generate-version-deparsers.ts
4444
*/
4545
46+
import { Node, ParseResult } from '@pgsql/types';
4647
import {
4748
deparse as deparse17,
4849
deparseSync as deparseSync17,
4950
DeparserOptions
50-
} from 'pgsql-deparser';
51-
import { Node, ParseResult } from '@pgsql/types';
51+
} from './deparser';
5252
import { ${config.directTransformerClass} } from '${config.directTransformerFile}';
5353
5454
const tx = new ${config.directTransformerClass}();
@@ -64,7 +64,7 @@ export function deparseSync(query: Node | Node[] | ParseResult, opts?: DeparserO
6464
}
6565
6666
// Re-export DeparserOptions for convenience
67-
export { DeparserOptions } from 'pgsql-deparser';
67+
export { DeparserOptions } from './deparser';
6868
`;
6969
}
7070

packages/transform/scripts/organize-transformers-by-version.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,9 +219,17 @@ function organizeByVersion(): void {
219219

220220
console.log('\nDone! Transformers are organized in version-specific directories.');
221221

222+
// Copy deparser files
223+
console.log('\nCopying deparser files...');
224+
const { execSync } = require('child_process');
225+
try {
226+
execSync('npx ts-node scripts/strip-deparser-types.ts', { stdio: 'inherit' });
227+
} catch (error) {
228+
console.error('Failed to copy deparser files:', error);
229+
}
230+
222231
// Now generate the deparser index files
223232
console.log('\nGenerating deparser index files...');
224-
const { execSync } = require('child_process');
225233
try {
226234
execSync('npx ts-node scripts/generate-version-deparsers.ts', { stdio: 'inherit' });
227235
} catch (error) {
Lines changed: 291 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,291 @@
1+
import * as ts from 'typescript';
2+
import * as fs from 'fs';
3+
import * as path from 'path';
4+
5+
/**
6+
* Script to strip types from deparser files and copy them to version directories
7+
* Replaces @pgsql/types imports and t.* type references with 'any'
8+
*/
9+
10+
const DEPARSER_SRC_DIR = '../deparser/src';
11+
const VERSIONS_DIR = 'versions';
12+
const VERSIONS = [13, 14, 15, 16];
13+
14+
// Types to strip
15+
const TYPES_TO_STRIP = ['Node', '@pgsql/types'];
16+
17+
function stripTypes(sourceFile: ts.SourceFile, fileName: string): string {
18+
const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed });
19+
20+
const transformer: ts.TransformerFactory<ts.SourceFile> = (context) => {
21+
const visit: ts.Visitor = (node) => {
22+
// Remove or modify import declarations
23+
if (ts.isImportDeclaration(node)) {
24+
const moduleSpecifier = node.moduleSpecifier;
25+
if (ts.isStringLiteral(moduleSpecifier)) {
26+
const importPath = moduleSpecifier.text;
27+
28+
// Remove @pgsql/types imports entirely
29+
if (importPath === '@pgsql/types') {
30+
return undefined;
31+
}
32+
}
33+
}
34+
35+
// Replace type references with 'any'
36+
if (ts.isTypeReferenceNode(node)) {
37+
const typeName = node.typeName.getText();
38+
39+
// Replace Node type
40+
if (typeName === 'Node') {
41+
return ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword);
42+
}
43+
44+
// Replace t.* types (e.g., t.SelectStmt, t.A_Const)
45+
if (typeName.startsWith('t.')) {
46+
return ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword);
47+
}
48+
}
49+
50+
// Replace qualified names in property access (e.g., node as t.SelectStmt)
51+
if (ts.isPropertyAccessExpression(node)) {
52+
const expression = node.expression;
53+
if (ts.isIdentifier(expression) && expression.text === 't') {
54+
// This is a t.* reference, but in an expression context
55+
// We'll handle this in type assertions
56+
}
57+
}
58+
59+
// Replace type assertions
60+
if (ts.isAsExpression(node)) {
61+
const typeText = node.type.getText();
62+
63+
// Remove assertions with Node type
64+
if (typeText === 'Node') {
65+
return node.expression;
66+
}
67+
68+
// Remove assertions with t.* types
69+
if (typeText.startsWith('t.')) {
70+
return node.expression;
71+
}
72+
}
73+
74+
// Replace parameter type annotations
75+
if (ts.isParameter(node) && node.type) {
76+
const typeText = node.type.getText();
77+
if (typeText === 'Node' || typeText.startsWith('t.')) {
78+
return ts.factory.updateParameterDeclaration(
79+
node,
80+
node.modifiers,
81+
node.dotDotDotToken,
82+
node.name,
83+
node.questionToken,
84+
ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword),
85+
node.initializer
86+
);
87+
}
88+
}
89+
90+
// Replace variable type annotations
91+
if (ts.isVariableDeclaration(node) && node.type) {
92+
const typeText = node.type.getText();
93+
if (typeText === 'Node' || typeText.startsWith('t.')) {
94+
return ts.factory.updateVariableDeclaration(
95+
node,
96+
node.name,
97+
node.exclamationToken,
98+
ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword),
99+
node.initializer
100+
);
101+
}
102+
}
103+
104+
// Replace return type annotations
105+
if ((ts.isMethodDeclaration(node) || ts.isFunctionDeclaration(node) || ts.isArrowFunction(node)) && node.type) {
106+
const typeText = node.type.getText();
107+
if (typeText === 'Node' || typeText.startsWith('t.')) {
108+
if (ts.isMethodDeclaration(node)) {
109+
return ts.factory.updateMethodDeclaration(
110+
node,
111+
node.modifiers,
112+
node.asteriskToken,
113+
node.name,
114+
node.questionToken,
115+
node.typeParameters,
116+
node.parameters,
117+
ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword),
118+
node.body
119+
);
120+
} else if (ts.isFunctionDeclaration(node)) {
121+
return ts.factory.updateFunctionDeclaration(
122+
node,
123+
node.modifiers,
124+
node.asteriskToken,
125+
node.name,
126+
node.typeParameters,
127+
node.parameters,
128+
ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword),
129+
node.body
130+
);
131+
} else if (ts.isArrowFunction(node)) {
132+
return ts.factory.updateArrowFunction(
133+
node,
134+
node.modifiers,
135+
node.typeParameters,
136+
node.parameters,
137+
ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword),
138+
node.equalsGreaterThanToken,
139+
node.body
140+
);
141+
}
142+
}
143+
}
144+
145+
// Handle property declarations with types
146+
if (ts.isPropertyDeclaration(node) && node.type) {
147+
const typeText = node.type.getText();
148+
if (typeText === 'Node' || typeText.startsWith('t.')) {
149+
return ts.factory.updatePropertyDeclaration(
150+
node,
151+
node.modifiers,
152+
node.name,
153+
node.questionToken || node.exclamationToken,
154+
ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword),
155+
node.initializer
156+
);
157+
}
158+
}
159+
160+
// Handle interface declarations - convert to type alias with any
161+
if (ts.isInterfaceDeclaration(node)) {
162+
// Skip interfaces that extend from @pgsql/types
163+
const hasTypesExtension = node.heritageClauses?.some(clause =>
164+
clause.types.some(type => {
165+
const typeText = type.expression.getText();
166+
return typeText.startsWith('t.') || typeText === 'Node';
167+
})
168+
);
169+
170+
if (hasTypesExtension) {
171+
// Convert interface to type alias = any
172+
return ts.factory.createTypeAliasDeclaration(
173+
node.modifiers,
174+
node.name,
175+
node.typeParameters,
176+
ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)
177+
);
178+
}
179+
}
180+
181+
return ts.visitEachChild(node, visit, context);
182+
};
183+
184+
return (node) => ts.visitNode(node, visit) as ts.SourceFile;
185+
};
186+
187+
const result = ts.transform(sourceFile, [transformer]);
188+
const transformedSourceFile = result.transformed[0];
189+
190+
let code = printer.printFile(transformedSourceFile);
191+
192+
// Post-process to clean up any remaining type references
193+
// Remove any remaining 'as t.*' patterns
194+
code = code.replace(/\s+as\s+t\.[A-Za-z_]+/g, '');
195+
196+
// Remove any remaining 'as Node' patterns
197+
code = code.replace(/\s+as\s+Node/g, '');
198+
199+
// Add header comment
200+
const headerComment = `/**
201+
* Auto-generated file with types stripped for better tree-shaking
202+
* DO NOT EDIT - Generated by strip-deparser-types.ts
203+
*/
204+
205+
`;
206+
207+
return headerComment + code;
208+
}
209+
210+
function processFile(filePath: string, relativePath: string): string {
211+
console.log(` Processing ${relativePath}...`);
212+
213+
const sourceCode = fs.readFileSync(filePath, 'utf-8');
214+
215+
const sourceFile = ts.createSourceFile(
216+
filePath,
217+
sourceCode,
218+
ts.ScriptTarget.Latest,
219+
true
220+
);
221+
222+
return stripTypes(sourceFile, filePath);
223+
}
224+
225+
function copyDeparserToVersions(): void {
226+
console.log('Stripping types from deparser files and copying to version directories...\n');
227+
228+
const deparserSrcPath = path.join(process.cwd(), DEPARSER_SRC_DIR);
229+
230+
if (!fs.existsSync(deparserSrcPath)) {
231+
console.error(`Deparser source directory not found: ${deparserSrcPath}`);
232+
return;
233+
}
234+
235+
// Get all TypeScript files in deparser src
236+
const files: string[] = [];
237+
238+
function collectFiles(dir: string, baseDir: string = '') {
239+
const entries = fs.readdirSync(dir, { withFileTypes: true });
240+
241+
for (const entry of entries) {
242+
const fullPath = path.join(dir, entry.name);
243+
const relativePath = path.join(baseDir, entry.name);
244+
245+
if (entry.isDirectory()) {
246+
collectFiles(fullPath, relativePath);
247+
} else if (entry.isFile() && entry.name.endsWith('.ts')) {
248+
files.push(relativePath);
249+
}
250+
}
251+
}
252+
253+
collectFiles(deparserSrcPath);
254+
255+
console.log(`Found ${files.length} TypeScript files in deparser src\n`);
256+
257+
// Process each version
258+
for (const version of VERSIONS) {
259+
console.log(`Processing version ${version}...`);
260+
261+
const versionDeparserDir = path.join(VERSIONS_DIR, version.toString(), 'deparser');
262+
263+
// Create deparser directory
264+
if (!fs.existsSync(versionDeparserDir)) {
265+
fs.mkdirSync(versionDeparserDir, { recursive: true });
266+
}
267+
268+
// Process and copy each file
269+
for (const file of files) {
270+
const sourcePath = path.join(deparserSrcPath, file);
271+
const destPath = path.join(versionDeparserDir, file);
272+
273+
// Create subdirectories if needed
274+
const destDir = path.dirname(destPath);
275+
if (!fs.existsSync(destDir)) {
276+
fs.mkdirSync(destDir, { recursive: true });
277+
}
278+
279+
// Process and write file
280+
const strippedCode = processFile(sourcePath, file);
281+
fs.writeFileSync(destPath, strippedCode);
282+
}
283+
284+
console.log(` ✓ Copied ${files.length} files to versions/${version}/deparser/\n`);
285+
}
286+
287+
console.log('Done! Deparser files have been stripped and copied to all version directories.');
288+
}
289+
290+
// Run the script
291+
copyDeparserToVersions();

0 commit comments

Comments
 (0)