algolia-codegen 0.1.2 → 0.1.4
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 +22 -0
- package/README.md +75 -71
- package/dist/{chunk-R66ECGLW.js → chunk-USMYY2DN.js} +185 -56
- package/dist/cli.cjs +191 -58
- package/dist/cli.js +7 -3
- package/dist/index.cjs +185 -56
- package/dist/index.d.cts +7 -2
- package/dist/index.d.ts +7 -2
- package/dist/index.js +1 -1
- package/package.json +19 -4
package/dist/cli.cjs
CHANGED
|
@@ -42,7 +42,7 @@ async function loadTypeScriptConfig(resolvedPath) {
|
|
|
42
42
|
const result = esbuild.transformSync(source, {
|
|
43
43
|
loader: "ts",
|
|
44
44
|
format: "esm",
|
|
45
|
-
target: "
|
|
45
|
+
target: "node20",
|
|
46
46
|
sourcefile: resolvedPath
|
|
47
47
|
});
|
|
48
48
|
if (!result.code) {
|
|
@@ -56,10 +56,8 @@ async function loadTypeScriptConfig(resolvedPath) {
|
|
|
56
56
|
// src/utils/validations/generator-config.ts
|
|
57
57
|
function validateGeneratorConfig(config, path) {
|
|
58
58
|
if (typeof config !== "object" || config === null || Array.isArray(config)) {
|
|
59
|
-
throw new Error(
|
|
60
|
-
|
|
61
|
-
Path: ${path}`
|
|
62
|
-
);
|
|
59
|
+
throw new Error(`Invalid generator config: must be an object
|
|
60
|
+
Path: ${path}`);
|
|
63
61
|
}
|
|
64
62
|
const cfg = config;
|
|
65
63
|
const requiredFields = [
|
|
@@ -101,10 +99,8 @@ Received: ${typeof cfg.postfix}`
|
|
|
101
99
|
// src/utils/validations/url-schema.ts
|
|
102
100
|
function validateUrlSchema(urlSchema, path) {
|
|
103
101
|
if (typeof urlSchema !== "object" || urlSchema === null || Array.isArray(urlSchema)) {
|
|
104
|
-
throw new Error(
|
|
105
|
-
|
|
106
|
-
Path: ${path}`
|
|
107
|
-
);
|
|
102
|
+
throw new Error(`Invalid generates entry: must be an object
|
|
103
|
+
Path: ${path}`);
|
|
108
104
|
}
|
|
109
105
|
const schema = urlSchema;
|
|
110
106
|
for (const [filePath, generatorConfig] of Object.entries(schema)) {
|
|
@@ -121,10 +117,8 @@ Path: ${path}[${filePath}]`
|
|
|
121
117
|
// src/utils/validations/config.ts
|
|
122
118
|
function validateConfig(config, configPath) {
|
|
123
119
|
if (typeof config !== "object" || config === null || Array.isArray(config)) {
|
|
124
|
-
throw new Error(
|
|
125
|
-
|
|
126
|
-
Config file: ${configPath}`
|
|
127
|
-
);
|
|
120
|
+
throw new Error(`Invalid config: must be an object
|
|
121
|
+
Config file: ${configPath}`);
|
|
128
122
|
}
|
|
129
123
|
const cfg = config;
|
|
130
124
|
if (!("overwrite" in cfg)) {
|
|
@@ -205,10 +199,8 @@ Make sure esbuild is installed as a dependency.`
|
|
|
205
199
|
configModule = await import(configUrl);
|
|
206
200
|
} catch (importError) {
|
|
207
201
|
const errorMessage = importError instanceof Error ? importError.message : String(importError);
|
|
208
|
-
throw new Error(
|
|
209
|
-
|
|
210
|
-
Error: ${errorMessage}`
|
|
211
|
-
);
|
|
202
|
+
throw new Error(`Failed to import config file: ${resolvedPath}
|
|
203
|
+
Error: ${errorMessage}`);
|
|
212
204
|
}
|
|
213
205
|
}
|
|
214
206
|
if (!configModule.default) {
|
|
@@ -337,7 +329,7 @@ var TypeGenerator = class {
|
|
|
337
329
|
return `${this.prefix}Hit${this.postfix}`;
|
|
338
330
|
}
|
|
339
331
|
const lastPart = path[path.length - 1];
|
|
340
|
-
const parts = lastPart.replace(/[
|
|
332
|
+
const parts = lastPart.replace(/[[\]]/g, "").split(/[-_\s]+/).filter(Boolean);
|
|
341
333
|
const pascalCase = parts.map((part) => part.charAt(0).toUpperCase() + part.slice(1).toLowerCase()).join("");
|
|
342
334
|
if (path.length > 1) {
|
|
343
335
|
const parent = path[path.length - 2];
|
|
@@ -489,30 +481,34 @@ function generateTypeScriptTypes(sampleHit, config) {
|
|
|
489
481
|
}
|
|
490
482
|
|
|
491
483
|
// src/utils/fetch-algolia-data.ts
|
|
492
|
-
async function fetchAlgoliaData(filePath, generatorConfig, overwrite) {
|
|
493
|
-
|
|
494
|
-
Processing file: ${filePath}`);
|
|
484
|
+
async function fetchAlgoliaData(filePath, generatorConfig, overwrite, logger) {
|
|
485
|
+
logger.info(`Processing file: ${filePath}`);
|
|
495
486
|
const resolvedPath = (0, import_path2.resolve)(process.cwd(), filePath);
|
|
487
|
+
logger.verbose(`Resolved path: ${resolvedPath}`);
|
|
496
488
|
if ((0, import_fs3.existsSync)(resolvedPath) && !overwrite) {
|
|
497
489
|
throw new Error(
|
|
498
490
|
`File already exists: ${resolvedPath}
|
|
499
491
|
Set overwrite: true in config to allow overwriting existing files.`
|
|
500
492
|
);
|
|
501
493
|
}
|
|
502
|
-
|
|
503
|
-
|
|
494
|
+
const connectSpinner = logger.spinner("Connecting to Algolia...");
|
|
495
|
+
connectSpinner.start();
|
|
504
496
|
let client;
|
|
505
497
|
try {
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
);
|
|
498
|
+
logger.verbose(`App ID: ${generatorConfig.appId}`);
|
|
499
|
+
logger.verbose(`Index: ${generatorConfig.indexName}`);
|
|
500
|
+
client = (0, import_algoliasearch.algoliasearch)(generatorConfig.appId, generatorConfig.searchKey);
|
|
501
|
+
connectSpinner.succeed("Connected to Algolia");
|
|
510
502
|
} catch (error) {
|
|
503
|
+
connectSpinner.fail("Failed to connect to Algolia");
|
|
511
504
|
throw new Error(
|
|
512
505
|
`Failed to initialize Algolia client: ${error instanceof Error ? error.message : String(error)}`
|
|
513
506
|
);
|
|
514
507
|
}
|
|
515
|
-
|
|
508
|
+
const fetchSpinner = logger.spinner(
|
|
509
|
+
`Fetching sample record from index: ${generatorConfig.indexName}`
|
|
510
|
+
);
|
|
511
|
+
fetchSpinner.start();
|
|
516
512
|
let results;
|
|
517
513
|
try {
|
|
518
514
|
results = await client.search([
|
|
@@ -524,7 +520,9 @@ Set overwrite: true in config to allow overwriting existing files.`
|
|
|
524
520
|
}
|
|
525
521
|
}
|
|
526
522
|
]);
|
|
523
|
+
fetchSpinner.succeed("Sample record fetched successfully");
|
|
527
524
|
} catch (error) {
|
|
525
|
+
fetchSpinner.fail("Failed to fetch data from Algolia");
|
|
528
526
|
let errorMessage;
|
|
529
527
|
if (error instanceof Error) {
|
|
530
528
|
errorMessage = error.message;
|
|
@@ -556,52 +554,183 @@ Set overwrite: true in config to allow overwriting existing files.`
|
|
|
556
554
|
throw new Error(`No hits found in Algolia index: ${generatorConfig.indexName}`);
|
|
557
555
|
}
|
|
558
556
|
const sampleHit = result.hits[0];
|
|
559
|
-
|
|
560
|
-
|
|
557
|
+
logger.verbose(`ObjectID: ${sampleHit.objectID || "N/A"}`);
|
|
558
|
+
const generateSpinner = logger.spinner("Generating TypeScript types...");
|
|
559
|
+
generateSpinner.start();
|
|
561
560
|
const fileContent = generateTypeScriptTypes(sampleHit, generatorConfig);
|
|
561
|
+
generateSpinner.succeed("TypeScript types generated");
|
|
562
562
|
const dir = (0, import_path2.dirname)(resolvedPath);
|
|
563
563
|
if (!(0, import_fs3.existsSync)(dir)) {
|
|
564
|
-
(
|
|
564
|
+
if (!logger.isDryRun) {
|
|
565
|
+
(0, import_fs3.mkdirSync)(dir, { recursive: true });
|
|
566
|
+
logger.verbose(`Created directory: ${dir}`);
|
|
567
|
+
} else {
|
|
568
|
+
logger.dryRun(`Would create directory: ${dir}`);
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
if (logger.isDryRun) {
|
|
572
|
+
logger.dryRun(`Would write file: ${filePath}`);
|
|
573
|
+
logger.verbose(`File content length: ${fileContent.length} characters`);
|
|
574
|
+
} else {
|
|
575
|
+
(0, import_fs3.writeFileSync)(resolvedPath, fileContent, "utf-8");
|
|
576
|
+
logger.success(`Generated file: ${filePath}`);
|
|
565
577
|
}
|
|
566
|
-
(0, import_fs3.writeFileSync)(resolvedPath, fileContent, "utf-8");
|
|
567
|
-
console.log(`Generated file: ${filePath}`);
|
|
568
578
|
}
|
|
569
579
|
|
|
580
|
+
// src/utils/logger.ts
|
|
581
|
+
var import_chalk = __toESM(require("chalk"), 1);
|
|
582
|
+
var import_ora = __toESM(require("ora"), 1);
|
|
583
|
+
var Logger = class {
|
|
584
|
+
_verbose;
|
|
585
|
+
_dryRun;
|
|
586
|
+
constructor(options = {}) {
|
|
587
|
+
this._verbose = options.verbose ?? false;
|
|
588
|
+
this._dryRun = options.dryRun ?? false;
|
|
589
|
+
}
|
|
590
|
+
/**
|
|
591
|
+
* Check if verbose mode is enabled
|
|
592
|
+
*/
|
|
593
|
+
get isVerbose() {
|
|
594
|
+
return this._verbose;
|
|
595
|
+
}
|
|
596
|
+
/**
|
|
597
|
+
* Check if dry-run mode is enabled
|
|
598
|
+
*/
|
|
599
|
+
get isDryRun() {
|
|
600
|
+
return this._dryRun;
|
|
601
|
+
}
|
|
602
|
+
/**
|
|
603
|
+
* Log info message (always shown)
|
|
604
|
+
*/
|
|
605
|
+
info(message) {
|
|
606
|
+
console.log(import_chalk.default.blue("\u2139"), message);
|
|
607
|
+
}
|
|
608
|
+
/**
|
|
609
|
+
* Log success message (always shown)
|
|
610
|
+
*/
|
|
611
|
+
success(message) {
|
|
612
|
+
console.log(import_chalk.default.green("\u2713"), message);
|
|
613
|
+
}
|
|
614
|
+
/**
|
|
615
|
+
* Log warning message (always shown)
|
|
616
|
+
*/
|
|
617
|
+
warn(message) {
|
|
618
|
+
console.log(import_chalk.default.yellow("\u26A0"), message);
|
|
619
|
+
}
|
|
620
|
+
/**
|
|
621
|
+
* Log error message (always shown)
|
|
622
|
+
*/
|
|
623
|
+
error(message) {
|
|
624
|
+
console.error(import_chalk.default.red("\u2717"), message);
|
|
625
|
+
}
|
|
626
|
+
/**
|
|
627
|
+
* Log verbose message (only shown in verbose mode)
|
|
628
|
+
*/
|
|
629
|
+
verbose(message) {
|
|
630
|
+
if (this._verbose) {
|
|
631
|
+
console.log(import_chalk.default.gray("\u2192"), message);
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
/**
|
|
635
|
+
* Log dry-run message (only shown in dry-run mode)
|
|
636
|
+
*/
|
|
637
|
+
dryRun(message) {
|
|
638
|
+
if (this._dryRun) {
|
|
639
|
+
console.log(import_chalk.default.cyan("[DRY-RUN]"), message);
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
/**
|
|
643
|
+
* Create a spinner for long-running operations
|
|
644
|
+
*/
|
|
645
|
+
spinner(text) {
|
|
646
|
+
return (0, import_ora.default)({
|
|
647
|
+
text,
|
|
648
|
+
color: "cyan",
|
|
649
|
+
spinner: "dots"
|
|
650
|
+
});
|
|
651
|
+
}
|
|
652
|
+
/**
|
|
653
|
+
* Log file operation (respects dry-run)
|
|
654
|
+
*/
|
|
655
|
+
fileOperation(action, filePath) {
|
|
656
|
+
if (this._dryRun) {
|
|
657
|
+
this.dryRun(`Would ${action}: ${import_chalk.default.underline(filePath)}`);
|
|
658
|
+
} else {
|
|
659
|
+
this.verbose(`${action}: ${filePath}`);
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
/**
|
|
663
|
+
* Format error with context
|
|
664
|
+
*/
|
|
665
|
+
formatError(error, context) {
|
|
666
|
+
let errorMessage = "";
|
|
667
|
+
if (error instanceof Error) {
|
|
668
|
+
errorMessage = error.message;
|
|
669
|
+
if (this._verbose && error.stack) {
|
|
670
|
+
errorMessage += `
|
|
671
|
+
${import_chalk.default.gray(error.stack)}`;
|
|
672
|
+
}
|
|
673
|
+
} else if (error && typeof error === "object") {
|
|
674
|
+
const errorObj = error;
|
|
675
|
+
if (errorObj.message) {
|
|
676
|
+
errorMessage = String(errorObj.message);
|
|
677
|
+
} else if (errorObj.status) {
|
|
678
|
+
errorMessage = `HTTP ${errorObj.status}: ${errorObj.statusText || "Unknown error"}`;
|
|
679
|
+
} else {
|
|
680
|
+
try {
|
|
681
|
+
errorMessage = JSON.stringify(error, null, 2);
|
|
682
|
+
} catch {
|
|
683
|
+
errorMessage = String(error);
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
} else {
|
|
687
|
+
errorMessage = String(error);
|
|
688
|
+
}
|
|
689
|
+
if (context) {
|
|
690
|
+
return `${import_chalk.default.red(context)}
|
|
691
|
+
${errorMessage}`;
|
|
692
|
+
}
|
|
693
|
+
return errorMessage;
|
|
694
|
+
}
|
|
695
|
+
};
|
|
696
|
+
var logger_default = Logger;
|
|
697
|
+
|
|
570
698
|
// src/index.ts
|
|
571
|
-
var main = async (
|
|
699
|
+
var main = async (options) => {
|
|
700
|
+
const opts = typeof options === "string" ? { configPath: options } : options ?? {};
|
|
701
|
+
const logger = new logger_default({
|
|
702
|
+
verbose: opts.verbose ?? false,
|
|
703
|
+
dryRun: opts.dryRun ?? false
|
|
704
|
+
});
|
|
572
705
|
try {
|
|
573
|
-
const
|
|
574
|
-
|
|
706
|
+
const configSpinner = logger.spinner("Loading configuration...");
|
|
707
|
+
configSpinner.start();
|
|
708
|
+
const config = await loadConfig(opts.configPath);
|
|
709
|
+
configSpinner.succeed("Configuration loaded successfully");
|
|
710
|
+
logger.verbose(`Config path: ${opts.configPath || "default"}`);
|
|
711
|
+
logger.verbose(`Overwrite mode: ${config.overwrite ? "enabled" : "disabled"}`);
|
|
575
712
|
const generatesArray = Array.isArray(config.generates) ? config.generates : [config.generates];
|
|
713
|
+
logger.verbose(`Found ${generatesArray.length} generate configuration(s)`);
|
|
576
714
|
for (const urlSchema of generatesArray) {
|
|
577
715
|
for (const [filePath, generatorConfig] of Object.entries(urlSchema)) {
|
|
578
716
|
try {
|
|
579
|
-
await fetchAlgoliaData(filePath, generatorConfig, config.overwrite);
|
|
717
|
+
await fetchAlgoliaData(filePath, generatorConfig, config.overwrite, logger);
|
|
580
718
|
} catch (error) {
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
console.error(error.message);
|
|
585
|
-
if (error.stack) {
|
|
586
|
-
console.error(error.stack);
|
|
587
|
-
}
|
|
588
|
-
} else {
|
|
589
|
-
try {
|
|
590
|
-
console.error(JSON.stringify(error, null, 2));
|
|
591
|
-
} catch {
|
|
592
|
-
console.error(String(error));
|
|
593
|
-
}
|
|
594
|
-
}
|
|
719
|
+
logger.error(`Error processing file: ${filePath}`);
|
|
720
|
+
const errorMessage = logger.formatError(error, "Processing failed");
|
|
721
|
+
logger.error(errorMessage);
|
|
595
722
|
}
|
|
596
723
|
}
|
|
597
724
|
}
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
if (error instanceof Error) {
|
|
601
|
-
console.error(error.message);
|
|
725
|
+
if (opts.dryRun) {
|
|
726
|
+
logger.info("Dry-run completed. No files were written.");
|
|
602
727
|
} else {
|
|
603
|
-
|
|
728
|
+
logger.success("All files generated successfully!");
|
|
604
729
|
}
|
|
730
|
+
} catch (error) {
|
|
731
|
+
logger.error("Failed to load configuration");
|
|
732
|
+
const errorMessage = logger.formatError(error, "Configuration error");
|
|
733
|
+
logger.error(errorMessage);
|
|
605
734
|
process.exit(1);
|
|
606
735
|
}
|
|
607
736
|
};
|
|
@@ -612,6 +741,10 @@ if ((0, import_fs4.existsSync)(envPath)) {
|
|
|
612
741
|
(0, import_dotenv.config)({ path: envPath });
|
|
613
742
|
}
|
|
614
743
|
var program = new import_commander.Command();
|
|
615
|
-
program.name("algolia-codegen").description("Generate TypeScript types from Algolia index").option("-c, --config <path>", "Config file path").action(async (options) => {
|
|
616
|
-
await main(
|
|
744
|
+
program.name("algolia-codegen").description("Generate TypeScript types from Algolia index").option("-c, --config <path>", "Config file path").option("-v, --verbose", "Enable verbose output").option("--dry-run", "Simulate execution without writing files").action(async (options) => {
|
|
745
|
+
await main({
|
|
746
|
+
configPath: options.config,
|
|
747
|
+
verbose: options.verbose ?? false,
|
|
748
|
+
dryRun: options.dryRun ?? false
|
|
749
|
+
});
|
|
617
750
|
}).parse();
|
package/dist/cli.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
main
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-USMYY2DN.js";
|
|
5
5
|
|
|
6
6
|
// src/cli.ts
|
|
7
7
|
import { config as loadDotenv } from "dotenv";
|
|
@@ -13,6 +13,10 @@ if (existsSync(envPath)) {
|
|
|
13
13
|
loadDotenv({ path: envPath });
|
|
14
14
|
}
|
|
15
15
|
var program = new Command();
|
|
16
|
-
program.name("algolia-codegen").description("Generate TypeScript types from Algolia index").option("-c, --config <path>", "Config file path").action(async (options) => {
|
|
17
|
-
await main(
|
|
16
|
+
program.name("algolia-codegen").description("Generate TypeScript types from Algolia index").option("-c, --config <path>", "Config file path").option("-v, --verbose", "Enable verbose output").option("--dry-run", "Simulate execution without writing files").action(async (options) => {
|
|
17
|
+
await main({
|
|
18
|
+
configPath: options.config,
|
|
19
|
+
verbose: options.verbose ?? false,
|
|
20
|
+
dryRun: options.dryRun ?? false
|
|
21
|
+
});
|
|
18
22
|
}).parse();
|