latticesql 0.18.2 → 0.18.3
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/dist/cli.js +35 -19
- package/dist/index.cjs +16 -0
- package/dist/index.d.cts +18 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.js +28 -12
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/cli.ts
|
|
4
|
-
import { resolve as
|
|
4
|
+
import { resolve as resolve4, dirname as dirname5 } from "path";
|
|
5
5
|
import { readFileSync as readFileSync6 } from "fs";
|
|
6
6
|
import { parse as parse2 } from "yaml";
|
|
7
7
|
|
|
@@ -634,8 +634,8 @@ var Sanitizer = class {
|
|
|
634
634
|
};
|
|
635
635
|
|
|
636
636
|
// src/render/engine.ts
|
|
637
|
-
import { join as join5 } from "path";
|
|
638
|
-
import { mkdirSync as mkdirSync3 } from "fs";
|
|
637
|
+
import { join as join5, basename, isAbsolute, resolve as resolve3 } from "path";
|
|
638
|
+
import { mkdirSync as mkdirSync3, existsSync as existsSync5, copyFileSync } from "fs";
|
|
639
639
|
|
|
640
640
|
// src/render/entity-query.ts
|
|
641
641
|
var SAFE_COL_RE = /^[a-zA-Z0-9_]+$/;
|
|
@@ -1175,6 +1175,22 @@ var RenderEngine = class {
|
|
|
1175
1175
|
const slug = def.slug(entityRow);
|
|
1176
1176
|
const entityDir = def.directory ? join5(outputDir, def.directory(entityRow)) : join5(outputDir, directoryRoot, slug);
|
|
1177
1177
|
mkdirSync3(entityDir, { recursive: true });
|
|
1178
|
+
if (def.attachFileColumn) {
|
|
1179
|
+
const filePath = entityRow[def.attachFileColumn];
|
|
1180
|
+
if (filePath && typeof filePath === "string" && filePath.length > 0) {
|
|
1181
|
+
const absPath = isAbsolute(filePath) ? filePath : resolve3(outputDir, filePath);
|
|
1182
|
+
if (existsSync5(absPath)) {
|
|
1183
|
+
const destPath = join5(entityDir, basename(absPath));
|
|
1184
|
+
if (!existsSync5(destPath)) {
|
|
1185
|
+
try {
|
|
1186
|
+
copyFileSync(absPath, destPath);
|
|
1187
|
+
filesWritten.push(destPath);
|
|
1188
|
+
} catch {
|
|
1189
|
+
}
|
|
1190
|
+
}
|
|
1191
|
+
}
|
|
1192
|
+
}
|
|
1193
|
+
}
|
|
1178
1194
|
const renderedFiles = /* @__PURE__ */ new Map();
|
|
1179
1195
|
const entityFileHashes = {};
|
|
1180
1196
|
const protection = protectedTables.size > 0 ? { protectedTables, currentTable: table } : void 0;
|
|
@@ -1224,7 +1240,7 @@ var RenderEngine = class {
|
|
|
1224
1240
|
|
|
1225
1241
|
// src/reverse-sync/engine.ts
|
|
1226
1242
|
import { join as join6 } from "path";
|
|
1227
|
-
import { existsSync as
|
|
1243
|
+
import { existsSync as existsSync6, readFileSync as readFileSync4 } from "fs";
|
|
1228
1244
|
var ReverseSyncEngine = class {
|
|
1229
1245
|
_schema;
|
|
1230
1246
|
_adapter;
|
|
@@ -1276,7 +1292,7 @@ var ReverseSyncEngine = class {
|
|
|
1276
1292
|
if (!fileInfo.hash) continue;
|
|
1277
1293
|
const filePath = join6(entityDir, filename);
|
|
1278
1294
|
result.filesScanned++;
|
|
1279
|
-
if (!
|
|
1295
|
+
if (!existsSync6(filePath)) continue;
|
|
1280
1296
|
let currentContent;
|
|
1281
1297
|
try {
|
|
1282
1298
|
currentContent = readFileSync4(filePath, "utf8");
|
|
@@ -1376,8 +1392,8 @@ var SyncLoop = class {
|
|
|
1376
1392
|
};
|
|
1377
1393
|
|
|
1378
1394
|
// src/writeback/pipeline.ts
|
|
1379
|
-
import { readFileSync as readFileSync5, statSync as statSync2, existsSync as
|
|
1380
|
-
import { join as join7, dirname as dirname4, basename } from "path";
|
|
1395
|
+
import { readFileSync as readFileSync5, statSync as statSync2, existsSync as existsSync7, readdirSync as readdirSync2 } from "fs";
|
|
1396
|
+
import { join as join7, dirname as dirname4, basename as basename2 } from "path";
|
|
1381
1397
|
|
|
1382
1398
|
// src/writeback/state-store.ts
|
|
1383
1399
|
var InMemoryStateStore = class {
|
|
@@ -1427,7 +1443,7 @@ var WritebackPipeline = class {
|
|
|
1427
1443
|
let processed = 0;
|
|
1428
1444
|
const store = def.stateStore ?? this._stateStore;
|
|
1429
1445
|
for (const filePath of paths) {
|
|
1430
|
-
if (!
|
|
1446
|
+
if (!existsSync7(filePath)) continue;
|
|
1431
1447
|
const stat = statSync2(filePath);
|
|
1432
1448
|
const currentSize = stat.size;
|
|
1433
1449
|
const storedOffset = store.getOffset(filePath);
|
|
@@ -1461,8 +1477,8 @@ var WritebackPipeline = class {
|
|
|
1461
1477
|
return [pattern];
|
|
1462
1478
|
}
|
|
1463
1479
|
const dir = dirname4(pattern);
|
|
1464
|
-
const filePattern =
|
|
1465
|
-
if (!
|
|
1480
|
+
const filePattern = basename2(pattern);
|
|
1481
|
+
if (!existsSync7(dir)) return [];
|
|
1466
1482
|
const regexStr = filePattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*").replace(/\?/g, ".");
|
|
1467
1483
|
const regex = new RegExp(`^${regexStr}$`);
|
|
1468
1484
|
return readdirSync2(dir).filter((f) => regex.test(f)).map((f) => join7(dir, f));
|
|
@@ -2738,7 +2754,7 @@ function printVersion() {
|
|
|
2738
2754
|
}
|
|
2739
2755
|
}
|
|
2740
2756
|
function runGenerate(args) {
|
|
2741
|
-
const configPath =
|
|
2757
|
+
const configPath = resolve4(args.config);
|
|
2742
2758
|
let raw;
|
|
2743
2759
|
try {
|
|
2744
2760
|
raw = readFileSync6(configPath, "utf-8");
|
|
@@ -2758,7 +2774,7 @@ function runGenerate(args) {
|
|
|
2758
2774
|
process.exit(1);
|
|
2759
2775
|
}
|
|
2760
2776
|
const configDir = dirname5(configPath);
|
|
2761
|
-
const outDir =
|
|
2777
|
+
const outDir = resolve4(args.out);
|
|
2762
2778
|
try {
|
|
2763
2779
|
const result = generateAll({ config, configDir, outDir, scaffold: args.scaffold });
|
|
2764
2780
|
console.log(`Generated ${String(result.filesWritten.length)} file(s):`);
|
|
@@ -2771,15 +2787,15 @@ function runGenerate(args) {
|
|
|
2771
2787
|
}
|
|
2772
2788
|
}
|
|
2773
2789
|
async function runRender(args) {
|
|
2774
|
-
const outputDir =
|
|
2790
|
+
const outputDir = resolve4(args.output);
|
|
2775
2791
|
let parsed;
|
|
2776
2792
|
try {
|
|
2777
|
-
parsed = parseConfigFile(
|
|
2793
|
+
parsed = parseConfigFile(resolve4(args.config));
|
|
2778
2794
|
} catch (e) {
|
|
2779
2795
|
console.error(`Error: ${e.message}`);
|
|
2780
2796
|
process.exit(1);
|
|
2781
2797
|
}
|
|
2782
|
-
const db = new Lattice({ config:
|
|
2798
|
+
const db = new Lattice({ config: resolve4(args.config) });
|
|
2783
2799
|
try {
|
|
2784
2800
|
await db.init();
|
|
2785
2801
|
const start = Date.now();
|
|
@@ -2798,8 +2814,8 @@ async function runRender(args) {
|
|
|
2798
2814
|
void parsed;
|
|
2799
2815
|
}
|
|
2800
2816
|
async function runReconcile(args, isDryRun) {
|
|
2801
|
-
const outputDir =
|
|
2802
|
-
const db = new Lattice({ config:
|
|
2817
|
+
const outputDir = resolve4(args.output);
|
|
2818
|
+
const db = new Lattice({ config: resolve4(args.config) });
|
|
2803
2819
|
try {
|
|
2804
2820
|
await db.init();
|
|
2805
2821
|
const start = Date.now();
|
|
@@ -2858,8 +2874,8 @@ function formatTimestamp() {
|
|
|
2858
2874
|
return `${hh}:${mm}:${ss}`;
|
|
2859
2875
|
}
|
|
2860
2876
|
async function runWatch(args) {
|
|
2861
|
-
const outputDir =
|
|
2862
|
-
const db = new Lattice({ config:
|
|
2877
|
+
const outputDir = resolve4(args.output);
|
|
2878
|
+
const db = new Lattice({ config: resolve4(args.config) });
|
|
2863
2879
|
try {
|
|
2864
2880
|
await db.init();
|
|
2865
2881
|
} catch (e) {
|
package/dist/index.cjs
CHANGED
|
@@ -935,6 +935,22 @@ var RenderEngine = class {
|
|
|
935
935
|
const slug = def.slug(entityRow);
|
|
936
936
|
const entityDir = def.directory ? (0, import_node_path4.join)(outputDir, def.directory(entityRow)) : (0, import_node_path4.join)(outputDir, directoryRoot, slug);
|
|
937
937
|
(0, import_node_fs4.mkdirSync)(entityDir, { recursive: true });
|
|
938
|
+
if (def.attachFileColumn) {
|
|
939
|
+
const filePath = entityRow[def.attachFileColumn];
|
|
940
|
+
if (filePath && typeof filePath === "string" && filePath.length > 0) {
|
|
941
|
+
const absPath = (0, import_node_path4.isAbsolute)(filePath) ? filePath : (0, import_node_path4.resolve)(outputDir, filePath);
|
|
942
|
+
if ((0, import_node_fs4.existsSync)(absPath)) {
|
|
943
|
+
const destPath = (0, import_node_path4.join)(entityDir, (0, import_node_path4.basename)(absPath));
|
|
944
|
+
if (!(0, import_node_fs4.existsSync)(destPath)) {
|
|
945
|
+
try {
|
|
946
|
+
(0, import_node_fs4.copyFileSync)(absPath, destPath);
|
|
947
|
+
filesWritten.push(destPath);
|
|
948
|
+
} catch {
|
|
949
|
+
}
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
}
|
|
938
954
|
const renderedFiles = /* @__PURE__ */ new Map();
|
|
939
955
|
const entityFileHashes = {};
|
|
940
956
|
const protection = protectedTables.size > 0 ? { protectedTables, currentTable: table } : void 0;
|
package/dist/index.d.cts
CHANGED
|
@@ -534,6 +534,24 @@ interface EntityContextDefinition {
|
|
|
534
534
|
encrypted?: boolean | {
|
|
535
535
|
columns: string[];
|
|
536
536
|
};
|
|
537
|
+
/**
|
|
538
|
+
* Column name containing a file path. When set, the render pipeline
|
|
539
|
+
* copies the referenced file into each entity's rendered directory.
|
|
540
|
+
*
|
|
541
|
+
* If the path is relative, it's resolved from `outputDir`.
|
|
542
|
+
* If the file doesn't exist, it's silently skipped.
|
|
543
|
+
* The column value is updated to the new relative path after copy.
|
|
544
|
+
*
|
|
545
|
+
* @example
|
|
546
|
+
* ```ts
|
|
547
|
+
* db.defineEntityContext('files', {
|
|
548
|
+
* slug: (r) => r.name,
|
|
549
|
+
* attachFileColumn: 'file_path', // copies file at row.file_path into entity dir
|
|
550
|
+
* files: { 'FILE.md': { ... } },
|
|
551
|
+
* });
|
|
552
|
+
* ```
|
|
553
|
+
*/
|
|
554
|
+
attachFileColumn?: string;
|
|
537
555
|
}
|
|
538
556
|
|
|
539
557
|
interface CleanupOptions {
|
package/dist/index.d.ts
CHANGED
|
@@ -534,6 +534,24 @@ interface EntityContextDefinition {
|
|
|
534
534
|
encrypted?: boolean | {
|
|
535
535
|
columns: string[];
|
|
536
536
|
};
|
|
537
|
+
/**
|
|
538
|
+
* Column name containing a file path. When set, the render pipeline
|
|
539
|
+
* copies the referenced file into each entity's rendered directory.
|
|
540
|
+
*
|
|
541
|
+
* If the path is relative, it's resolved from `outputDir`.
|
|
542
|
+
* If the file doesn't exist, it's silently skipped.
|
|
543
|
+
* The column value is updated to the new relative path after copy.
|
|
544
|
+
*
|
|
545
|
+
* @example
|
|
546
|
+
* ```ts
|
|
547
|
+
* db.defineEntityContext('files', {
|
|
548
|
+
* slug: (r) => r.name,
|
|
549
|
+
* attachFileColumn: 'file_path', // copies file at row.file_path into entity dir
|
|
550
|
+
* files: { 'FILE.md': { ... } },
|
|
551
|
+
* });
|
|
552
|
+
* ```
|
|
553
|
+
*/
|
|
554
|
+
attachFileColumn?: string;
|
|
537
555
|
}
|
|
538
556
|
|
|
539
557
|
interface CleanupOptions {
|
package/dist/index.js
CHANGED
|
@@ -320,8 +320,8 @@ var Sanitizer = class {
|
|
|
320
320
|
};
|
|
321
321
|
|
|
322
322
|
// src/render/engine.ts
|
|
323
|
-
import { join as join4 } from "path";
|
|
324
|
-
import { mkdirSync as mkdirSync2 } from "fs";
|
|
323
|
+
import { join as join4, basename, isAbsolute, resolve } from "path";
|
|
324
|
+
import { mkdirSync as mkdirSync2, existsSync as existsSync4, copyFileSync } from "fs";
|
|
325
325
|
|
|
326
326
|
// src/render/entity-query.ts
|
|
327
327
|
var SAFE_COL_RE = /^[a-zA-Z0-9_]+$/;
|
|
@@ -868,6 +868,22 @@ var RenderEngine = class {
|
|
|
868
868
|
const slug = def.slug(entityRow);
|
|
869
869
|
const entityDir = def.directory ? join4(outputDir, def.directory(entityRow)) : join4(outputDir, directoryRoot, slug);
|
|
870
870
|
mkdirSync2(entityDir, { recursive: true });
|
|
871
|
+
if (def.attachFileColumn) {
|
|
872
|
+
const filePath = entityRow[def.attachFileColumn];
|
|
873
|
+
if (filePath && typeof filePath === "string" && filePath.length > 0) {
|
|
874
|
+
const absPath = isAbsolute(filePath) ? filePath : resolve(outputDir, filePath);
|
|
875
|
+
if (existsSync4(absPath)) {
|
|
876
|
+
const destPath = join4(entityDir, basename(absPath));
|
|
877
|
+
if (!existsSync4(destPath)) {
|
|
878
|
+
try {
|
|
879
|
+
copyFileSync(absPath, destPath);
|
|
880
|
+
filesWritten.push(destPath);
|
|
881
|
+
} catch {
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
}
|
|
871
887
|
const renderedFiles = /* @__PURE__ */ new Map();
|
|
872
888
|
const entityFileHashes = {};
|
|
873
889
|
const protection = protectedTables.size > 0 ? { protectedTables, currentTable: table } : void 0;
|
|
@@ -917,7 +933,7 @@ var RenderEngine = class {
|
|
|
917
933
|
|
|
918
934
|
// src/reverse-sync/engine.ts
|
|
919
935
|
import { join as join5 } from "path";
|
|
920
|
-
import { existsSync as
|
|
936
|
+
import { existsSync as existsSync5, readFileSync as readFileSync3 } from "fs";
|
|
921
937
|
var ReverseSyncEngine = class {
|
|
922
938
|
_schema;
|
|
923
939
|
_adapter;
|
|
@@ -969,7 +985,7 @@ var ReverseSyncEngine = class {
|
|
|
969
985
|
if (!fileInfo.hash) continue;
|
|
970
986
|
const filePath = join5(entityDir, filename);
|
|
971
987
|
result.filesScanned++;
|
|
972
|
-
if (!
|
|
988
|
+
if (!existsSync5(filePath)) continue;
|
|
973
989
|
let currentContent;
|
|
974
990
|
try {
|
|
975
991
|
currentContent = readFileSync3(filePath, "utf8");
|
|
@@ -1069,8 +1085,8 @@ var SyncLoop = class {
|
|
|
1069
1085
|
};
|
|
1070
1086
|
|
|
1071
1087
|
// src/writeback/pipeline.ts
|
|
1072
|
-
import { readFileSync as readFileSync4, statSync as statSync2, existsSync as
|
|
1073
|
-
import { join as join6, dirname as dirname2, basename } from "path";
|
|
1088
|
+
import { readFileSync as readFileSync4, statSync as statSync2, existsSync as existsSync6, readdirSync as readdirSync2 } from "fs";
|
|
1089
|
+
import { join as join6, dirname as dirname2, basename as basename2 } from "path";
|
|
1074
1090
|
|
|
1075
1091
|
// src/writeback/state-store.ts
|
|
1076
1092
|
var InMemoryStateStore = class {
|
|
@@ -1176,7 +1192,7 @@ var WritebackPipeline = class {
|
|
|
1176
1192
|
let processed = 0;
|
|
1177
1193
|
const store = def.stateStore ?? this._stateStore;
|
|
1178
1194
|
for (const filePath of paths) {
|
|
1179
|
-
if (!
|
|
1195
|
+
if (!existsSync6(filePath)) continue;
|
|
1180
1196
|
const stat = statSync2(filePath);
|
|
1181
1197
|
const currentSize = stat.size;
|
|
1182
1198
|
const storedOffset = store.getOffset(filePath);
|
|
@@ -1210,8 +1226,8 @@ var WritebackPipeline = class {
|
|
|
1210
1226
|
return [pattern];
|
|
1211
1227
|
}
|
|
1212
1228
|
const dir = dirname2(pattern);
|
|
1213
|
-
const filePattern =
|
|
1214
|
-
if (!
|
|
1229
|
+
const filePattern = basename2(pattern);
|
|
1230
|
+
if (!existsSync6(dir)) return [];
|
|
1215
1231
|
const regexStr = filePattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*").replace(/\?/g, ".");
|
|
1216
1232
|
const regex = new RegExp(`^${regexStr}$`);
|
|
1217
1233
|
return readdirSync2(dir).filter((f) => regex.test(f)).map((f) => join6(dir, f));
|
|
@@ -1335,10 +1351,10 @@ ${body}`;
|
|
|
1335
1351
|
|
|
1336
1352
|
// src/config/parser.ts
|
|
1337
1353
|
import { readFileSync as readFileSync5 } from "fs";
|
|
1338
|
-
import { resolve, dirname as dirname3 } from "path";
|
|
1354
|
+
import { resolve as resolve2, dirname as dirname3 } from "path";
|
|
1339
1355
|
import { parse } from "yaml";
|
|
1340
1356
|
function parseConfigFile(configPath) {
|
|
1341
|
-
const absPath =
|
|
1357
|
+
const absPath = resolve2(configPath);
|
|
1342
1358
|
const configDir = dirname3(absPath);
|
|
1343
1359
|
let raw;
|
|
1344
1360
|
try {
|
|
@@ -1377,7 +1393,7 @@ function buildParsedConfig(raw, sourceName, configDir) {
|
|
|
1377
1393
|
throw new Error(`Lattice: config.entities must be an object`);
|
|
1378
1394
|
}
|
|
1379
1395
|
const config = raw;
|
|
1380
|
-
const dbPath =
|
|
1396
|
+
const dbPath = resolve2(configDir, config.db);
|
|
1381
1397
|
const tables = [];
|
|
1382
1398
|
for (const [entityName, entityDef] of Object.entries(config.entities)) {
|
|
1383
1399
|
const definition = entityToTableDef(entityName, entityDef);
|