Skip to content

Commit 8e624a0

Browse files
committed
templates
1 parent dd1e585 commit 8e624a0

30 files changed

+921
-5
lines changed

README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,18 @@ pnpm run test
185185
- Ensure Emscripten SDK is properly installed and configured
186186
- Check that all required build dependencies are available
187187

188+
### Template System
189+
190+
To avoid duplication across PostgreSQL versions, common files are maintained in the `templates/` directory:
191+
- `LICENSE`, `Makefile`, `src/index.ts`, `src/libpg-query.d.ts`, `src/wasm_wrapper.c`
192+
193+
To update version-specific files from templates:
194+
```bash
195+
npm run copy:templates
196+
```
197+
198+
This ensures consistency while allowing version-specific customizations (e.g., patches for version 13).
199+
188200
### Build Artifacts
189201

190202
The build process generates these files:

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
"publish:enums": "node scripts/publish-enums.js",
2424
"publish:versions": "node scripts/publish-versions.js",
2525
"update:versions-types": "node scripts/update-versions-types.js",
26+
"copy:templates": "node scripts/copy-templates.js",
2627
"build:parser": "pnpm --filter @pgsql/parser build",
2728
"build:parser:lts": "PARSER_BUILD_TYPE=lts pnpm --filter @pgsql/parser build",
2829
"build:parser:full": "PARSER_BUILD_TYPE=full pnpm --filter @pgsql/parser build",

scripts/README.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# Scripts Directory
2+
3+
This directory contains various build and maintenance scripts for the libpg-query monorepo.
4+
5+
## Scripts
6+
7+
### copy-templates.js
8+
9+
Copies template files from the `templates/` directory to each PostgreSQL version directory.
10+
11+
**Usage:**
12+
```bash
13+
npm run copy:templates
14+
```
15+
16+
**Features:**
17+
- Processes template placeholders (e.g., `{{LIBPG_QUERY_TAG}}`)
18+
- Handles conditional blocks using mustache-like syntax
19+
- Adds auto-generated headers to source files
20+
- Maintains version-specific configurations
21+
22+
**Version Configurations:**
23+
- Version 13: Uses emscripten patch (`useEmscriptenPatch: true`)
24+
- Versions 14-17: No special patches
25+
26+
### Other Scripts
27+
28+
- `analyze-sizes.js` - Analyzes build artifact sizes
29+
- `fetch-protos.js` - Fetches protocol buffer definitions
30+
- `build-types.js` - Builds TypeScript type definitions
31+
- `prepare-types.js` - Prepares type definitions for publishing
32+
- `build-enums.js` - Builds enum definitions
33+
- `prepare-enums.js` - Prepares enum definitions for publishing
34+
- `publish-types.js` - Publishes @pgsql/types package
35+
- `publish-enums.js` - Publishes @pgsql/enums package
36+
- `publish-versions.js` - Publishes version-specific packages
37+
- `update-versions-types.js` - Updates type dependencies in version packages

