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/index.cjs
CHANGED
|
@@ -50,7 +50,7 @@ async function loadTypeScriptConfig(resolvedPath) {
|
|
|
50
50
|
const result = esbuild.transformSync(source, {
|
|
51
51
|
loader: "ts",
|
|
52
52
|
format: "esm",
|
|
53
|
-
target: "
|
|
53
|
+
target: "node20",
|
|
54
54
|
sourcefile: resolvedPath
|
|
55
55
|
});
|
|
56
56
|
if (!result.code) {
|
|
@@ -64,10 +64,8 @@ async function loadTypeScriptConfig(resolvedPath) {
|
|
|
64
64
|
// src/utils/validations/generator-config.ts
|
|
65
65
|
function validateGeneratorConfig(config, path) {
|
|
66
66
|
if (typeof config !== "object" || config === null || Array.isArray(config)) {
|
|
67
|
-
throw new Error(
|
|
68
|
-
|
|
69
|
-
Path: ${path}`
|
|
70
|
-
);
|
|
67
|
+
throw new Error(`Invalid generator config: must be an object
|
|
68
|
+
Path: ${path}`);
|
|
71
69
|
}
|
|
72
70
|
const cfg = config;
|
|
73
71
|
const requiredFields = [
|
|
@@ -109,10 +107,8 @@ Received: ${typeof cfg.postfix}`
|
|
|
109
107
|
// src/utils/validations/url-schema.ts
|
|
110
108
|
function validateUrlSchema(urlSchema, path) {
|
|
111
109
|
if (typeof urlSchema !== "object" || urlSchema === null || Array.isArray(urlSchema)) {
|
|
112
|
-
throw new Error(
|
|
113
|
-
|
|
114
|
-
Path: ${path}`
|
|
115
|
-
);
|
|
110
|
+
throw new Error(`Invalid generates entry: must be an object
|
|
111
|
+
Path: ${path}`);
|
|
116
112
|
}
|
|
117
113
|
const schema = urlSchema;
|
|
118
114
|
for (const [filePath, generatorConfig] of Object.entries(schema)) {
|
|
@@ -129,10 +125,8 @@ Path: ${path}[${filePath}]`
|
|
|
129
125
|
// src/utils/validations/config.ts
|
|
130
126
|
function validateConfig(config, configPath) {
|
|
131
127
|
if (typeof config !== "object" || config === null || Array.isArray(config)) {
|
|
132
|
-
throw new Error(
|
|
133
|
-
|
|
134
|
-
Config file: ${configPath}`
|
|
135
|
-
);
|
|
128
|
+
throw new Error(`Invalid config: must be an object
|
|
129
|
+
Config file: ${configPath}`);
|
|
136
130
|
}
|
|
137
131
|
const cfg = config;
|
|
138
132
|
if (!("overwrite" in cfg)) {
|
|
@@ -213,10 +207,8 @@ Make sure esbuild is installed as a dependency.`
|
|
|
213
207
|
configModule = await import(configUrl);
|
|
214
208
|
} catch (importError) {
|
|
215
209
|
const errorMessage = importError instanceof Error ? importError.message : String(importError);
|
|
216
|
-
throw new Error(
|
|
217
|
-
|
|
218
|
-
Error: ${errorMessage}`
|
|
219
|
-
);
|
|
210
|
+
throw new Error(`Failed to import config file: ${resolvedPath}
|
|
211
|
+
Error: ${errorMessage}`);
|
|
220
212
|
}
|
|
221
213
|
}
|
|
222
214
|
if (!configModule.default) {
|
|
@@ -345,7 +337,7 @@ var TypeGenerator = class {
|
|
|
345
337
|
return `${this.prefix}Hit${this.postfix}`;
|
|
346
338
|
}
|
|
347
339
|
const lastPart = path[path.length - 1];
|
|
348
|
-
const parts = lastPart.replace(/[
|
|
340
|
+
const parts = lastPart.replace(/[[\]]/g, "").split(/[-_\s]+/).filter(Boolean);
|
|
349
341
|
const pascalCase = parts.map((part) => part.charAt(0).toUpperCase() + part.slice(1).toLowerCase()).join("");
|
|
350
342
|
if (path.length > 1) {
|
|
351
343
|
const parent = path[path.length - 2];
|
|
@@ -497,30 +489,34 @@ function generateTypeScriptTypes(sampleHit, config) {
|
|
|
497
489
|
}
|
|
498
490
|
|
|
499
491
|
// src/utils/fetch-algolia-data.ts
|
|
500
|
-
async function fetchAlgoliaData(filePath, generatorConfig, overwrite) {
|
|
501
|
-
|
|
502
|
-
Processing file: ${filePath}`);
|
|
492
|
+
async function fetchAlgoliaData(filePath, generatorConfig, overwrite, logger) {
|
|
493
|
+
logger.info(`Processing file: ${filePath}`);
|
|
503
494
|
const resolvedPath = (0, import_path2.resolve)(process.cwd(), filePath);
|
|
495
|
+
logger.verbose(`Resolved path: ${resolvedPath}`);
|
|
504
496
|
if ((0, import_fs3.existsSync)(resolvedPath) && !overwrite) {
|
|
505
497
|
throw new Error(
|
|
506
498
|
`File already exists: ${resolvedPath}
|
|
507
499
|
Set overwrite: true in config to allow overwriting existing files.`
|
|
508
500
|
);
|
|
509
501
|
}
|
|
510
|
-
|
|
511
|
-
|
|
502
|
+
const connectSpinner = logger.spinner("Connecting to Algolia...");
|
|
503
|
+
connectSpinner.start();
|
|
512
504
|
let client;
|
|
513
505
|
try {
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
);
|
|
506
|
+
logger.verbose(`App ID: ${generatorConfig.appId}`);
|
|
507
|
+
logger.verbose(`Index: ${generatorConfig.indexName}`);
|
|
508
|
+
client = (0, import_algoliasearch.algoliasearch)(generatorConfig.appId, generatorConfig.searchKey);
|
|
509
|
+
connectSpinner.succeed("Connected to Algolia");
|
|
518
510
|
} catch (error) {
|
|
511
|
+
connectSpinner.fail("Failed to connect to Algolia");
|
|
519
512
|
throw new Error(
|
|
520
513
|
`Failed to initialize Algolia client: ${error instanceof Error ? error.message : String(error)}`
|
|
521
514
|
);
|
|
522
515
|
}
|
|
523
|
-
|
|
516
|
+
const fetchSpinner = logger.spinner(
|
|
517
|
+
`Fetching sample record from index: ${generatorConfig.indexName}`
|
|
518
|
+
);
|
|
519
|
+
fetchSpinner.start();
|
|
524
520
|
let results;
|
|
525
521
|
try {
|
|
526
522
|
results = await client.search([
|
|
@@ -532,7 +528,9 @@ Set overwrite: true in config to allow overwriting existing files.`
|
|
|
532
528
|
}
|
|
533
529
|
}
|
|
534
530
|
]);
|
|
531
|
+
fetchSpinner.succeed("Sample record fetched successfully");
|
|
535
532
|
} catch (error) {
|
|
533
|
+
fetchSpinner.fail("Failed to fetch data from Algolia");
|
|
536
534
|
let errorMessage;
|
|
537
535
|
if (error instanceof Error) {
|
|
538
536
|
errorMessage = error.message;
|
|
@@ -564,52 +562,183 @@ Set overwrite: true in config to allow overwriting existing files.`
|
|
|
564
562
|
throw new Error(`No hits found in Algolia index: ${generatorConfig.indexName}`);
|
|
565
563
|
}
|
|
566
564
|
const sampleHit = result.hits[0];
|
|
567
|
-
|
|
568
|
-
|
|
565
|
+
logger.verbose(`ObjectID: ${sampleHit.objectID || "N/A"}`);
|
|
566
|
+
const generateSpinner = logger.spinner("Generating TypeScript types...");
|
|
567
|
+
generateSpinner.start();
|
|
569
568
|
const fileContent = generateTypeScriptTypes(sampleHit, generatorConfig);
|
|
569
|
+
generateSpinner.succeed("TypeScript types generated");
|
|
570
570
|
const dir = (0, import_path2.dirname)(resolvedPath);
|
|
571
571
|
if (!(0, import_fs3.existsSync)(dir)) {
|
|
572
|
-
(
|
|
572
|
+
if (!logger.isDryRun) {
|
|
573
|
+
(0, import_fs3.mkdirSync)(dir, { recursive: true });
|
|
574
|
+
logger.verbose(`Created directory: ${dir}`);
|
|
575
|
+
} else {
|
|
576
|
+
logger.dryRun(`Would create directory: ${dir}`);
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
if (logger.isDryRun) {
|
|
580
|
+
logger.dryRun(`Would write file: ${filePath}`);
|
|
581
|
+
logger.verbose(`File content length: ${fileContent.length} characters`);
|
|
582
|
+
} else {
|
|
583
|
+
(0, import_fs3.writeFileSync)(resolvedPath, fileContent, "utf-8");
|
|
584
|
+
logger.success(`Generated file: ${filePath}`);
|
|
573
585
|
}
|
|
574
|
-
(0, import_fs3.writeFileSync)(resolvedPath, fileContent, "utf-8");
|
|
575
|
-
console.log(`Generated file: ${filePath}`);
|
|
576
586
|
}
|
|
577
587
|
|
|
588
|
+
// src/utils/logger.ts
|
|
589
|
+
var import_chalk = __toESM(require("chalk"), 1);
|
|
590
|
+
var import_ora = __toESM(require("ora"), 1);
|
|
591
|
+
var Logger = class {
|
|
592
|
+
_verbose;
|
|
593
|
+
_dryRun;
|
|
594
|
+
constructor(options = {}) {
|
|
595
|
+
this._verbose = options.verbose ?? false;
|
|
596
|
+
this._dryRun = options.dryRun ?? false;
|
|
597
|
+
}
|
|
598
|
+
/**
|
|
599
|
+
* Check if verbose mode is enabled
|
|
600
|
+
*/
|
|
601
|
+
get isVerbose() {
|
|
602
|
+
return this._verbose;
|
|
603
|
+
}
|
|
604
|
+
/**
|
|
605
|
+
* Check if dry-run mode is enabled
|
|
606
|
+
*/
|
|
607
|
+
get isDryRun() {
|
|
608
|
+
return this._dryRun;
|
|
609
|
+
}
|
|
610
|
+
/**
|
|
611
|
+
* Log info message (always shown)
|
|
612
|
+
*/
|
|
613
|
+
info(message) {
|
|
614
|
+
console.log(import_chalk.default.blue("\u2139"), message);
|
|
615
|
+
}
|
|
616
|
+
/**
|
|
617
|
+
* Log success message (always shown)
|
|
618
|
+
*/
|
|
619
|
+
success(message) {
|
|
620
|
+
console.log(import_chalk.default.green("\u2713"), message);
|
|
621
|
+
}
|
|
622
|
+
/**
|
|
623
|
+
* Log warning message (always shown)
|
|
624
|
+
*/
|
|
625
|
+
warn(message) {
|
|
626
|
+
console.log(import_chalk.default.yellow("\u26A0"), message);
|
|
627
|
+
}
|
|
628
|
+
/**
|
|
629
|
+
* Log error message (always shown)
|
|
630
|
+
*/
|
|
631
|
+
error(message) {
|
|
632
|
+
console.error(import_chalk.default.red("\u2717"), message);
|
|
633
|
+
}
|
|
634
|
+
/**
|
|
635
|
+
* Log verbose message (only shown in verbose mode)
|
|
636
|
+
*/
|
|
637
|
+
verbose(message) {
|
|
638
|
+
if (this._verbose) {
|
|
639
|
+
console.log(import_chalk.default.gray("\u2192"), message);
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
/**
|
|
643
|
+
* Log dry-run message (only shown in dry-run mode)
|
|
644
|
+
*/
|
|
645
|
+
dryRun(message) {
|
|
646
|
+
if (this._dryRun) {
|
|
647
|
+
console.log(import_chalk.default.cyan("[DRY-RUN]"), message);
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
/**
|
|
651
|
+
* Create a spinner for long-running operations
|
|
652
|
+
*/
|
|
653
|
+
spinner(text) {
|
|
654
|
+
return (0, import_ora.default)({
|
|
655
|
+
text,
|
|
656
|
+
color: "cyan",
|
|
657
|
+
spinner: "dots"
|
|
658
|
+
});
|
|
659
|
+
}
|
|
660
|
+
/**
|
|
661
|
+
* Log file operation (respects dry-run)
|
|
662
|
+
*/
|
|
663
|
+
fileOperation(action, filePath) {
|
|
664
|
+
if (this._dryRun) {
|
|
665
|
+
this.dryRun(`Would ${action}: ${import_chalk.default.underline(filePath)}`);
|
|
666
|
+
} else {
|
|
667
|
+
this.verbose(`${action}: ${filePath}`);
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
/**
|
|
671
|
+
* Format error with context
|
|
672
|
+
*/
|
|
673
|
+
formatError(error, context) {
|
|
674
|
+
let errorMessage = "";
|
|
675
|
+
if (error instanceof Error) {
|
|
676
|
+
errorMessage = error.message;
|
|
677
|
+
if (this._verbose && error.stack) {
|
|
678
|
+
errorMessage += `
|
|
679
|
+
${import_chalk.default.gray(error.stack)}`;
|
|
680
|
+
}
|
|
681
|
+
} else if (error && typeof error === "object") {
|
|
682
|
+
const errorObj = error;
|
|
683
|
+
if (errorObj.message) {
|
|
684
|
+
errorMessage = String(errorObj.message);
|
|
685
|
+
} else if (errorObj.status) {
|
|
686
|
+
errorMessage = `HTTP ${errorObj.status}: ${errorObj.statusText || "Unknown error"}`;
|
|
687
|
+
} else {
|
|
688
|
+
try {
|
|
689
|
+
errorMessage = JSON.stringify(error, null, 2);
|
|
690
|
+
} catch {
|
|
691
|
+
errorMessage = String(error);
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
} else {
|
|
695
|
+
errorMessage = String(error);
|
|
696
|
+
}
|
|
697
|
+
if (context) {
|
|
698
|
+
return `${import_chalk.default.red(context)}
|
|
699
|
+
${errorMessage}`;
|
|
700
|
+
}
|
|
701
|
+
return errorMessage;
|
|
702
|
+
}
|
|
703
|
+
};
|
|
704
|
+
var logger_default = Logger;
|
|
705
|
+
|
|
578
706
|
// src/index.ts
|
|
579
|
-
var main = async (
|
|
707
|
+
var main = async (options) => {
|
|
708
|
+
const opts = typeof options === "string" ? { configPath: options } : options ?? {};
|
|
709
|
+
const logger = new logger_default({
|
|
710
|
+
verbose: opts.verbose ?? false,
|
|
711
|
+
dryRun: opts.dryRun ?? false
|
|
712
|
+
});
|
|
580
713
|
try {
|
|
581
|
-
const
|
|
582
|
-
|
|
714
|
+
const configSpinner = logger.spinner("Loading configuration...");
|
|
715
|
+
configSpinner.start();
|
|
716
|
+
const config = await loadConfig(opts.configPath);
|
|
717
|
+
configSpinner.succeed("Configuration loaded successfully");
|
|
718
|
+
logger.verbose(`Config path: ${opts.configPath || "default"}`);
|
|
719
|
+
logger.verbose(`Overwrite mode: ${config.overwrite ? "enabled" : "disabled"}`);
|
|
583
720
|
const generatesArray = Array.isArray(config.generates) ? config.generates : [config.generates];
|
|
721
|
+
logger.verbose(`Found ${generatesArray.length} generate configuration(s)`);
|
|
584
722
|
for (const urlSchema of generatesArray) {
|
|
585
723
|
for (const [filePath, generatorConfig] of Object.entries(urlSchema)) {
|
|
586
724
|
try {
|
|
587
|
-
await fetchAlgoliaData(filePath, generatorConfig, config.overwrite);
|
|
725
|
+
await fetchAlgoliaData(filePath, generatorConfig, config.overwrite, logger);
|
|
588
726
|
} catch (error) {
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
console.error(error.message);
|
|
593
|
-
if (error.stack) {
|
|
594
|
-
console.error(error.stack);
|
|
595
|
-
}
|
|
596
|
-
} else {
|
|
597
|
-
try {
|
|
598
|
-
console.error(JSON.stringify(error, null, 2));
|
|
599
|
-
} catch {
|
|
600
|
-
console.error(String(error));
|
|
601
|
-
}
|
|
602
|
-
}
|
|
727
|
+
logger.error(`Error processing file: ${filePath}`);
|
|
728
|
+
const errorMessage = logger.formatError(error, "Processing failed");
|
|
729
|
+
logger.error(errorMessage);
|
|
603
730
|
}
|
|
604
731
|
}
|
|
605
732
|
}
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
if (error instanceof Error) {
|
|
609
|
-
console.error(error.message);
|
|
733
|
+
if (opts.dryRun) {
|
|
734
|
+
logger.info("Dry-run completed. No files were written.");
|
|
610
735
|
} else {
|
|
611
|
-
|
|
736
|
+
logger.success("All files generated successfully!");
|
|
612
737
|
}
|
|
738
|
+
} catch (error) {
|
|
739
|
+
logger.error("Failed to load configuration");
|
|
740
|
+
const errorMessage = logger.formatError(error, "Configuration error");
|
|
741
|
+
logger.error(errorMessage);
|
|
613
742
|
process.exit(1);
|
|
614
743
|
}
|
|
615
744
|
};
|
package/dist/index.d.cts
CHANGED
|
@@ -29,9 +29,14 @@ declare function validateUrlSchema(urlSchema: unknown, path: string): asserts ur
|
|
|
29
29
|
*/
|
|
30
30
|
declare function validateGeneratorConfig(config: unknown, path: string): asserts config is AlgoliaCodegenGeneratorConfig;
|
|
31
31
|
|
|
32
|
+
interface MainOptions {
|
|
33
|
+
configPath?: string;
|
|
34
|
+
verbose?: boolean;
|
|
35
|
+
dryRun?: boolean;
|
|
36
|
+
}
|
|
32
37
|
/**
|
|
33
38
|
* Main function to load and process configuration
|
|
34
39
|
*/
|
|
35
|
-
declare const main: (
|
|
40
|
+
declare const main: (options?: MainOptions | string) => Promise<void>;
|
|
36
41
|
|
|
37
|
-
export { type AlgoliaCodegenConfig, type AlgoliaCodegenGeneratorConfig, type InstanceOrArray, type UrlSchema, main, validateConfig, validateGeneratorConfig, validateUrlSchema };
|
|
42
|
+
export { type AlgoliaCodegenConfig, type AlgoliaCodegenGeneratorConfig, type InstanceOrArray, type MainOptions, type UrlSchema, main, validateConfig, validateGeneratorConfig, validateUrlSchema };
|
package/dist/index.d.ts
CHANGED
|
@@ -29,9 +29,14 @@ declare function validateUrlSchema(urlSchema: unknown, path: string): asserts ur
|
|
|
29
29
|
*/
|
|
30
30
|
declare function validateGeneratorConfig(config: unknown, path: string): asserts config is AlgoliaCodegenGeneratorConfig;
|
|
31
31
|
|
|
32
|
+
interface MainOptions {
|
|
33
|
+
configPath?: string;
|
|
34
|
+
verbose?: boolean;
|
|
35
|
+
dryRun?: boolean;
|
|
36
|
+
}
|
|
32
37
|
/**
|
|
33
38
|
* Main function to load and process configuration
|
|
34
39
|
*/
|
|
35
|
-
declare const main: (
|
|
40
|
+
declare const main: (options?: MainOptions | string) => Promise<void>;
|
|
36
41
|
|
|
37
|
-
export { type AlgoliaCodegenConfig, type AlgoliaCodegenGeneratorConfig, type InstanceOrArray, type UrlSchema, main, validateConfig, validateGeneratorConfig, validateUrlSchema };
|
|
42
|
+
export { type AlgoliaCodegenConfig, type AlgoliaCodegenGeneratorConfig, type InstanceOrArray, type MainOptions, type UrlSchema, main, validateConfig, validateGeneratorConfig, validateUrlSchema };
|
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "algolia-codegen",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "Generate TypeScript types from Algolia indices",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "nightlightmare",
|
|
@@ -38,18 +38,26 @@
|
|
|
38
38
|
],
|
|
39
39
|
"dependencies": {
|
|
40
40
|
"algoliasearch": "^5.46.2",
|
|
41
|
+
"chalk": "^5.6.2",
|
|
41
42
|
"commander": "^14.0.2",
|
|
42
43
|
"dotenv": "^17.2.3",
|
|
43
44
|
"esbuild": "^0.27.0",
|
|
45
|
+
"ora": "^9.0.0",
|
|
44
46
|
"tsx": "^4.21.0"
|
|
45
47
|
},
|
|
46
48
|
"devDependencies": {
|
|
47
49
|
"@types/node": "^25.0.3",
|
|
50
|
+
"@vitest/coverage-v8": "^2.1.8",
|
|
51
|
+
"eslint": "^9.39.2",
|
|
52
|
+
"eslint-config-prettier": "^10.1.8",
|
|
53
|
+
"prettier": "^3.7.4",
|
|
48
54
|
"tsup": "^8.0.0",
|
|
49
|
-
"typescript": "^5.4.0"
|
|
55
|
+
"typescript": "^5.4.0",
|
|
56
|
+
"typescript-eslint": "^8.50.1",
|
|
57
|
+
"vitest": "^2.1.8"
|
|
50
58
|
},
|
|
51
59
|
"engines": {
|
|
52
|
-
"node": ">=
|
|
60
|
+
"node": ">=20"
|
|
53
61
|
},
|
|
54
62
|
"publishConfig": {
|
|
55
63
|
"access": "public"
|
|
@@ -58,6 +66,13 @@
|
|
|
58
66
|
"build": "tsup",
|
|
59
67
|
"dev": "tsup --watch",
|
|
60
68
|
"clean": "rm -rf dist",
|
|
61
|
-
"type-check": "tsc --noEmit"
|
|
69
|
+
"type-check": "tsc --noEmit",
|
|
70
|
+
"lint": "eslint .",
|
|
71
|
+
"lint:fix": "eslint . --fix",
|
|
72
|
+
"format": "prettier --write .",
|
|
73
|
+
"format:check": "prettier --check .",
|
|
74
|
+
"test": "vitest run",
|
|
75
|
+
"test:watch": "vitest",
|
|
76
|
+
"test:coverage": "vitest run --coverage"
|
|
62
77
|
}
|
|
63
78
|
}
|