@dyrected/cli 0.0.1
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/.turbo/turbo-build.log +5 -0
- package/README.md +3 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +118 -0
- package/dist/index.js.map +1 -0
- package/package.json +23 -0
- package/src/index.ts +136 -0
- package/tsconfig.json +11 -0
package/README.md
ADDED
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
import prettier from 'prettier';
|
|
4
|
+
import chalk from 'chalk';
|
|
5
|
+
import fs from 'fs-extra';
|
|
6
|
+
import path from 'path';
|
|
7
|
+
const program = new Command();
|
|
8
|
+
program
|
|
9
|
+
.name('dyrected')
|
|
10
|
+
.description('Dyrected CMS CLI tool')
|
|
11
|
+
.version('0.0.1');
|
|
12
|
+
program
|
|
13
|
+
.command('generate:types')
|
|
14
|
+
.description('Generate TypeScript interfaces from your Dyrected schema')
|
|
15
|
+
.option('-u, --url <url>', 'Base URL of your Dyrected API', 'http://localhost:3000')
|
|
16
|
+
.option('-o, --output <path>', 'Output file path', './dyrected-types.ts')
|
|
17
|
+
.action(async (options) => {
|
|
18
|
+
try {
|
|
19
|
+
console.log(chalk.blue(`Fetching schemas from ${options.url}/api/schemas...`));
|
|
20
|
+
const response = await fetch(`${options.url}/api/schemas`);
|
|
21
|
+
if (!response.ok) {
|
|
22
|
+
throw new Error(`Failed to fetch schemas: ${response.statusText}`);
|
|
23
|
+
}
|
|
24
|
+
const schema = await response.json();
|
|
25
|
+
const code = generateTypes(schema);
|
|
26
|
+
const formattedCode = await prettier.format(code, { parser: 'typescript' });
|
|
27
|
+
await fs.outputFile(path.resolve(process.cwd(), options.output), formattedCode);
|
|
28
|
+
console.log(chalk.green(`\nSuccess! Types generated at ${options.output}`));
|
|
29
|
+
}
|
|
30
|
+
catch (error) {
|
|
31
|
+
console.error(chalk.red(`\nError: ${error.message}`));
|
|
32
|
+
process.exit(1);
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
function generateTypes(schema) {
|
|
36
|
+
let code = `/**
|
|
37
|
+
* This file was automatically generated by Dyrected CLI.
|
|
38
|
+
* DO NOT MODIFY IT BY HAND.
|
|
39
|
+
*/
|
|
40
|
+
|
|
41
|
+
export interface Media {
|
|
42
|
+
id: string;
|
|
43
|
+
filename: string;
|
|
44
|
+
filesize: number;
|
|
45
|
+
mimeType: string;
|
|
46
|
+
url: string;
|
|
47
|
+
width?: number;
|
|
48
|
+
height?: number;
|
|
49
|
+
createdAt: string;
|
|
50
|
+
updatedAt: string;
|
|
51
|
+
}
|
|
52
|
+
\n`;
|
|
53
|
+
// Collections
|
|
54
|
+
for (const col of schema.collections) {
|
|
55
|
+
const interfaceName = toPascalCase(col.slug);
|
|
56
|
+
code += `export interface ${interfaceName} {\n`;
|
|
57
|
+
code += ` id: string;\n`;
|
|
58
|
+
for (const field of col.fields) {
|
|
59
|
+
code += ` ${field.name}${field.required ? '' : '?'}: ${mapFieldType(field)};\n`;
|
|
60
|
+
}
|
|
61
|
+
code += ` createdAt: string;\n`;
|
|
62
|
+
code += ` updatedAt: string;\n`;
|
|
63
|
+
code += `}\n\n`;
|
|
64
|
+
}
|
|
65
|
+
// Globals
|
|
66
|
+
for (const glb of schema.globals) {
|
|
67
|
+
const interfaceName = `${toPascalCase(glb.slug)}Global`;
|
|
68
|
+
code += `export interface ${interfaceName} {\n`;
|
|
69
|
+
for (const field of glb.fields) {
|
|
70
|
+
code += ` ${field.name}${field.required ? '' : '?'}: ${mapFieldType(field)};\n`;
|
|
71
|
+
}
|
|
72
|
+
code += `}\n\n`;
|
|
73
|
+
}
|
|
74
|
+
// Registry
|
|
75
|
+
code += `export interface DyrectedSchema {\n`;
|
|
76
|
+
code += ` collections: {\n`;
|
|
77
|
+
for (const col of schema.collections) {
|
|
78
|
+
code += ` ${col.slug}: ${toPascalCase(col.slug)};\n`;
|
|
79
|
+
}
|
|
80
|
+
code += ` };\n`;
|
|
81
|
+
code += ` globals: {\n`;
|
|
82
|
+
for (const glb of schema.globals) {
|
|
83
|
+
code += ` ${glb.slug}: ${toPascalCase(glb.slug)}Global;\n`;
|
|
84
|
+
}
|
|
85
|
+
code += ` };\n`;
|
|
86
|
+
code += `}\n`;
|
|
87
|
+
return code;
|
|
88
|
+
}
|
|
89
|
+
function mapFieldType(field) {
|
|
90
|
+
switch (field.type) {
|
|
91
|
+
case 'text':
|
|
92
|
+
case 'textarea':
|
|
93
|
+
case 'richText':
|
|
94
|
+
case 'date':
|
|
95
|
+
case 'email':
|
|
96
|
+
case 'url':
|
|
97
|
+
return 'string';
|
|
98
|
+
case 'number':
|
|
99
|
+
return 'number';
|
|
100
|
+
case 'boolean':
|
|
101
|
+
return 'boolean';
|
|
102
|
+
case 'select':
|
|
103
|
+
return field.options ? field.options.map((o) => `'${typeof o === 'string' ? o : o.value}'`).join(' | ') : 'string';
|
|
104
|
+
case 'relationship':
|
|
105
|
+
return field.collection === 'media' ? 'Media | string' : `${toPascalCase(field.collection)} | string`;
|
|
106
|
+
case 'array':
|
|
107
|
+
return 'any[]'; // Deep nesting handled later
|
|
108
|
+
case 'object':
|
|
109
|
+
return 'any';
|
|
110
|
+
default:
|
|
111
|
+
return 'any';
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
function toPascalCase(str) {
|
|
115
|
+
return str.replace(/(^\w|-\w)/g, (m) => m.replace(/-/, '').toUpperCase());
|
|
116
|
+
}
|
|
117
|
+
program.parse();
|
|
118
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@dyrected/cli",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"bin": {
|
|
6
|
+
"dyrected": "./dist/index.js"
|
|
7
|
+
},
|
|
8
|
+
"dependencies": {
|
|
9
|
+
"chalk": "^5.3.0",
|
|
10
|
+
"commander": "^12.1.0",
|
|
11
|
+
"fs-extra": "^11.2.0",
|
|
12
|
+
"prettier": "^3.2.5"
|
|
13
|
+
},
|
|
14
|
+
"devDependencies": {
|
|
15
|
+
"@types/fs-extra": "^11.0.4",
|
|
16
|
+
"@types/node": "^20.12.12",
|
|
17
|
+
"typescript": "^5.4.5"
|
|
18
|
+
},
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "tsc && chmod +x dist/index.js",
|
|
21
|
+
"dev": "tsc --watch"
|
|
22
|
+
}
|
|
23
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
import prettier from 'prettier';
|
|
4
|
+
import chalk from 'chalk';
|
|
5
|
+
import fs from 'fs-extra';
|
|
6
|
+
import path from 'path';
|
|
7
|
+
|
|
8
|
+
const program = new Command();
|
|
9
|
+
|
|
10
|
+
program
|
|
11
|
+
.name('dyrected')
|
|
12
|
+
.description('Dyrected CMS CLI tool')
|
|
13
|
+
.version('0.0.1');
|
|
14
|
+
|
|
15
|
+
program
|
|
16
|
+
.command('generate:types')
|
|
17
|
+
.description('Generate TypeScript interfaces from your Dyrected schema')
|
|
18
|
+
.option('-u, --url <url>', 'Base URL of your Dyrected API', 'http://localhost:3000')
|
|
19
|
+
.option('-o, --output <path>', 'Output file path', './dyrected-types.ts')
|
|
20
|
+
.action(async (options) => {
|
|
21
|
+
try {
|
|
22
|
+
console.log(chalk.blue(`Fetching schemas from ${options.url}/api/schemas...`));
|
|
23
|
+
|
|
24
|
+
const response = await fetch(`${options.url}/api/schemas`);
|
|
25
|
+
if (!response.ok) {
|
|
26
|
+
throw new Error(`Failed to fetch schemas: ${response.statusText}`);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const schema = await response.json();
|
|
30
|
+
const code = generateTypes(schema);
|
|
31
|
+
|
|
32
|
+
const formattedCode = await prettier.format(code, { parser: 'typescript' });
|
|
33
|
+
|
|
34
|
+
await fs.outputFile(path.resolve(process.cwd(), options.output), formattedCode);
|
|
35
|
+
|
|
36
|
+
console.log(chalk.green(`\nSuccess! Types generated at ${options.output}`));
|
|
37
|
+
} catch (error: any) {
|
|
38
|
+
console.error(chalk.red(`\nError: ${error.message}`));
|
|
39
|
+
process.exit(1);
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
function generateTypes(schema: any) {
|
|
44
|
+
let code = `/**
|
|
45
|
+
* This file was automatically generated by Dyrected CLI.
|
|
46
|
+
* DO NOT MODIFY IT BY HAND.
|
|
47
|
+
*/
|
|
48
|
+
|
|
49
|
+
export interface Media {
|
|
50
|
+
id: string;
|
|
51
|
+
filename: string;
|
|
52
|
+
filesize: number;
|
|
53
|
+
mimeType: string;
|
|
54
|
+
url: string;
|
|
55
|
+
width?: number;
|
|
56
|
+
height?: number;
|
|
57
|
+
createdAt: string;
|
|
58
|
+
updatedAt: string;
|
|
59
|
+
}
|
|
60
|
+
\n`;
|
|
61
|
+
|
|
62
|
+
// Collections
|
|
63
|
+
for (const col of schema.collections) {
|
|
64
|
+
const interfaceName = toPascalCase(col.slug);
|
|
65
|
+
code += `export interface ${interfaceName} {\n`;
|
|
66
|
+
code += ` id: string;\n`;
|
|
67
|
+
|
|
68
|
+
for (const field of col.fields) {
|
|
69
|
+
code += ` ${field.name}${field.required ? '' : '?'}: ${mapFieldType(field)};\n`;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
code += ` createdAt: string;\n`;
|
|
73
|
+
code += ` updatedAt: string;\n`;
|
|
74
|
+
code += `}\n\n`;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Globals
|
|
78
|
+
for (const glb of schema.globals) {
|
|
79
|
+
const interfaceName = `${toPascalCase(glb.slug)}Global`;
|
|
80
|
+
code += `export interface ${interfaceName} {\n`;
|
|
81
|
+
|
|
82
|
+
for (const field of glb.fields) {
|
|
83
|
+
code += ` ${field.name}${field.required ? '' : '?'}: ${mapFieldType(field)};\n`;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
code += `}\n\n`;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Registry
|
|
90
|
+
code += `export interface DyrectedSchema {\n`;
|
|
91
|
+
code += ` collections: {\n`;
|
|
92
|
+
for (const col of schema.collections) {
|
|
93
|
+
code += ` ${col.slug}: ${toPascalCase(col.slug)};\n`;
|
|
94
|
+
}
|
|
95
|
+
code += ` };\n`;
|
|
96
|
+
code += ` globals: {\n`;
|
|
97
|
+
for (const glb of schema.globals) {
|
|
98
|
+
code += ` ${glb.slug}: ${toPascalCase(glb.slug)}Global;\n`;
|
|
99
|
+
}
|
|
100
|
+
code += ` };\n`;
|
|
101
|
+
code += `}\n`;
|
|
102
|
+
|
|
103
|
+
return code;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function mapFieldType(field: any): string {
|
|
107
|
+
switch (field.type) {
|
|
108
|
+
case 'text':
|
|
109
|
+
case 'textarea':
|
|
110
|
+
case 'richText':
|
|
111
|
+
case 'date':
|
|
112
|
+
case 'email':
|
|
113
|
+
case 'url':
|
|
114
|
+
return 'string';
|
|
115
|
+
case 'number':
|
|
116
|
+
return 'number';
|
|
117
|
+
case 'boolean':
|
|
118
|
+
return 'boolean';
|
|
119
|
+
case 'select':
|
|
120
|
+
return field.options ? field.options.map((o: any) => `'${typeof o === 'string' ? o : o.value}'`).join(' | ') : 'string';
|
|
121
|
+
case 'relationship':
|
|
122
|
+
return field.collection === 'media' ? 'Media | string' : `${toPascalCase(field.collection)} | string`;
|
|
123
|
+
case 'array':
|
|
124
|
+
return 'any[]'; // Deep nesting handled later
|
|
125
|
+
case 'object':
|
|
126
|
+
return 'any';
|
|
127
|
+
default:
|
|
128
|
+
return 'any';
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function toPascalCase(str: string) {
|
|
133
|
+
return str.replace(/(^\w|-\w)/g, (m) => m.replace(/-/, '').toUpperCase());
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
program.parse();
|
package/tsconfig.json
ADDED