@noormdev/sdk 1.0.0-alpha.8 → 1.0.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.
- package/LICENSE +21 -0
- package/README.md +81 -0
- package/dist/chunk-2RW4SL2O.js +97664 -0
- package/dist/chunk-D2XW2UOP.js +42 -0
- package/dist/chunk-DSXHOXDE.js +2591 -0
- package/dist/chunk-QAECL4RN.js +3372 -0
- package/dist/chunk-SPU42W75.js +13779 -0
- package/dist/chunk-TBRUDUBQ.js +1099 -0
- package/dist/chunk-UOFJT5PY.js +1499 -0
- package/dist/chunk-YJBKNUTP.js +7233 -0
- package/dist/csv-T5P3IN4K.js +7 -0
- package/dist/engine-S4DX3V33.js +11 -0
- package/dist/index.d.ts +3967 -1315
- package/dist/index.js +13771 -6150
- package/dist/json5-LNT3RGJ7.js +7 -0
- package/dist/mssql-NL6OHOMO.js +161 -0
- package/dist/{mysql-C2DR4TF7.js → mysql-5P43DYBY.js} +7 -4
- package/dist/{postgres-SIDJBSIT.js → postgres-NIL5BE3O.js} +7 -4
- package/dist/{sqlite-5VZTBN5J.js → sqlite-F3ZSSDUM.js} +5 -3
- package/dist/sqlite-bun-LMHUMGQI.js +60 -0
- package/dist/storage-6QBJ55SB.js +8 -0
- package/dist/yaml-XI7RQ2D5.js +7 -0
- package/package.json +5 -4
- package/dist/chunk-HMKJXT3X.js +0 -299
- package/dist/chunk-HMKJXT3X.js.map +0 -1
- package/dist/engine-IRI22LUB.js +0 -3
- package/dist/engine-IRI22LUB.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/mssql-T4M7OGEC.js +0 -46
- package/dist/mssql-T4M7OGEC.js.map +0 -1
- package/dist/mysql-C2DR4TF7.js.map +0 -1
- package/dist/postgres-SIDJBSIT.js.map +0 -1
- package/dist/sqlite-5VZTBN5J.js.map +0 -1
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { createRequire } from 'module';
|
|
2
|
+
import { DEFAULT_PORTS } from './chunk-SPU42W75.js';
|
|
3
|
+
import './chunk-D2XW2UOP.js';
|
|
4
|
+
import { isIP } from 'net';
|
|
5
|
+
import { Kysely, MssqlDialect, sql, OperationNodeTransformer } from 'kysely';
|
|
6
|
+
|
|
7
|
+
createRequire(import.meta.url);
|
|
8
|
+
var LimitToTopTransformer = class extends OperationNodeTransformer {
|
|
9
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
10
|
+
transformSelectQuery(node) {
|
|
11
|
+
const transformed = super.transformSelectQuery(node);
|
|
12
|
+
if (!transformed.limit || transformed.top) {
|
|
13
|
+
return transformed;
|
|
14
|
+
}
|
|
15
|
+
const limitOp = transformed.limit.limit;
|
|
16
|
+
let value;
|
|
17
|
+
if (limitOp?.kind === "ValueNode" && (typeof limitOp.value === "number" || typeof limitOp.value === "bigint")) {
|
|
18
|
+
value = limitOp.value;
|
|
19
|
+
}
|
|
20
|
+
if (value === void 0) {
|
|
21
|
+
return transformed;
|
|
22
|
+
}
|
|
23
|
+
return {
|
|
24
|
+
...transformed,
|
|
25
|
+
limit: void 0,
|
|
26
|
+
top: {
|
|
27
|
+
kind: "TopNode",
|
|
28
|
+
expression: value
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
var MssqlLimitPlugin = class {
|
|
34
|
+
#transformer = new LimitToTopTransformer();
|
|
35
|
+
transformQuery(args) {
|
|
36
|
+
return this.#transformer.transformNode(args.node);
|
|
37
|
+
}
|
|
38
|
+
async transformResult(args) {
|
|
39
|
+
return args.result;
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
// src/core/connection/dialects/mssql.ts
|
|
44
|
+
var UNVERIFIED_TLS_SERVER_NAME = "noorm-unverified.invalid";
|
|
45
|
+
var MssqlTlsServerNameError = class extends Error {
|
|
46
|
+
constructor(host, message) {
|
|
47
|
+
super(message);
|
|
48
|
+
this.host = host;
|
|
49
|
+
}
|
|
50
|
+
name = "MssqlTlsServerNameError";
|
|
51
|
+
};
|
|
52
|
+
function resolveTlsServerName(config) {
|
|
53
|
+
const host = config.host ?? "localhost";
|
|
54
|
+
const supplied = config.tlsServerName;
|
|
55
|
+
const validatingCertificate = !!config.ssl;
|
|
56
|
+
if (supplied && isIP(supplied) !== 0) {
|
|
57
|
+
throw new MssqlTlsServerNameError(
|
|
58
|
+
host,
|
|
59
|
+
`Invalid tlsServerName '${supplied}': a TLS ServerName must be a hostname, not an IP address. Set it to the hostname the server's certificate is issued for.`
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
if (supplied) {
|
|
63
|
+
return supplied;
|
|
64
|
+
}
|
|
65
|
+
if (isIP(host) === 0) {
|
|
66
|
+
return void 0;
|
|
67
|
+
}
|
|
68
|
+
if (validatingCertificate) {
|
|
69
|
+
throw new MssqlTlsServerNameError(
|
|
70
|
+
host,
|
|
71
|
+
`Cannot verify the TLS certificate of MSSQL host '${host}': a certificate cannot be validated against an IP address, because TLS forbids sending one as the ServerName. Set connection.tlsServerName to the hostname the server's certificate is issued for, or connect using that hostname instead.`
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
return UNVERIFIED_TLS_SERVER_NAME;
|
|
75
|
+
}
|
|
76
|
+
function buildTediousOptions(config, database) {
|
|
77
|
+
return {
|
|
78
|
+
server: config.host ?? "localhost",
|
|
79
|
+
authentication: {
|
|
80
|
+
type: "default",
|
|
81
|
+
options: {
|
|
82
|
+
userName: config.user,
|
|
83
|
+
password: config.password
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
options: {
|
|
87
|
+
port: config.port ?? DEFAULT_PORTS.mssql,
|
|
88
|
+
database: database ?? config.database,
|
|
89
|
+
trustServerCertificate: !config.ssl,
|
|
90
|
+
encrypt: true,
|
|
91
|
+
serverName: resolveTlsServerName(config)
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
function buildTediousConfig(Tedious, config, database) {
|
|
96
|
+
return new Tedious.Connection(buildTediousOptions(config, database));
|
|
97
|
+
}
|
|
98
|
+
async function verifyDatabaseExists(Tedious, Tarn, config) {
|
|
99
|
+
const masterDb = new Kysely({
|
|
100
|
+
dialect: new MssqlDialect({
|
|
101
|
+
tarn: {
|
|
102
|
+
...Tarn,
|
|
103
|
+
options: {
|
|
104
|
+
min: 0,
|
|
105
|
+
max: 1,
|
|
106
|
+
propagateCreateError: true
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
tedious: {
|
|
110
|
+
...Tedious,
|
|
111
|
+
connectionFactory: () => buildTediousConfig(Tedious, config, "master")
|
|
112
|
+
}
|
|
113
|
+
}),
|
|
114
|
+
plugins: [new MssqlLimitPlugin()]
|
|
115
|
+
});
|
|
116
|
+
try {
|
|
117
|
+
const { rows } = await sql`
|
|
118
|
+
SELECT name FROM sys.databases WHERE name = ${config.database}
|
|
119
|
+
`.execute(masterDb);
|
|
120
|
+
if (rows.length === 0) {
|
|
121
|
+
throw new Error(
|
|
122
|
+
`Database '${config.database}' does not exist on ${config.host ?? "localhost"}:${config.port ?? DEFAULT_PORTS.mssql}`
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
} finally {
|
|
126
|
+
await masterDb.destroy();
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
async function createMssqlConnection(config) {
|
|
130
|
+
const TediousImport = await import('tedious');
|
|
131
|
+
const TarnImport = await import('tarn');
|
|
132
|
+
const Tedious = TediousImport.default ?? TediousImport;
|
|
133
|
+
const Tarn = TarnImport.default ?? TarnImport;
|
|
134
|
+
await verifyDatabaseExists(Tedious, Tarn, config);
|
|
135
|
+
const db = new Kysely({
|
|
136
|
+
dialect: new MssqlDialect({
|
|
137
|
+
tarn: {
|
|
138
|
+
...Tarn,
|
|
139
|
+
options: {
|
|
140
|
+
min: config.pool?.min ?? 0,
|
|
141
|
+
max: config.pool?.max ?? 10,
|
|
142
|
+
propagateCreateError: true
|
|
143
|
+
}
|
|
144
|
+
},
|
|
145
|
+
tedious: {
|
|
146
|
+
...Tedious,
|
|
147
|
+
connectionFactory: () => buildTediousConfig(Tedious, config)
|
|
148
|
+
}
|
|
149
|
+
}),
|
|
150
|
+
plugins: [new MssqlLimitPlugin()]
|
|
151
|
+
});
|
|
152
|
+
return {
|
|
153
|
+
db,
|
|
154
|
+
dialect: "mssql",
|
|
155
|
+
destroy: () => db.destroy()
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export { MssqlTlsServerNameError, UNVERIFIED_TLS_SERVER_NAME, buildTediousOptions, createMssqlConnection, resolveTlsServerName };
|
|
160
|
+
//# sourceMappingURL=mssql-NL6OHOMO.js.map
|
|
161
|
+
//# sourceMappingURL=mssql-NL6OHOMO.js.map
|
|
@@ -1,12 +1,15 @@
|
|
|
1
|
+
import { createRequire } from 'module';
|
|
2
|
+
import { DEFAULT_PORTS } from './chunk-SPU42W75.js';
|
|
3
|
+
import './chunk-D2XW2UOP.js';
|
|
1
4
|
import { Kysely, MysqlDialect } from 'kysely';
|
|
2
5
|
|
|
3
|
-
|
|
6
|
+
createRequire(import.meta.url);
|
|
4
7
|
async function createMysqlConnection(config) {
|
|
5
8
|
const mysql2 = await import('mysql2');
|
|
6
9
|
const createPool = mysql2.default?.createPool ?? mysql2.createPool;
|
|
7
10
|
const pool = createPool({
|
|
8
11
|
host: config.host ?? "localhost",
|
|
9
|
-
port: config.port ??
|
|
12
|
+
port: config.port ?? DEFAULT_PORTS.mysql,
|
|
10
13
|
user: config.user,
|
|
11
14
|
password: config.password,
|
|
12
15
|
database: config.database,
|
|
@@ -24,5 +27,5 @@ async function createMysqlConnection(config) {
|
|
|
24
27
|
}
|
|
25
28
|
|
|
26
29
|
export { createMysqlConnection };
|
|
27
|
-
//# sourceMappingURL=mysql-
|
|
28
|
-
//# sourceMappingURL=mysql-
|
|
30
|
+
//# sourceMappingURL=mysql-5P43DYBY.js.map
|
|
31
|
+
//# sourceMappingURL=mysql-5P43DYBY.js.map
|
|
@@ -1,12 +1,15 @@
|
|
|
1
|
+
import { createRequire } from 'module';
|
|
2
|
+
import { DEFAULT_PORTS } from './chunk-SPU42W75.js';
|
|
3
|
+
import './chunk-D2XW2UOP.js';
|
|
1
4
|
import { Kysely, PostgresDialect } from 'kysely';
|
|
2
5
|
|
|
3
|
-
|
|
6
|
+
createRequire(import.meta.url);
|
|
4
7
|
async function createPostgresConnection(config) {
|
|
5
8
|
const pg = await import('pg');
|
|
6
9
|
const Pool = pg.default?.Pool ?? pg.Pool;
|
|
7
10
|
const pool = new Pool({
|
|
8
11
|
host: config.host ?? "localhost",
|
|
9
|
-
port: config.port ??
|
|
12
|
+
port: config.port ?? DEFAULT_PORTS.postgres,
|
|
10
13
|
user: config.user,
|
|
11
14
|
password: config.password,
|
|
12
15
|
database: config.database,
|
|
@@ -25,5 +28,5 @@ async function createPostgresConnection(config) {
|
|
|
25
28
|
}
|
|
26
29
|
|
|
27
30
|
export { createPostgresConnection };
|
|
28
|
-
//# sourceMappingURL=postgres-
|
|
29
|
-
//# sourceMappingURL=postgres-
|
|
31
|
+
//# sourceMappingURL=postgres-NIL5BE3O.js.map
|
|
32
|
+
//# sourceMappingURL=postgres-NIL5BE3O.js.map
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
import { createRequire } from 'module';
|
|
2
|
+
import './chunk-D2XW2UOP.js';
|
|
1
3
|
import { Kysely, SqliteDialect } from 'kysely';
|
|
2
4
|
import Database from 'better-sqlite3';
|
|
3
5
|
|
|
4
|
-
|
|
6
|
+
createRequire(import.meta.url);
|
|
5
7
|
function createSqliteConnection(config) {
|
|
6
8
|
const filename = config.filename ?? config.database;
|
|
7
9
|
const db = new Kysely({
|
|
@@ -17,5 +19,5 @@ function createSqliteConnection(config) {
|
|
|
17
19
|
}
|
|
18
20
|
|
|
19
21
|
export { createSqliteConnection };
|
|
20
|
-
//# sourceMappingURL=sqlite-
|
|
21
|
-
//# sourceMappingURL=sqlite-
|
|
22
|
+
//# sourceMappingURL=sqlite-F3ZSSDUM.js.map
|
|
23
|
+
//# sourceMappingURL=sqlite-F3ZSSDUM.js.map
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { createRequire } from 'module';
|
|
2
|
+
import './chunk-D2XW2UOP.js';
|
|
3
|
+
import { Kysely, SqliteDialect } from 'kysely';
|
|
4
|
+
import { Database } from 'bun:sqlite';
|
|
5
|
+
|
|
6
|
+
createRequire(import.meta.url);
|
|
7
|
+
var BunSqliteStatement = class {
|
|
8
|
+
#stmt;
|
|
9
|
+
constructor(stmt) {
|
|
10
|
+
this.#stmt = stmt;
|
|
11
|
+
}
|
|
12
|
+
get reader() {
|
|
13
|
+
return this.#stmt.columnNames.length > 0;
|
|
14
|
+
}
|
|
15
|
+
all(params) {
|
|
16
|
+
return this.#stmt.all(...params);
|
|
17
|
+
}
|
|
18
|
+
run(params) {
|
|
19
|
+
const result = this.#stmt.run(...params);
|
|
20
|
+
return {
|
|
21
|
+
changes: result.changes,
|
|
22
|
+
lastInsertRowid: result.lastInsertRowid
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
*iterate(params) {
|
|
26
|
+
const rows = this.#stmt.all(...params);
|
|
27
|
+
for (const row of rows) {
|
|
28
|
+
yield row;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
var BunSqliteDatabase = class {
|
|
33
|
+
#db;
|
|
34
|
+
constructor(filename) {
|
|
35
|
+
this.#db = new Database(filename);
|
|
36
|
+
}
|
|
37
|
+
close() {
|
|
38
|
+
this.#db.close();
|
|
39
|
+
}
|
|
40
|
+
prepare(sql) {
|
|
41
|
+
return new BunSqliteStatement(this.#db.prepare(sql));
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
function createBunSqliteConnection(config) {
|
|
45
|
+
const filename = config.filename ?? config.database;
|
|
46
|
+
const db = new Kysely({
|
|
47
|
+
dialect: new SqliteDialect({
|
|
48
|
+
database: new BunSqliteDatabase(filename)
|
|
49
|
+
})
|
|
50
|
+
});
|
|
51
|
+
return {
|
|
52
|
+
db,
|
|
53
|
+
dialect: "sqlite",
|
|
54
|
+
destroy: () => db.destroy()
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export { BunSqliteDatabase, createBunSqliteConnection };
|
|
59
|
+
//# sourceMappingURL=sqlite-bun-LMHUMGQI.js.map
|
|
60
|
+
//# sourceMappingURL=sqlite-bun-LMHUMGQI.js.map
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { createRequire } from 'module';
|
|
2
|
+
export { deleteVaultSecret, deleteVaultSecretChecked, getAllVaultSecrets, getVaultKey, getVaultKeyChecked, getVaultSecret, getVaultStatus, initializeVault, initializeVaultChecked, listVaultSecretKeys, listVaultSecretKeysChecked, setVaultSecret, setVaultSecretChecked, vaultSecretExists } from './chunk-2RW4SL2O.js';
|
|
3
|
+
import './chunk-QAECL4RN.js';
|
|
4
|
+
import './chunk-D2XW2UOP.js';
|
|
5
|
+
|
|
6
|
+
createRequire(import.meta.url);
|
|
7
|
+
//# sourceMappingURL=storage-6QBJ55SB.js.map
|
|
8
|
+
//# sourceMappingURL=storage-6QBJ55SB.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@noormdev/sdk",
|
|
3
|
-
"version": "1.0.0
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "Database schema & changeset manager SDK",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -13,7 +13,8 @@
|
|
|
13
13
|
}
|
|
14
14
|
},
|
|
15
15
|
"files": [
|
|
16
|
-
"dist"
|
|
16
|
+
"dist",
|
|
17
|
+
"!dist/**/*.map"
|
|
17
18
|
],
|
|
18
19
|
"sideEffects": false,
|
|
19
20
|
"peerDependencies": {
|
|
@@ -42,7 +43,7 @@
|
|
|
42
43
|
}
|
|
43
44
|
},
|
|
44
45
|
"engines": {
|
|
45
|
-
"node": ">=
|
|
46
|
+
"node": ">=22.13"
|
|
46
47
|
},
|
|
47
48
|
"keywords": [
|
|
48
49
|
"database",
|
|
@@ -52,7 +53,7 @@
|
|
|
52
53
|
"kysely",
|
|
53
54
|
"noorm"
|
|
54
55
|
],
|
|
55
|
-
"license": "
|
|
56
|
+
"license": "MIT",
|
|
56
57
|
"repository": {
|
|
57
58
|
"type": "git",
|
|
58
59
|
"url": "https://github.com/noormdev/noorm"
|
package/dist/chunk-HMKJXT3X.js
DELETED
|
@@ -1,299 +0,0 @@
|
|
|
1
|
-
import { readFile, readdir, stat } from 'fs/promises';
|
|
2
|
-
import { Eta } from 'eta';
|
|
3
|
-
import { ObserverEngine } from '@logosdx/observer';
|
|
4
|
-
import path from 'path';
|
|
5
|
-
import { attempt } from '@logosdx/utils';
|
|
6
|
-
import { pathToFileURL } from 'url';
|
|
7
|
-
import JSON5 from 'json5';
|
|
8
|
-
import { parse as parse$1 } from 'yaml';
|
|
9
|
-
import { parse } from 'csv-parse/sync';
|
|
10
|
-
import v from 'voca';
|
|
11
|
-
|
|
12
|
-
// src/core/template/engine.ts
|
|
13
|
-
var observer = new ObserverEngine({
|
|
14
|
-
name: "noorm",
|
|
15
|
-
spy: process.env["NOORM_DEBUG"] ? (action) => console.error(`[noorm:${action.fn}] ${String(action.event)}`) : void 0
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
// src/core/template/types.ts
|
|
19
|
-
var TEMPLATE_EXTENSION = ".tmpl";
|
|
20
|
-
var HELPER_FILENAME = "$helpers";
|
|
21
|
-
var HELPER_EXTENSIONS = [".ts", ".js", ".mjs"];
|
|
22
|
-
async function loadJs(filepath) {
|
|
23
|
-
const url = pathToFileURL(filepath).href;
|
|
24
|
-
const urlWithCacheBust = `${url}?t=${Date.now()}`;
|
|
25
|
-
const mod = await import(urlWithCacheBust);
|
|
26
|
-
return mod.default !== void 0 ? mod.default : mod;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
// src/core/template/helpers.ts
|
|
30
|
-
async function findHelperFiles(fromDir, projectRoot) {
|
|
31
|
-
const helperPaths = [];
|
|
32
|
-
let currentDir = path.resolve(fromDir);
|
|
33
|
-
const root = path.resolve(projectRoot);
|
|
34
|
-
while (currentDir.startsWith(root)) {
|
|
35
|
-
const helperPath = await findHelperInDir(currentDir);
|
|
36
|
-
if (helperPath) {
|
|
37
|
-
helperPaths.unshift(helperPath);
|
|
38
|
-
}
|
|
39
|
-
const parentDir = path.dirname(currentDir);
|
|
40
|
-
if (parentDir === currentDir) {
|
|
41
|
-
break;
|
|
42
|
-
}
|
|
43
|
-
currentDir = parentDir;
|
|
44
|
-
}
|
|
45
|
-
return helperPaths;
|
|
46
|
-
}
|
|
47
|
-
async function findHelperInDir(dir) {
|
|
48
|
-
for (const ext of HELPER_EXTENSIONS) {
|
|
49
|
-
const filepath = path.join(dir, `${HELPER_FILENAME}${ext}`);
|
|
50
|
-
const [stats] = await attempt(() => stat(filepath));
|
|
51
|
-
if (stats?.isFile()) {
|
|
52
|
-
return filepath;
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
return null;
|
|
56
|
-
}
|
|
57
|
-
async function loadHelpers(fromDir, projectRoot) {
|
|
58
|
-
const helperPaths = await findHelperFiles(fromDir, projectRoot);
|
|
59
|
-
const merged = {};
|
|
60
|
-
for (const filepath of helperPaths) {
|
|
61
|
-
const [mod, err] = await attempt(() => loadJs(filepath));
|
|
62
|
-
if (err) {
|
|
63
|
-
observer.emit("error", {
|
|
64
|
-
source: "template",
|
|
65
|
-
error: err,
|
|
66
|
-
context: { filepath, operation: "load-helpers" }
|
|
67
|
-
});
|
|
68
|
-
continue;
|
|
69
|
-
}
|
|
70
|
-
if (mod && typeof mod === "object") {
|
|
71
|
-
const exports$1 = mod;
|
|
72
|
-
const exportCount = Object.keys(exports$1).length;
|
|
73
|
-
Object.assign(merged, exports$1);
|
|
74
|
-
observer.emit("template:helpers", {
|
|
75
|
-
filepath,
|
|
76
|
-
count: exportCount
|
|
77
|
-
});
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
return merged;
|
|
81
|
-
}
|
|
82
|
-
async function loadJson5(filepath) {
|
|
83
|
-
const content = await readFile(filepath, "utf-8");
|
|
84
|
-
return JSON5.parse(content);
|
|
85
|
-
}
|
|
86
|
-
async function loadYaml(filepath) {
|
|
87
|
-
const content = await readFile(filepath, "utf-8");
|
|
88
|
-
return parse$1(content);
|
|
89
|
-
}
|
|
90
|
-
async function loadCsv(filepath) {
|
|
91
|
-
const content = await readFile(filepath, "utf-8");
|
|
92
|
-
return parse(content, {
|
|
93
|
-
columns: true,
|
|
94
|
-
skip_empty_lines: true,
|
|
95
|
-
trim: true
|
|
96
|
-
});
|
|
97
|
-
}
|
|
98
|
-
async function loadSql(filepath) {
|
|
99
|
-
return readFile(filepath, "utf-8");
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
// src/core/template/loaders/index.ts
|
|
103
|
-
var loaders = {
|
|
104
|
-
".json": loadJson5,
|
|
105
|
-
".json5": loadJson5,
|
|
106
|
-
".yaml": loadYaml,
|
|
107
|
-
".yml": loadYaml,
|
|
108
|
-
".csv": loadCsv,
|
|
109
|
-
".js": loadJs,
|
|
110
|
-
".mjs": loadJs,
|
|
111
|
-
".ts": loadJs,
|
|
112
|
-
".sql": loadSql
|
|
113
|
-
};
|
|
114
|
-
function hasLoader(ext) {
|
|
115
|
-
return ext in loaders;
|
|
116
|
-
}
|
|
117
|
-
function getLoader(ext) {
|
|
118
|
-
return loaders[ext];
|
|
119
|
-
}
|
|
120
|
-
async function loadDataFile(filepath) {
|
|
121
|
-
const ext = path.extname(filepath).toLowerCase();
|
|
122
|
-
const loader = getLoader(ext);
|
|
123
|
-
if (!loader) {
|
|
124
|
-
throw new Error(`No loader registered for extension: ${ext}`);
|
|
125
|
-
}
|
|
126
|
-
return loader(filepath);
|
|
127
|
-
}
|
|
128
|
-
function toContextKey(filename) {
|
|
129
|
-
const ext = path.extname(filename);
|
|
130
|
-
const base = path.basename(filename, ext);
|
|
131
|
-
return v.camelCase(base);
|
|
132
|
-
}
|
|
133
|
-
function sqlEscape(value) {
|
|
134
|
-
return value.replace(/'/g, "''");
|
|
135
|
-
}
|
|
136
|
-
function sqlQuote(value) {
|
|
137
|
-
if (value === null) {
|
|
138
|
-
return "NULL";
|
|
139
|
-
}
|
|
140
|
-
return `'${sqlEscape(String(value))}'`;
|
|
141
|
-
}
|
|
142
|
-
function generateUuid() {
|
|
143
|
-
return crypto.randomUUID();
|
|
144
|
-
}
|
|
145
|
-
function isoNow() {
|
|
146
|
-
return (/* @__PURE__ */ new Date()).toISOString();
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
// src/core/template/context.ts
|
|
150
|
-
async function buildContext(templatePath, options = {}) {
|
|
151
|
-
const templateDir = path.dirname(templatePath);
|
|
152
|
-
const projectRoot = options.projectRoot ?? process.cwd();
|
|
153
|
-
const helpers = await loadHelpers(templateDir, projectRoot);
|
|
154
|
-
const dataFiles = await loadDataFilesInDir(templateDir);
|
|
155
|
-
const hasLocalConfig = "config" in dataFiles;
|
|
156
|
-
const ctx = {
|
|
157
|
-
// Inherited helpers (can be overridden by data files with same name)
|
|
158
|
-
...helpers,
|
|
159
|
-
// Auto-loaded data files
|
|
160
|
-
...dataFiles,
|
|
161
|
-
// Config (only if no local config.* file)
|
|
162
|
-
...hasLocalConfig ? {} : { config: options.config },
|
|
163
|
-
// Secrets
|
|
164
|
-
secrets: options.secrets ?? {},
|
|
165
|
-
globalSecrets: options.globalSecrets ?? {},
|
|
166
|
-
// Environment
|
|
167
|
-
env: process.env,
|
|
168
|
-
// Built-in helpers
|
|
169
|
-
include: createIncludeHelper(templateDir, projectRoot, options),
|
|
170
|
-
escape: sqlEscape,
|
|
171
|
-
quote: sqlQuote,
|
|
172
|
-
json: (value) => JSON.stringify(value),
|
|
173
|
-
now: isoNow,
|
|
174
|
-
uuid: generateUuid
|
|
175
|
-
};
|
|
176
|
-
return ctx;
|
|
177
|
-
}
|
|
178
|
-
async function loadDataFilesInDir(dir) {
|
|
179
|
-
const data = {};
|
|
180
|
-
const [entries, readErr] = await attempt(() => readdir(dir, { withFileTypes: true }));
|
|
181
|
-
if (readErr || !entries) {
|
|
182
|
-
observer.emit("error", {
|
|
183
|
-
source: "template",
|
|
184
|
-
error: readErr ?? new Error("Failed to read directory"),
|
|
185
|
-
context: { dir, operation: "scan-data-files" }
|
|
186
|
-
});
|
|
187
|
-
return data;
|
|
188
|
-
}
|
|
189
|
-
for (const entry of entries) {
|
|
190
|
-
if (!entry.isFile()) {
|
|
191
|
-
continue;
|
|
192
|
-
}
|
|
193
|
-
if (entry.name.startsWith(HELPER_FILENAME)) {
|
|
194
|
-
continue;
|
|
195
|
-
}
|
|
196
|
-
if (entry.name.endsWith(".tmpl")) {
|
|
197
|
-
continue;
|
|
198
|
-
}
|
|
199
|
-
const ext = path.extname(entry.name).toLowerCase();
|
|
200
|
-
if (!hasLoader(ext)) {
|
|
201
|
-
continue;
|
|
202
|
-
}
|
|
203
|
-
if (ext === ".sql") {
|
|
204
|
-
continue;
|
|
205
|
-
}
|
|
206
|
-
const filepath = path.join(dir, entry.name);
|
|
207
|
-
const key = toContextKey(entry.name);
|
|
208
|
-
const [loaded, loadErr] = await attempt(() => loadDataFile(filepath));
|
|
209
|
-
if (loadErr) {
|
|
210
|
-
observer.emit("error", {
|
|
211
|
-
source: "template",
|
|
212
|
-
error: loadErr,
|
|
213
|
-
context: { filepath, operation: "load-data-file" }
|
|
214
|
-
});
|
|
215
|
-
continue;
|
|
216
|
-
}
|
|
217
|
-
data[key] = loaded;
|
|
218
|
-
observer.emit("template:load", {
|
|
219
|
-
filepath,
|
|
220
|
-
format: ext
|
|
221
|
-
});
|
|
222
|
-
}
|
|
223
|
-
return data;
|
|
224
|
-
}
|
|
225
|
-
function createIncludeHelper(templateDir, projectRoot, options) {
|
|
226
|
-
return async (includePath) => {
|
|
227
|
-
const resolved = path.resolve(templateDir, includePath);
|
|
228
|
-
if (!resolved.startsWith(projectRoot)) {
|
|
229
|
-
throw new Error(`Include path escapes project root: ${includePath}`);
|
|
230
|
-
}
|
|
231
|
-
if (resolved.endsWith(".tmpl")) {
|
|
232
|
-
const { processFile: processFile2 } = await import('./engine-IRI22LUB.js');
|
|
233
|
-
const result = await processFile2(resolved, options);
|
|
234
|
-
return result.sql;
|
|
235
|
-
}
|
|
236
|
-
const [content, err] = await attempt(() => loadDataFile(resolved));
|
|
237
|
-
if (err) {
|
|
238
|
-
throw new Error(`Failed to include '${includePath}': ${err.message}`);
|
|
239
|
-
}
|
|
240
|
-
if (typeof content === "string") {
|
|
241
|
-
return content;
|
|
242
|
-
}
|
|
243
|
-
return JSON.stringify(content);
|
|
244
|
-
};
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
// src/core/template/engine.ts
|
|
248
|
-
var eta = new Eta({
|
|
249
|
-
// Custom tags for code blocks
|
|
250
|
-
tags: ["{%", "%}"],
|
|
251
|
-
// Variable name for context ($ instead of it)
|
|
252
|
-
varName: "$",
|
|
253
|
-
// Don't auto-escape (SQL doesn't need HTML escaping)
|
|
254
|
-
autoEscape: false,
|
|
255
|
-
// Allow async functions in templates
|
|
256
|
-
useWith: false,
|
|
257
|
-
// Don't cache templates (we handle caching at a higher level)
|
|
258
|
-
cache: false
|
|
259
|
-
});
|
|
260
|
-
function isTemplate(filepath) {
|
|
261
|
-
return filepath.endsWith(TEMPLATE_EXTENSION);
|
|
262
|
-
}
|
|
263
|
-
async function renderTemplate(template, context) {
|
|
264
|
-
return eta.renderStringAsync(template, context);
|
|
265
|
-
}
|
|
266
|
-
async function processFile(filepath, options = {}) {
|
|
267
|
-
const content = await readFile(filepath, "utf-8");
|
|
268
|
-
if (!isTemplate(filepath)) {
|
|
269
|
-
return {
|
|
270
|
-
sql: content,
|
|
271
|
-
isTemplate: false
|
|
272
|
-
};
|
|
273
|
-
}
|
|
274
|
-
const start = performance.now();
|
|
275
|
-
const context = await buildContext(filepath, options);
|
|
276
|
-
const sql = await renderTemplate(content, context);
|
|
277
|
-
const durationMs = performance.now() - start;
|
|
278
|
-
observer.emit("template:render", {
|
|
279
|
-
filepath,
|
|
280
|
-
durationMs
|
|
281
|
-
});
|
|
282
|
-
return {
|
|
283
|
-
sql,
|
|
284
|
-
isTemplate: true,
|
|
285
|
-
durationMs
|
|
286
|
-
};
|
|
287
|
-
}
|
|
288
|
-
async function processFiles(filepaths, options = {}) {
|
|
289
|
-
const results = [];
|
|
290
|
-
for (const filepath of filepaths) {
|
|
291
|
-
const result = await processFile(filepath, options);
|
|
292
|
-
results.push(result);
|
|
293
|
-
}
|
|
294
|
-
return results;
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
export { eta, isTemplate, observer, processFile, processFiles, renderTemplate };
|
|
298
|
-
//# sourceMappingURL=chunk-HMKJXT3X.js.map
|
|
299
|
-
//# sourceMappingURL=chunk-HMKJXT3X.js.map
|