scripts/copy-templates.js

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
#!/usr/bin/env node
2+
3+
const fs = require('fs');
4+
const path = require('path');
5+
6+
// Version configurations
7+
const VERSION_CONFIGS = {
8+
'13': {
9+
libpgQueryTag: '13-2.2.0',
10+
useEmscriptenPatch: true
11+
},
12+
'14': {
13+
libpgQueryTag: '14-3.0.0',
14+
useEmscriptenPatch: false
15+
},
16+
'15': {
17+
libpgQueryTag: '15-4.2.4',
18+
useEmscriptenPatch: false
19+
},
20+
'16': {
21+
libpgQueryTag: '16-5.2.0',
22+
useEmscriptenPatch: false
23+
},
24+
'17': {
25+
libpgQueryTag: '17-6.1.0',
26+
useEmscriptenPatch: false
27+
}
28+
};
29+
30+
// Headers for different file types
31+
const HEADERS = {
32+
// JavaScript/TypeScript/C style comment
33+
default: `/**
34+
* DO NOT MODIFY MANUALLY — this is generated from the templates dir
35+
*
36+
* To make changes, edit the files in the templates/ directory and run:
37+
* npm run copy:templates
38+
*/
39+
40+
`,
41+
// Makefile style comment
42+
makefile: `# DO NOT MODIFY MANUALLY — this is generated from the templates dir
43+
#
44+
# To make changes, edit the files in the templates/ directory and run:
45+
# npm run copy:templates
46+
47+
`
48+
};
49+
50+
// File extensions that should get headers
51+
const HEADER_EXTENSIONS = ['.ts', '.js', '.c'];
52+
const MAKEFILE_NAMES = ['Makefile', 'makefile'];
53+
54+
/**
55+
* Process template content with simple mustache-like syntax
56+
* @param {string} content - Template content
57+
* @param {object} config - Configuration object
58+
* @returns {string} Processed content
59+
*/
60+
function processTemplate(content, config) {
61+
// Replace simple variables
62+
content = content.replace(/\{\{LIBPG_QUERY_TAG\}\}/g, config.libpgQueryTag);
63+
64+
// Handle conditional blocks
65+
// {{#USE_EMSCRIPTEN_PATCH}}...{{/USE_EMSCRIPTEN_PATCH}}
66+
const conditionalRegex = /\{\{#(\w+)\}\}([\s\S]*?)\{\{\/\1\}\}/g;
67+
68+
content = content.replace(conditionalRegex, (match, flag, blockContent) => {
69+
if (flag === 'USE_EMSCRIPTEN_PATCH' && config.useEmscriptenPatch) {
70+
return blockContent;
71+
}
72+
return '';
73+
});
74+
75+
return content;
76+
}
77+
78+
/**
79+
* Add header to file content if applicable
80+
* @param {string} filePath - Path to the file
81+
* @param {string} content - File content
82+
* @returns {string} Content with header if applicable
83+
*/
84+
function addHeaderIfNeeded(filePath, content) {
85+
const basename = path.basename(filePath);
86+
const ext = path.extname(filePath);
87+
88+
// Check if it's a Makefile
89+
if (MAKEFILE_NAMES.includes(basename)) {
90+
return HEADERS.makefile + content;
91+
}
92+
93+
// Check if it's a source file that needs a header
94+
if (HEADER_EXTENSIONS.includes(ext)) {
95+
return HEADERS.default + content;
96+
}
97+
98+
return content;
99+
}
100+
101+
/**
102+
* Copy a file from template to destination with processing
103+
* @param {string} templatePath - Source template path
104+
* @param {string} destPath - Destination path
105+
* @param {object} config - Version configuration
106+
*/
107+
function copyTemplate(templatePath, destPath, config) {
108+
const content = fs.readFileSync(templatePath, 'utf8');
109+
const processedContent = processTemplate(content, config);
110+
const finalContent = addHeaderIfNeeded(destPath, processedContent);
111+
112+
// Ensure destination directory exists
113+
const destDir = path.dirname(destPath);
114+
if (!fs.existsSync(destDir)) {
115+
fs.mkdirSync(destDir, { recursive: true });
116+
}
117+
118+
fs.writeFileSync(destPath, finalContent);
119+
}
120+
121+
/**
122+
* Copy all templates for a specific version
123+
* @param {string} version - Version number
124+
* @param {object} config - Version configuration
125+
*/
126+
function copyTemplatesForVersion(version, config) {
127+
const templatesDir = path.join(__dirname, '..', 'templates');
128+
const versionDir = path.join(__dirname, '..', 'versions', version);
129+
130+
// Check if version directory exists
131+
if (!fs.existsSync(versionDir)) {
132+
console.warn(`Warning: Directory ${versionDir} does not exist. Skipping...`);
133+
return;
134+
}
135+
136+
// Files to copy
137+
const filesToCopy = [
138+
'LICENSE',
139+
'Makefile',
140+
'src/index.ts',
141+
'src/libpg-query.d.ts',
142+
'src/wasm_wrapper.c'
143+
];
144+
145+
filesToCopy.forEach(file => {
146+
const templatePath = path.join(templatesDir, file);
147+
const destPath = path.join(versionDir, file);
148+
149+
if (!fs.existsSync(templatePath)) {
150+
console.error(`Error: Template file ${templatePath} does not exist!`);
151+
return;
152+
}
153+
154+
copyTemplate(templatePath, destPath, config);
155+
});
156+
157+
console.log(`✓ Version ${version} completed`);
158+
}
159+
160+
/**
161+
* Main function
162+
*/
163+
function main() {
164+
console.log('Copying template files to version directories...\n');
165+
166+
// Process each version
167+
Object.entries(VERSION_CONFIGS).forEach(([version, config]) => {
168+
console.log(`Processing version ${version}...`);
169+
copyTemplatesForVersion(version, config);
170+
});
171+
172+
console.log('\nAll versions processed successfully!');
173+
}
174+
175+
// Run if called directly
176+
if (require.main === module) {
177+
main();
178+
}
179+
180+
module.exports = { processTemplate, copyTemplatesForVersion };

templates/LICENSE

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
The MIT License (MIT)
2+
3+
Copyright (c) 2021 Dan Lynch <[email protected]>
4+
Copyright (c) 2025 Interweb, Inc. <[email protected]>
5+
6+
Permission is hereby granted, free of charge, to any person obtaining a copy
7+
of this software and associated documentation files (the "Software"), to deal
8+
in the Software without restriction, including without limitation the rights
9+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
copies of the Software, and to permit persons to whom the Software is
11+
furnished to do so, subject to the following conditions:
12+
13+
The above copyright notice and this permission notice shall be included in all
14+
copies or substantial portions of the Software.
15+
16+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+
SOFTWARE.

templates/Makefile

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
WASM_OUT_DIR := wasm
2+
WASM_OUT_NAME := libpg-query
3+
WASM_MODULE_NAME := PgQueryModule
4+
LIBPG_QUERY_REPO := https://github.com/pganalyze/libpg_query.git
5+
LIBPG_QUERY_TAG := {{LIBPG_QUERY_TAG}}
6+
7+
CACHE_DIR := .cache
8+
9+
OS ?= $(shell uname -s)
10+
ARCH ?= $(shell uname -m)
11+
12+
ifdef EMSCRIPTEN
13+
PLATFORM := emscripten
14+
else ifeq ($(OS),Darwin)
15+
PLATFORM := darwin
16+
else ifeq ($(OS),Linux)
17+
PLATFORM := linux
18+
else
19+
$(error Unsupported platform: $(OS))
20+
endif
21+
22+
ifdef EMSCRIPTEN
23+
ARCH := wasm
24+
endif
25+
26+
PLATFORM_ARCH := $(PLATFORM)-$(ARCH)
27+
SRC_FILES := src/wasm_wrapper.c
28+
LIBPG_QUERY_DIR := $(CACHE_DIR)/$(PLATFORM_ARCH)/libpg_query/$(LIBPG_QUERY_TAG)
29+
LIBPG_QUERY_ARCHIVE := $(LIBPG_QUERY_DIR)/libpg_query.a
30+
LIBPG_QUERY_HEADER := $(LIBPG_QUERY_DIR)/pg_query.h
31+
CXXFLAGS := -O3 -flto
32+
33+
ifdef EMSCRIPTEN
34+
OUT_FILES := $(foreach EXT,.js .wasm,$(WASM_OUT_DIR)/$(WASM_OUT_NAME)$(EXT))
35+
else
36+
$(error Native builds are no longer supported. Use EMSCRIPTEN=1 for WASM builds only.)
37+
endif
38+
39+
# Clone libpg_query source (lives in CACHE_DIR)
40+
$(LIBPG_QUERY_DIR):
41+
mkdir -p $(CACHE_DIR)
42+
git clone -b $(LIBPG_QUERY_TAG) --single-branch $(LIBPG_QUERY_REPO) $(LIBPG_QUERY_DIR)
43+
{{#USE_EMSCRIPTEN_PATCH}}
44+
ifdef EMSCRIPTEN
45+
cd $(LIBPG_QUERY_DIR); patch -p1 < $(shell pwd)/patches/emscripten_disable_spinlocks.patch
46+
endif
47+
{{/USE_EMSCRIPTEN_PATCH}}
48+
49+
$(LIBPG_QUERY_HEADER): $(LIBPG_QUERY_DIR)
50+
51+
# Build libpg_query
52+
$(LIBPG_QUERY_ARCHIVE): $(LIBPG_QUERY_DIR)
53+
cd $(LIBPG_QUERY_DIR); $(MAKE) build
54+
55+
# Build libpg-query-node WASM module
56+
$(OUT_FILES): $(LIBPG_QUERY_ARCHIVE) $(LIBPG_QUERY_HEADER) $(SRC_FILES)
57+
ifdef EMSCRIPTEN
58+
mkdir -p $(WASM_OUT_DIR)
59+
$(CC) \
60+
-v \
61+
$(CXXFLAGS) \
62+
-I$(LIBPG_QUERY_DIR) \
63+
-I$(LIBPG_QUERY_DIR)/vendor \
64+
-L$(LIBPG_QUERY_DIR) \
65+
-sEXPORTED_FUNCTIONS="['_malloc','_free','_wasm_parse_query','_wasm_free_string','_wasm_parse_query_raw','_wasm_free_parse_result']" \
66+
-sEXPORTED_RUNTIME_METHODS="['lengthBytesUTF8','stringToUTF8','getValue','UTF8ToString','HEAPU8','HEAPU32']" \
67+
-sEXPORT_NAME="$(WASM_MODULE_NAME)" \
68+
-sENVIRONMENT="web,node" \
69+
-sMODULARIZE=1 \
70+
-sEXPORT_ES6=0 \
71+
-sALLOW_MEMORY_GROWTH=1 \
72+
-lpg_query \
73+
-o $@ \
74+
$(SRC_FILES)
75+
else
76+
$(error Native builds are no longer supported. Use EMSCRIPTEN=1 for WASM builds only.)
77+
endif
78+
79+
# Commands
80+
build: $(OUT_FILES)
81+
82+
build-cache: $(LIBPG_QUERY_ARCHIVE) $(LIBPG_QUERY_HEADER)
83+
84+
rebuild: clean build
85+
86+
rebuild-cache: clean-cache build-cache
87+
88+
clean:
89+
-@ rm -r $(OUT_FILES) > /dev/null 2>&1
90+
91+
clean-cache:
92+
-@ rm -rf $(LIBPG_QUERY_DIR)
93+
94+
.PHONY: build build-cache rebuild rebuild-cache clean clean-cache

0 commit comments

Comments
 (0)