@naiv/flazy-api 0.0.1 → 0.0.2

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.
@@ -0,0 +1,221 @@
1
+ ## INSTRUCTION
2
+
3
+ ### 1. Database Design
4
+
5
+ No comments on design files `//` or `/** */`.
6
+
7
+ #### Table
8
+
9
+ ```naiv
10
+ table User {
11
+ id bigint pk inc notnull
12
+ name varchar(255) notnull
13
+ email varchar(255) unique notnull
14
+ password varchar(255) notnull
15
+ created_at timestamp notnull default=NOW()
16
+ updated_at timestamp notnull default=NOW()
17
+ }
18
+ ```
19
+
20
+ - `inc` means auto increment.
21
+ - `notnull` means not null.
22
+ - `pk` means primary key.
23
+ - `unique` means unique.
24
+ - `default` means default value. `NOW()` is a function that returns current timestamp. If default value is string then write it with quote like `default="value"`. If number write it without quote like `default=123`.
25
+
26
+
27
+ #### Relationship
28
+
29
+ ```naiv
30
+ table User {
31
+ id bigint pk inc notnull
32
+ name varchar(255) notnull
33
+ email varchar(255) unique notnull
34
+ password varchar(255) notnull
35
+ created_at timestamp notnull default=NOW()
36
+ updated_at timestamp notnull default=NOW()
37
+ }
38
+
39
+ table Product {
40
+ id bigint pk inc notnull
41
+ id_user_owner User.id notnull
42
+ name varchar(255) notnull
43
+ price decimal(10,2) notnull
44
+ created_at timestamp notnull default=NOW()
45
+ updated_at timestamp notnull default=NOW()
46
+ }
47
+ ```
48
+
49
+ `User` has link to `Product` by `id_user_owner`.
50
+
51
+ #### Enum
52
+
53
+ ```naiv
54
+ enum ProductStatus {
55
+ DRAFT
56
+ PUBLISHED
57
+ ARCHIVED
58
+ }
59
+
60
+ table Product {
61
+ id bigint pk inc notnull
62
+ id_user_owner User.id notnull
63
+ name varchar(255) notnull
64
+ price decimal(10,2) notnull
65
+ status enum.ProductStatus notnull default=DRAFT
66
+ created_at timestamp notnull default=NOW()
67
+ updated_at timestamp notnull default=NOW()
68
+ }
69
+ ```
70
+
71
+ default value for enum is written without quote like `default=DRAFT`.
72
+
73
+ ### 2. API Design
74
+
75
+ API design in NAIV accept only method GET, POST, PUT, DELETE, PATCH. Each API must have unique alias, alias will be used as function call in http client which consume this api design. No comments on design files `//` or `/** */`. Here is how to write it:
76
+
77
+ #### GET
78
+
79
+ ```naiv
80
+ api get /users {
81
+ alias getUsers
82
+ return array table.User required
83
+ }
84
+ ```
85
+
86
+ simple api design for get all users. `required` means this api will response list of users. If not required means this api will response either list users or null. `array` means this api will response array of users. `table.User` means this api will response table structure of User entity on database design above.
87
+
88
+ Other possibility return type beside table reference are native types: `string`, `boolean`, `number`, and schema inline and schema reference (schema will be explained later).
89
+
90
+ ```naiv
91
+ api get /users/:id {
92
+ alias getUserById
93
+ path {
94
+ id number required
95
+ }
96
+ return table.User required
97
+ }
98
+ ```
99
+
100
+ simple api design for get user by id. no `array` means this api will response single user. `path` means this api will accept path parameter, path parameter must be required if it has path parameter on the url. path parameter only accept native types: `string`, `number`, and `boolean`.
101
+
102
+ ```naiv
103
+ api get /users {
104
+ alias getUsers
105
+ query {
106
+ name string
107
+ limit number required
108
+ offset number required
109
+ }
110
+ return array table.User required
111
+ }
112
+ ```
113
+
114
+ simple api design for get users by name. `query` means this api will accept query parameter, query parameter must be optional if it has query parameter on the url. `required` on query `limit` and `offset` means this api will accept query parameter `limit` and `offset` and it must be required. `name` on query is optional. query parameter only accept native types: `string`, `number`, and `boolean`.
115
+
116
+ ```naiv
117
+ api get /profile {
118
+ alias getProfile
119
+ headers {
120
+ authorization string required
121
+ }
122
+ return table.User required
123
+ }
124
+ ```
125
+
126
+ simple api design for get profile. `headers` means this api will accept headers parameter, headers parameter must be required if it has headers parameter on the url. headers parameter only accept native types: `string`, `number`, and `boolean`.
127
+
128
+ #### DELETE
129
+
130
+ same like GET, DELETE also accept path, query, and headers parameter.
131
+
132
+ #### POST
133
+
134
+ ```naiv
135
+ api post /users {
136
+ alias createUser
137
+ body {
138
+ name string required
139
+ email string required
140
+ password string required
141
+ }
142
+ return table.User required
143
+ }
144
+ ```
145
+
146
+ simple api design for create user. `body` means this api will accept body parameter, body parameter must be required if it has body parameter on the url. body parameter accept native types: `string`, `number`, `boolean`, and schema inline and schema reference (schema will be explained later).
147
+
148
+ ```naiv
149
+ api post /sample-complex-post {
150
+ alias sampleComplexPost
151
+ body {
152
+ foo {
153
+ bar string required
154
+ baz number required
155
+ } required
156
+ qux string required
157
+ }
158
+ return string required
159
+ }
160
+ ```
161
+
162
+ foo has type schema inline, it means foo is a schema that defined inside api design like inline object type in typescript.
163
+
164
+ ```naiv
165
+ schema LoginRequest {
166
+ email string required
167
+ password string required
168
+ }
169
+ api post /login {
170
+ alias login
171
+ body {
172
+ data schema.LoginRequest required
173
+ }
174
+ return {
175
+ token string required
176
+ user table.User required
177
+ } required
178
+ }
179
+ ```
180
+
181
+ `data` has type schema reference `LoginRequest`, it means `data` is a schema that defined outside api design. Both schema reference and schema inline also supported for return type. If you want to have an array inside schema inline, you can use `array` keyword.
182
+
183
+ ```naiv
184
+ schema Foo {
185
+ bar array string required
186
+ tuz string required
187
+ }
188
+ schema Buzz {
189
+ foo schema.Foo required
190
+ }
191
+ api post /sample-complex-post-2 {
192
+ alias sampleComplexPost2
193
+ body {
194
+ foo schema.Foo required
195
+ buzz array schema.Buzz required
196
+ }
197
+ return string required
198
+ }
199
+ ```
200
+
201
+ object inside array also supported on body and also return type.
202
+
203
+ #### PATCH, PUT
204
+
205
+ same like POST, PATCH and PUT also accept path, query, body, and headers parameter.
206
+
207
+ #### Streaming response
208
+
209
+ NAIV api design also support streaming response. Here is how to write it:
210
+
211
+ ```naiv
212
+ api get /chat {
213
+ alias promptChat
214
+ query {
215
+ prompt string required
216
+ }
217
+ return stream of string required
218
+ }
219
+ ```
220
+
221
+ `stream of` keyword means this api will return stream of data. `stream of` accept native types: `string`, `number`, `boolean`, schema (inline or reference), and table reference.
@@ -0,0 +1 @@
1
+ export declare function cmdChat(): Promise<void>;
@@ -0,0 +1,130 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.cmdChat = cmdChat;
16
+ const enquirer_1 = require("enquirer");
17
+ const listr2_1 = require("listr2");
18
+ const fs_1 = __importDefault(require("fs"));
19
+ const path_1 = __importDefault(require("path"));
20
+ const llm_runner_1 = require("@graf-research/llm-runner");
21
+ const core_1 = require("@naiv/core");
22
+ const process_1 = require("process");
23
+ function cmdChat() {
24
+ return __awaiter(this, void 0, void 0, function* () {
25
+ const filename = `api-specification.naiv`;
26
+ const file_abs_path = path_1.default.resolve((0, process_1.cwd)(), filename);
27
+ let code = '';
28
+ if (fs_1.default.existsSync(file_abs_path)) {
29
+ code = yield fs_1.default.promises.readFile(file_abs_path, 'utf-8');
30
+ console.warn(`File ${file_abs_path} is exist, this file will be modified by your instruction.`);
31
+ }
32
+ const answers = yield (0, enquirer_1.prompt)([{
33
+ type: "input",
34
+ name: "prompt",
35
+ message: `Explain briefly your API program`,
36
+ }]);
37
+ let success_compiled = false;
38
+ const secret_key = process.env.SK || '';
39
+ const llm_model = 'google/gemini-3-flash-preview';
40
+ const llm_endpoint = 'https://openrouter.ai/api/v1';
41
+ const llm = new llm_runner_1.ChatGPTLLM(secret_key, llm_model, undefined, llm_endpoint);
42
+ let attempt = 0;
43
+ let error_message = '';
44
+ do {
45
+ yield new listr2_1.Listr([{
46
+ title: attempt > 0 ? "Fixing error specification NAIV DSL" : code ? "Updating existing NAIV file" : "Generating data & API specification",
47
+ rendererOptions: {
48
+ persistentOutput: true,
49
+ },
50
+ task: () => __awaiter(this, void 0, void 0, function* () {
51
+ const prompt = yield generatePrompt(answers.prompt, code, error_message);
52
+ const response = yield llm.askNoContext(prompt);
53
+ code = extractCodeBlocks(response);
54
+ try {
55
+ success_compiled = Boolean((0, core_1.naiv_parser)(code));
56
+ }
57
+ catch (err) {
58
+ error_message = (err === null || err === void 0 ? void 0 : err.message) || '';
59
+ console.log(error_message);
60
+ }
61
+ })
62
+ }]).run();
63
+ attempt++;
64
+ } while (!success_compiled);
65
+ yield fs_1.default.promises.writeFile(file_abs_path, code);
66
+ });
67
+ }
68
+ function generatePrompt(instruction, generated_code, error_message) {
69
+ return __awaiter(this, void 0, void 0, function* () {
70
+ const naiv_instruction = yield fs_1.default.promises.readFile(path_1.default.resolve(__dirname, '../NAIV-INSTRUCTION.md'), 'utf-8');
71
+ if (error_message && generated_code) {
72
+ return `
73
+ Read this NAIV DSL carefully
74
+
75
+ ${naiv_instruction}
76
+
77
+ --
78
+
79
+ An LLM generated this code on the context "${instruction}".
80
+
81
+ \`\`\`naiv
82
+ ${generated_code}
83
+ \`\`\`
84
+
85
+ but there is an error: ${error_message}.
86
+
87
+ Your task: fix the error and create naiv database and api dsl code in a single file based on the context "${instruction}".
88
+
89
+ please return only naiv code with code fence block without any other strings but typescript code! your code fence block must starts with "\`\`\`naiv" and ends with "\`\`\`"
90
+ `.trim();
91
+ }
92
+ if (generated_code) {
93
+ return `
94
+ Read this NAIV DSL carefully
95
+
96
+ ${naiv_instruction}
97
+
98
+ --
99
+
100
+ Your task: modify existing naiv database and api dsl code below based on the context "${instruction}".
101
+
102
+ Existing naiv design
103
+
104
+ \`\`\`naiv
105
+ ${generated_code}
106
+ \`\`\`
107
+
108
+ please return only naiv code with code fence block without any other strings but typescript code! your code fence block must starts with "\`\`\`naiv" and ends with "\`\`\`"
109
+ `.trim();
110
+ }
111
+ return `
112
+ Read this NAIV DSL carefully
113
+
114
+ ${naiv_instruction}
115
+
116
+ --
117
+
118
+ Your task: create naiv database and api dsl code in a single file based on the context "${instruction}".
119
+
120
+ please return only naiv code with code fence block without any other strings but typescript code! your code fence block must starts with "\`\`\`naiv" and ends with "\`\`\`"
121
+ `.trim();
122
+ });
123
+ }
124
+ function extractCodeBlocks(text) {
125
+ return /```(?:naiv|dsl)\b/i.test(text)
126
+ ? [...text.matchAll(/```(?:naiv|dsl)\s*([\s\S]*?)```/gi)]
127
+ .map(m => m[1])
128
+ .join('\n')
129
+ : '';
130
+ }
@@ -1 +1,2 @@
1
- export declare function cmdGenerate(design_file_abs_path: string, out_folder: string): Promise<void>;
1
+ import { NVResult } from "@naiv/core";
2
+ export declare function cmdGenerate(design_file_abs_path: string, out_folder: string): Promise<NVResult>;
@@ -15,10 +15,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
15
15
  exports.cmdGenerate = cmdGenerate;
16
16
  const naiv_parser_1 = require("@naiv/core/build/naiv_parser");
17
17
  const fs_1 = __importDefault(require("fs"));
18
+ const path_1 = __importDefault(require("path"));
18
19
  const _1 = require(".");
19
20
  function cmdGenerate(design_file_abs_path, out_folder) {
20
21
  return __awaiter(this, void 0, void 0, function* () {
21
- const result = (0, naiv_parser_1.naiv_parser)(yield fs_1.default.promises.readFile(design_file_abs_path, 'utf-8'));
22
+ const result = (0, naiv_parser_1.naiv_parse_folder)(design_file_abs_path, { fs: fs_1.default, path: path_1.default });
22
23
  const typeorm_model = _1.TypeORMModel.compile(result);
23
24
  for (const f of typeorm_model.enum.files) {
24
25
  writeFiles(f, out_folder);
@@ -32,6 +33,7 @@ function cmdGenerate(design_file_abs_path, out_folder) {
32
33
  for (const f of typeorm_model.api.files) {
33
34
  writeFiles(f, out_folder);
34
35
  }
36
+ return result;
35
37
  });
36
38
  }
37
39
  function writeFiles(output_1) {
package/dist/cmd-run.d.ts CHANGED
@@ -1 +1 @@
1
- export declare function cmdRun(design_file: string): Promise<void>;
1
+ export declare function cmdRun(naiv_cwd: string): Promise<void>;
package/dist/cmd-run.js CHANGED
@@ -14,21 +14,53 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
15
  exports.cmdRun = cmdRun;
16
16
  const cmd_generate_1 = require("./cmd-generate");
17
- const compile_folter_1 = require("./compile-folter");
17
+ const compile_folder_1 = require("./compile-folder");
18
18
  const server_1 = require("./server");
19
19
  const path_1 = __importDefault(require("path"));
20
20
  const fs_1 = __importDefault(require("fs"));
21
- function cmdRun(design_file) {
21
+ const glob_1 = require("glob");
22
+ function cmdRun(naiv_cwd) {
22
23
  return __awaiter(this, void 0, void 0, function* () {
23
- const types_path = path_1.default.resolve('./zzz-types');
24
- const implementation_path = path_1.default.resolve('./zzz-impl');
24
+ const list_naiv_file = (0, glob_1.globSync)("*.naiv", {
25
+ cwd: naiv_cwd,
26
+ absolute: true,
27
+ ignore: ["**/node_modules/**"]
28
+ });
29
+ if (list_naiv_file.length == 0) {
30
+ throw new Error(`No NAIV files is found. Create new data and API design with "--chat"`);
31
+ }
32
+ const working_directory = path_1.default.resolve(naiv_cwd, './__flazy');
33
+ if (!fs_1.default.existsSync(working_directory)) {
34
+ yield fs_1.default.promises.mkdir(working_directory);
35
+ }
36
+ const types_path = path_1.default.resolve(naiv_cwd, './__flazy/__types__');
25
37
  yield fs_1.default.promises.rm(types_path, { force: true, recursive: true });
26
- yield (0, cmd_generate_1.cmdGenerate)(path_1.default.resolve(design_file), types_path);
27
- yield (0, compile_folter_1.compileAndClean)(types_path);
28
- yield (new server_1.Server()).run({
38
+ let blueprint = [];
39
+ for (const naiv_file of list_naiv_file) {
40
+ blueprint.push(yield fs_1.default.promises.readFile(naiv_file, 'utf-8'));
41
+ }
42
+ const nv_result = yield (0, cmd_generate_1.cmdGenerate)(naiv_cwd, types_path);
43
+ yield (0, compile_folder_1.compileAndClean)({
44
+ source_abs_folder_path: types_path
45
+ });
46
+ const source_implementation_path = path_1.default.resolve(naiv_cwd, './__flazy/original-implementation');
47
+ const transp_implementation_path = path_1.default.resolve(naiv_cwd, './__flazy/__implementation__');
48
+ if (fs_1.default.existsSync(source_implementation_path)) {
49
+ yield fs_1.default.promises.rm(transp_implementation_path, { force: true, recursive: true });
50
+ yield (0, compile_folder_1.compileAndClean)({
51
+ source_abs_folder_path: source_implementation_path,
52
+ target_abs_folder_path: transp_implementation_path,
53
+ });
54
+ }
55
+ else {
56
+ yield fs_1.default.promises.mkdir(source_implementation_path);
57
+ }
58
+ yield (new server_1.XServer({ naivCwd: naiv_cwd })).run({
29
59
  port: 9000,
30
60
  types_path,
31
- implementation_path
61
+ implementation_path: transp_implementation_path,
62
+ nv_result,
63
+ blueprint
32
64
  });
33
65
  });
34
66
  }
@@ -0,0 +1,16 @@
1
+ interface CompileParam {
2
+ source_abs_folder_path: string;
3
+ target_abs_folder_path?: string;
4
+ clean_after_compiled?: boolean;
5
+ replace_keywords?: {
6
+ [key: string]: string;
7
+ };
8
+ }
9
+ export declare function compileAndClean(param: CompileParam): Promise<void>;
10
+ interface CompileSingleFileParam {
11
+ source_root_folder_abs_path: string;
12
+ source_abs_file_path: string;
13
+ target_root_folder_abs_path: string;
14
+ }
15
+ export declare function compileSingleFile(param: CompileSingleFileParam): Promise<void>;
16
+ export {};
@@ -0,0 +1,119 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.compileAndClean = compileAndClean;
16
+ exports.compileSingleFile = compileSingleFile;
17
+ const typescript_1 = __importDefault(require("typescript"));
18
+ const path_1 = __importDefault(require("path"));
19
+ const fs_1 = __importDefault(require("fs"));
20
+ const glob_1 = require("glob");
21
+ function compileAndClean(param) {
22
+ return __awaiter(this, void 0, void 0, function* () {
23
+ var _a;
24
+ const target_abs_folder_path = (_a = param.target_abs_folder_path) !== null && _a !== void 0 ? _a : param.source_abs_folder_path;
25
+ if (!path_1.default.isAbsolute(param.source_abs_folder_path)) {
26
+ throw new Error("Path must be absolute");
27
+ }
28
+ if (!fs_1.default.existsSync(param.source_abs_folder_path)) {
29
+ throw new Error("Folder does not exist");
30
+ }
31
+ console.log("Compiling:", param.source_abs_folder_path);
32
+ // Find all .ts files
33
+ const tsFiles = (0, glob_1.globSync)("**/*.ts", {
34
+ cwd: param.source_abs_folder_path,
35
+ absolute: true,
36
+ ignore: ["**/node_modules/**"]
37
+ });
38
+ if (!tsFiles.length) {
39
+ console.log("No TypeScript files found.");
40
+ return;
41
+ }
42
+ // Create TS program
43
+ const program = typescript_1.default.createProgram(tsFiles, {
44
+ target: typescript_1.default.ScriptTarget.ES2020,
45
+ module: typescript_1.default.ModuleKind.CommonJS,
46
+ outDir: target_abs_folder_path,
47
+ rootDir: param.source_abs_folder_path,
48
+ experimentalDecorators: true,
49
+ emitDecoratorMetadata: true,
50
+ useDefineForClassFields: false,
51
+ strict: true,
52
+ noEmitOnError: false
53
+ });
54
+ // Compile
55
+ const emitResult = program.emit();
56
+ // const diagnostics = ts.getPreEmitDiagnostics(program).concat(emitResult.diagnostics);
57
+ // diagnostics.forEach(d => {
58
+ // console.error(ts.flattenDiagnosticMessageText(d.messageText, "\n"));
59
+ // });
60
+ if (emitResult.emitSkipped) {
61
+ throw new Error("Compilation failed");
62
+ }
63
+ console.log("Compilation done.");
64
+ if (param.replace_keywords) {
65
+ const jsFiles = (0, glob_1.globSync)("**/*.js", {
66
+ cwd: param.target_abs_folder_path,
67
+ absolute: true,
68
+ ignore: ["**/node_modules/**"]
69
+ });
70
+ const keys = Object.keys(param.replace_keywords);
71
+ for (const file of jsFiles) {
72
+ let content = yield fs_1.default.promises.readFile(file, 'utf-8');
73
+ for (const key of keys) {
74
+ content = content.replace(new RegExp(key, 'g'), param.replace_keywords[key]);
75
+ }
76
+ yield fs_1.default.promises.writeFile(file, content);
77
+ }
78
+ }
79
+ if (param.clean_after_compiled) {
80
+ // Remove .ts files
81
+ for (const file of tsFiles) {
82
+ yield fs_1.default.promises.rm(file);
83
+ }
84
+ console.log("TS files removed.");
85
+ }
86
+ });
87
+ }
88
+ function compileSingleFile(param) {
89
+ return __awaiter(this, void 0, void 0, function* () {
90
+ if (!path_1.default.isAbsolute(param.source_abs_file_path)) {
91
+ throw new Error("Path must be absolute");
92
+ }
93
+ if (!fs_1.default.existsSync(param.source_abs_file_path)) {
94
+ throw new Error("This function is not implemented yet!");
95
+ }
96
+ console.log("Compiling:", param.source_abs_file_path);
97
+ const program = typescript_1.default.createProgram([param.source_abs_file_path], {
98
+ target: typescript_1.default.ScriptTarget.ES2020,
99
+ module: typescript_1.default.ModuleKind.CommonJS,
100
+ rootDir: param.source_root_folder_abs_path,
101
+ outDir: param.target_root_folder_abs_path,
102
+ experimentalDecorators: true,
103
+ emitDecoratorMetadata: true,
104
+ useDefineForClassFields: false,
105
+ strict: true,
106
+ noEmitOnError: false,
107
+ });
108
+ // Compile
109
+ const emitResult = program.emit();
110
+ // const diagnostics = ts.getPreEmitDiagnostics(program).concat(emitResult.diagnostics);
111
+ // diagnostics.forEach(d => {
112
+ // console.error(ts.flattenDiagnosticMessageText(d.messageText, "\n"));
113
+ // });
114
+ if (emitResult.emitSkipped) {
115
+ throw new Error("Compilation failed");
116
+ }
117
+ console.log("Compilation done.");
118
+ });
119
+ }
package/dist/exec.js CHANGED
@@ -6,11 +6,26 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
7
  const arg_1 = __importDefault(require("arg"));
8
8
  const cmd_run_1 = require("./cmd-run");
9
- const args = (0, arg_1.default)({
10
- "--design": String,
11
- "-d": "--design",
12
- });
13
- if (!args['--design']) {
14
- throw new Error(`--design/-d argument is required`);
9
+ const cmd_chat_1 = require("./cmd-chat");
10
+ try {
11
+ const args = (0, arg_1.default)({
12
+ "--run": String,
13
+ "-r": "--run",
14
+ "--chat": Boolean,
15
+ "-c": "--chat"
16
+ });
17
+ const dir_path = args['--run'];
18
+ const instruction = args['--chat'];
19
+ if (!dir_path && !instruction) {
20
+ throw new Error(`use "--run <folder path>" or "--chat" to begin.`);
21
+ }
22
+ if (dir_path) {
23
+ (0, cmd_run_1.cmdRun)(dir_path).then(() => console.log('completed.')).catch(console.error);
24
+ }
25
+ else if (instruction) {
26
+ (0, cmd_chat_1.cmdChat)();
27
+ }
28
+ }
29
+ catch (err) {
30
+ console.error(err === null || err === void 0 ? void 0 : err.toString());
15
31
  }
16
- (0, cmd_run_1.cmdRun)(args['--design']).then(() => console.log('completed.')).catch(console.error);
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { NVResult } from "@naiv/core";
2
2
  import { ItemOutput } from "./data-types";
3
- import { Server } from './server';
3
+ import { XServer } from './server';
4
4
  export declare namespace TypeORMModel {
5
5
  interface Output {
6
6
  table: ItemOutput;
@@ -10,4 +10,4 @@ export declare namespace TypeORMModel {
10
10
  }
11
11
  function compile(source: NVResult): Output;
12
12
  }
13
- export { Server };
13
+ export { XServer };
package/dist/index.js CHANGED
@@ -1,12 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Server = exports.TypeORMModel = void 0;
3
+ exports.XServer = exports.TypeORMModel = void 0;
4
4
  const build_from_table_1 = require("./build-from-table");
5
5
  const build_from_enum_1 = require("./build-from-enum");
6
6
  const build_from_schema_1 = require("./build-from-schema");
7
7
  const build_from_api_1 = require("./build-from-api");
8
8
  const server_1 = require("./server");
9
- Object.defineProperty(exports, "Server", { enumerable: true, get: function () { return server_1.Server; } });
9
+ Object.defineProperty(exports, "XServer", { enumerable: true, get: function () { return server_1.XServer; } });
10
10
  var TypeORMModel;
11
11
  (function (TypeORMModel) {
12
12
  function compile(source) {
@@ -0,0 +1,10 @@
1
+ export interface ImplPromptParam {
2
+ function_name: string;
3
+ types_relative_path: string;
4
+ target_implementation_path: string;
5
+ types_content: string;
6
+ description: string;
7
+ model_files_list: string[];
8
+ blueprint: string;
9
+ }
10
+ export declare function getImplPrompt(param: ImplPromptParam): string;
package/dist/prompt.js ADDED
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getImplPrompt = getImplPrompt;
4
+ function codefence(code) {
5
+ return `\`\`\`\n${code.trim()}\n\`\`\``;
6
+ }
7
+ function getImplPrompt(param) {
8
+ const function_name_first_lowcase = `${param.function_name[0].toLowerCase()}${param.function_name.slice(1)}`;
9
+ return `
10
+ This is a system blueprint that will related to the task
11
+
12
+ ${codefence(param.blueprint)}
13
+
14
+ Look at this types and signature ${param.function_name} of an API:
15
+
16
+ File location: ${param.types_relative_path}
17
+
18
+ ${codefence(param.types_content)}
19
+
20
+ TypeORM models available on this files location:
21
+
22
+ ${param.model_files_list.map(x => `- ${x}`).join('\n')}
23
+
24
+ Your task: implement function that satisfies that types and signature. This function should do: "${param.description}".
25
+
26
+ This is an example of my expectation how you will implement the function:
27
+
28
+ ${codefence(`
29
+ import { SomeModel } from "../__types__/model/table/SomeModel";
30
+
31
+ export const ${function_name_first_lowcase}: ${param.function_name} = async req => {
32
+ // implement function here...
33
+ }
34
+ `)}
35
+
36
+ You dont need to initialize AppDataSource or use getRepository to get model, just use the model directly since it already extends BaseEntity.
37
+ Function name ${function_name_first_lowcase} is intentional and must be exactly same, do not change.
38
+
39
+ Do not import third party library unless it built-in nodejs library and jsonwebtoken and bcrypt available, instead of other third party library use built-in alternative or just give mockup code/result.
40
+
41
+ please return only typescript code with code fence block without any other strings but typescript code!
42
+
43
+ `.trim();
44
+ }
45
+ // console.log(getImplPrompt({
46
+ // function_name: "T_getProductList",
47
+ // types_relative_path: "__flazy/__types__/api/T_getProductList.ts",
48
+ // target_implementation_path: "__flazy/original-implementation/T_getProductList.ts",
49
+ // types_content: `
50
+ // import { Response } from "express";
51
+ // import { ClassConstructor, Transform, Type, plainToInstance } from "class-transformer";
52
+ // import { IsNotEmpty, IsNumber, IsObject, IsBoolean, IsOptional, IsISO8601, IsString, IsEnum, ValidateNested, IsArray, ValidationError, validateOrReject } from "class-validator";
53
+ // import { Product } from '../model/table/Product'
54
+ // class ReturnType_0 {
55
+ // @IsNotEmpty({ message: 'total cannot be empty' })
56
+ // @Transform((param?: any): number | null => (param?.value === null || param?.value === undefined || param?.value === '') ? null : parseFloat(param.value))
57
+ // @IsNumber({}, { message: 'total must be a number (decimal)' })
58
+ // total!: number
59
+ // @IsNotEmpty({ message: 'data cannot be empty' })
60
+ // @IsArray()
61
+ // @ValidateNested({ each: true })
62
+ // @Type(() => Product)
63
+ // data!: Product[]
64
+ // }
65
+ // export type T_getProductList = (request: {
66
+ // }, response: Response) => Promise<ReturnType_0>;
67
+ // export const method = 'get';
68
+ // export const url_path = '/product';
69
+ // export const alias = 'T_getProductList';
70
+ // export const is_streaming = false;
71
+ // `.trim(),
72
+ // description: "get list of products",
73
+ // model_files_list: [
74
+ // '__flazy/__types__/model/Product.ts',
75
+ // '__flazy/__types__/model/User.ts'
76
+ // ]
77
+ // }))
package/dist/server.d.ts CHANGED
@@ -1,21 +1,35 @@
1
1
  import 'reflect-metadata';
2
2
  import { Express } from 'express';
3
+ import { NVResult } from '@naiv/core';
3
4
  export interface SystemParam {
4
5
  api_prefix?: string;
5
6
  port: number;
6
7
  types_path: string;
7
8
  implementation_path: string;
8
9
  beforeStart?(): Promise<void>;
10
+ nv_result: NVResult;
11
+ blueprint: string[];
9
12
  }
10
13
  export interface ServerConstructorParam {
11
14
  noCors?: boolean;
12
15
  noTrustProxy?: boolean;
16
+ naivCwd: string;
13
17
  }
14
- export declare class Server {
18
+ export declare class XServer {
15
19
  express: Express;
20
+ private server_instance;
16
21
  private constructor_param;
22
+ private server_param;
23
+ private AppDataSource;
24
+ private secret_key;
25
+ private llm_model;
26
+ private llm_endpoint;
27
+ private llm;
17
28
  constructor(param?: ServerConstructorParam);
18
- run(param: SystemParam): Promise<Server>;
29
+ private restart;
30
+ run(param: SystemParam): Promise<XServer>;
19
31
  private errorToString;
32
+ private getImplementationFunction;
33
+ private extractCodeBlocks;
20
34
  _run(types_folder_abs_path: string, implementation_folder: string, api_prefix?: string): Promise<void>;
21
35
  }
package/dist/server.js CHANGED
@@ -45,14 +45,21 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
45
45
  return (mod && mod.__esModule) ? mod : { "default": mod };
46
46
  };
47
47
  Object.defineProperty(exports, "__esModule", { value: true });
48
- exports.Server = void 0;
48
+ exports.XServer = void 0;
49
49
  require("reflect-metadata");
50
+ const typeorm_1 = require("typeorm");
50
51
  const express_1 = __importStar(require("express"));
51
52
  const cors_1 = __importDefault(require("cors"));
52
53
  const class_transformer_1 = require("class-transformer");
53
54
  const class_validator_1 = require("class-validator");
54
55
  const path_1 = __importDefault(require("path"));
55
56
  const promises_1 = __importDefault(require("fs/promises"));
57
+ const cmd_run_1 = require("./cmd-run");
58
+ const compile_folder_1 = require("./compile-folder");
59
+ const prompt_1 = require("./prompt");
60
+ const fs_1 = __importDefault(require("fs"));
61
+ const glob_1 = require("glob");
62
+ const llm_runner_1 = require("@graf-research/llm-runner");
56
63
  const { createRequire } = require("module");
57
64
  const Module = require("module");
58
65
  // patch resolver
@@ -61,27 +68,80 @@ const nm = path_1.default.join(root, "node_modules");
61
68
  Module.globalPaths.push(nm);
62
69
  process.env.NODE_PATH = nm;
63
70
  Module._initPaths();
64
- class Server {
71
+ class XServer {
65
72
  constructor(param) {
66
73
  this.express = (0, express_1.default)();
74
+ this.secret_key = process.env.SK || '';
75
+ this.llm_model = 'google/gemini-3-flash-preview';
76
+ this.llm_endpoint = 'https://openrouter.ai/api/v1';
77
+ this.llm = new llm_runner_1.ChatGPTLLM(this.secret_key, this.llm_model, undefined, this.llm_endpoint);
67
78
  this.constructor_param = param;
68
79
  }
80
+ restart() {
81
+ var _a;
82
+ console.log("Shutting down...");
83
+ (_a = this.server_instance) === null || _a === void 0 ? void 0 : _a.close(() => __awaiter(this, void 0, void 0, function* () {
84
+ var _a;
85
+ yield ((_a = this.AppDataSource) === null || _a === void 0 ? void 0 : _a.destroy());
86
+ console.log("HTTP server closed");
87
+ if (this.server_param) {
88
+ console.log("Restarting server...");
89
+ (0, cmd_run_1.cmdRun)(this.constructor_param.naivCwd);
90
+ }
91
+ }));
92
+ }
69
93
  run(param) {
70
94
  return __awaiter(this, void 0, void 0, function* () {
71
- var _a, _b, _c, _d;
72
- if (!((_a = this.constructor_param) === null || _a === void 0 ? void 0 : _a.noCors)) {
95
+ var _a, _b, _c, _d, _e;
96
+ try {
97
+ const types_location = path_1.default.resolve(this.constructor_param.naivCwd, './__flazy/__types__/model/**/*.js');
98
+ console.log(`types loc: ${types_location}`);
99
+ this.AppDataSource = new typeorm_1.DataSource({
100
+ type: 'mysql',
101
+ host: 'zero-db.naiv.dev',
102
+ port: 23306,
103
+ username: 'uname_4982e1194bb34d2cbacba11dee',
104
+ password: 'pwd_7a64c3d31b3445e4b1e945517100d796',
105
+ database: 'db_7ff95570b7714369af4512ea287ca52d',
106
+ synchronize: true,
107
+ logging: false,
108
+ // migrations: [
109
+ // param?.naivCwd + '/migration/**.ts'
110
+ // ],
111
+ entities: [
112
+ types_location
113
+ ]
114
+ });
115
+ const prefix_model = path_1.default.resolve(this.constructor_param.naivCwd, './__flazy/__types__/model');
116
+ Object.keys(require.cache).forEach((k) => {
117
+ if (k.startsWith(prefix_model)) {
118
+ delete require.cache[k];
119
+ }
120
+ });
121
+ yield ((_a = this.AppDataSource) === null || _a === void 0 ? void 0 : _a.initialize());
122
+ console.log(`db initialized`);
123
+ }
124
+ catch (err) {
125
+ console.log(`Error initializing database: ${err === null || err === void 0 ? void 0 : err.toString()}`);
126
+ }
127
+ this.server_param = param;
128
+ if (!((_b = this.constructor_param) === null || _b === void 0 ? void 0 : _b.noCors)) {
73
129
  this.express.use((0, cors_1.default)());
74
130
  }
75
131
  this.express.use(express_1.default.json({ limit: '5mb' }));
76
- if (!((_b = this.constructor_param) === null || _b === void 0 ? void 0 : _b.noTrustProxy)) {
132
+ if (!((_c = this.constructor_param) === null || _c === void 0 ? void 0 : _c.noTrustProxy)) {
77
133
  this.express.set('trust proxy', true);
78
134
  }
79
135
  if (param.beforeStart) {
80
136
  yield param.beforeStart();
81
137
  }
82
138
  yield this._run(param.types_path, param.implementation_path, param.api_prefix);
83
- const port = (_d = (_c = param === null || param === void 0 ? void 0 : param.port) !== null && _c !== void 0 ? _c : process.env.PORT) !== null && _d !== void 0 ? _d : 3000;
84
- this.express.listen(port, () => {
139
+ const port = (_e = (_d = param === null || param === void 0 ? void 0 : param.port) !== null && _d !== void 0 ? _d : process.env.PORT) !== null && _e !== void 0 ? _e : 3000;
140
+ this.express.post('/__restart__', (req, res) => {
141
+ this.restart();
142
+ res.status(200).send('restarting...');
143
+ });
144
+ this.server_instance = this.express.listen(port, () => {
85
145
  console.log(`\n⚡️[server]: Server is running at http://localhost:${port}`);
86
146
  });
87
147
  return this;
@@ -98,42 +158,86 @@ class Server {
98
158
  return keys.filter(key => constrains[key].length > 0).map(key => constrains[key]).join(', ');
99
159
  }).join(', ');
100
160
  }
161
+ getImplementationFunction(file, types_folder_abs_path, implementation_folder) {
162
+ const filename_without_ext = path_1.default.basename(file, path_1.default.extname(file));
163
+ const path_location = path_1.default.join(types_folder_abs_path, 'api', filename_without_ext);
164
+ delete require.cache[`${implementation_folder}/${file}`];
165
+ const types = require(path_location);
166
+ const method = types['method'];
167
+ const url_path = types['url_path'];
168
+ const alias = types['alias'];
169
+ const is_streaming = types['is_streaming'];
170
+ if (!alias) {
171
+ console.warn(`⚠️ api '${method} ${url_path}' doesnt have alias name, skip.`);
172
+ return {
173
+ fn: null,
174
+ types,
175
+ method,
176
+ url_path,
177
+ is_streaming,
178
+ alias
179
+ };
180
+ }
181
+ let f;
182
+ try {
183
+ f = require(path_1.default.join(implementation_folder, alias));
184
+ }
185
+ catch (err) {
186
+ if (err.code === "MODULE_NOT_FOUND") {
187
+ console.warn(`⚠️ implementation for api '${method} ${url_path}' not found, skip.`);
188
+ return {
189
+ fn: null,
190
+ types,
191
+ method,
192
+ url_path,
193
+ is_streaming,
194
+ alias
195
+ };
196
+ }
197
+ throw err;
198
+ }
199
+ const export_alias = alias.charAt(0).toLowerCase() + alias.slice(1);
200
+ const fn = f[export_alias];
201
+ if (!fn) {
202
+ console.warn(`⚠️ export function implementation for api '${method} ${url_path}' not found, skip.`);
203
+ return {
204
+ fn: null,
205
+ types,
206
+ method,
207
+ url_path,
208
+ is_streaming,
209
+ alias
210
+ };
211
+ }
212
+ return {
213
+ fn,
214
+ types,
215
+ method,
216
+ url_path,
217
+ is_streaming,
218
+ alias
219
+ };
220
+ }
221
+ extractCodeBlocks(text) {
222
+ return /```(?:js|javascript|ts|typescript)\b/i.test(text)
223
+ ? [...text.matchAll(/```(?:js|javascript|ts|typescript)\s*([\s\S]*?)```/gi)]
224
+ .map(m => m[1])
225
+ .join('\n')
226
+ : '';
227
+ }
101
228
  _run(types_folder_abs_path_1, implementation_folder_1) {
102
229
  return __awaiter(this, arguments, void 0, function* (types_folder_abs_path, implementation_folder, api_prefix = '/') {
230
+ var _a, _b, _c;
103
231
  if (!this.express) {
104
232
  throw new Error('🚨 ExpressJS has not been initialized yet');
105
233
  }
106
234
  const router = (0, express_1.Router)();
107
235
  const files = yield promises_1.default.readdir(path_1.default.join(types_folder_abs_path, 'api'));
108
- for (const file of files) {
109
- const filename_without_ext = path_1.default.basename(file, path_1.default.extname(file));
110
- const types = require(path_1.default.join(types_folder_abs_path, 'api', filename_without_ext));
111
- const method = types['method'];
112
- const url_path = types['url_path'];
113
- const alias = types['alias'];
114
- const is_streaming = types['is_streaming'];
115
- if (!alias) {
116
- console.warn(`⚠️ api '${method} ${url_path}' doesnt have alias name, skip.`);
117
- continue;
118
- }
119
- let f;
120
- try {
121
- f = require(path_1.default.join(implementation_folder, alias));
122
- }
123
- catch (err) {
124
- if (err.code === "MODULE_NOT_FOUND") {
125
- console.warn(`⚠️ implementation for api '${method} ${url_path}' not found, skip.`);
126
- continue;
127
- }
128
- throw err;
129
- }
130
- const export_alias = alias.charAt(0).toLowerCase() + alias.slice(1);
131
- const fn = f[export_alias];
132
- if (!fn) {
133
- console.warn(`⚠️ export function implementation for api '${method} ${url_path}' not found, skip.`);
134
- continue;
135
- }
236
+ for (const file of files.filter(f => f.endsWith('.js'))) {
237
+ const { types, method, alias, url_path, is_streaming } = this.getImplementationFunction(file, types_folder_abs_path, implementation_folder);
238
+ const description = ((_c = (_b = (_a = this.server_param) === null || _a === void 0 ? void 0 : _a.nv_result.list_api.find(api => api.url_path == url_path)) === null || _b === void 0 ? void 0 : _b.data.descriptions) === null || _c === void 0 ? void 0 : _c.join('\n')) || '';
136
239
  router[method.toLowerCase()](url_path, (req, res) => __awaiter(this, void 0, void 0, function* () {
240
+ var _a, _b;
137
241
  const t_headers = types[`T_${alias}_headers`];
138
242
  const t_query = types[`T_${alias}_query`];
139
243
  const t_path = types[`T_${alias}_path`];
@@ -163,6 +267,49 @@ class Server {
163
267
  path: req.params,
164
268
  body: req.body,
165
269
  };
270
+ const prefix_source_path = path_1.default.resolve(this.constructor_param.naivCwd, './__flazy/original-implementation');
271
+ const prefix_target_path = path_1.default.resolve(this.constructor_param.naivCwd, './__flazy/__implementation__');
272
+ const types_abs_path = path_1.default.resolve(this.constructor_param.naivCwd, './__flazy/__types__/model');
273
+ const filename_ts = `${file.slice(0, -3)}.ts`;
274
+ const source_abs_file_path = `${prefix_source_path}/${filename_ts}`;
275
+ if (!fs_1.default.existsSync(source_abs_file_path)) {
276
+ try {
277
+ yield (0, compile_folder_1.compileSingleFile)({
278
+ source_root_folder_abs_path: prefix_source_path,
279
+ source_abs_file_path,
280
+ target_root_folder_abs_path: prefix_target_path
281
+ });
282
+ }
283
+ catch (_c) {
284
+ const types_path_abs = path_1.default.resolve(this.constructor_param.naivCwd, `./__flazy/__types__/api/${filename_ts}`);
285
+ const cwd = path_1.default.resolve(this.constructor_param.naivCwd) + '/';
286
+ const impl_param = {
287
+ function_name: file.slice(0, -3),
288
+ types_relative_path: `__flazy/__types__/api/${filename_ts}`,
289
+ target_implementation_path: `__flazy/original-implementation/api/${filename_ts}`,
290
+ types_content: yield fs_1.default.promises.readFile(types_path_abs, 'utf-8'),
291
+ description,
292
+ model_files_list: (0, glob_1.globSync)("**/*.ts", {
293
+ cwd: types_abs_path,
294
+ absolute: true,
295
+ ignore: ["**/node_modules/**"]
296
+ }).map(x => x.replace(cwd, '')),
297
+ blueprint: (_b = (_a = this.server_param) === null || _a === void 0 ? void 0 : _a.blueprint.join('\n')) !== null && _b !== void 0 ? _b : ''
298
+ };
299
+ const llm_response = yield this.llm.askNoContext((0, prompt_1.getImplPrompt)(impl_param));
300
+ const code = this.extractCodeBlocks(llm_response);
301
+ yield fs_1.default.promises.writeFile(`${prefix_source_path}/${filename_ts}`, code);
302
+ yield (0, compile_folder_1.compileSingleFile)({
303
+ source_root_folder_abs_path: prefix_source_path,
304
+ source_abs_file_path,
305
+ target_root_folder_abs_path: prefix_target_path
306
+ });
307
+ }
308
+ }
309
+ const { fn } = this.getImplementationFunction(file, types_folder_abs_path, implementation_folder);
310
+ if (!fn) {
311
+ throw new Error(`This function is not implemented yet!!`);
312
+ }
166
313
  if (is_streaming) {
167
314
  res.status(200);
168
315
  yield fn(request_params, (chunk) => res.write(chunk), res);
@@ -183,10 +330,9 @@ class Server {
183
330
  res.status(500).send(err_msg);
184
331
  }
185
332
  }));
186
- console.info(`✅api [${is_streaming ? 'stream' : 'normal'}] '${method} ${url_path}' (${alias}) is ready`);
187
333
  }
188
334
  this.express.use(api_prefix, router);
189
335
  });
190
336
  }
191
337
  }
192
- exports.Server = Server;
338
+ exports.XServer = XServer;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@naiv/flazy-api",
3
- "version": "0.0.1",
3
+ "version": "0.0.2",
4
4
  "main": "dist/index.js",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -16,7 +16,8 @@
16
16
  },
17
17
  "files": [
18
18
  "dist",
19
- "package.json"
19
+ "package.json",
20
+ "NAIV-INSTRUCTION.md"
20
21
  ],
21
22
  "keywords": [],
22
23
  "author": "",
@@ -28,18 +29,26 @@
28
29
  "@types/express": "^5.0.3",
29
30
  "@types/lodash": "^4.17.13",
30
31
  "@types/node": "^22.8.1",
32
+ "@types/uuid": "^10.0.0",
31
33
  "typescript": "^5.6.3"
32
34
  },
33
35
  "dependencies": {
36
+ "@graf-research/llm-runner": "^0.0.21",
34
37
  "@naiv/core": "^0.0.15",
35
38
  "arg": "^5.0.2",
39
+ "bcrypt": "^6.0.0",
36
40
  "class-transformer": "^0.5.1",
37
41
  "class-validator": "^0.14.2",
38
42
  "cors": "^2.8.5",
43
+ "enquirer": "^2.4.1",
39
44
  "express": "^5.1.0",
40
45
  "glob": "^13.0.2",
46
+ "jsonwebtoken": "^9.0.3",
47
+ "listr2": "^10.1.0",
41
48
  "lodash": "^4.17.21",
49
+ "mysql2": "^3.17.0",
42
50
  "reflect-metadata": "^0.2.2",
43
- "typeorm": "^0.3.28"
51
+ "typeorm": "^0.3.28",
52
+ "uuid": "^13.0.0"
44
53
  }
45
54
  }
@@ -1,4 +0,0 @@
1
- /**
2
- * Compile a TS folder and remove .ts files
3
- */
4
- export declare function compileAndClean(absFolderPath: string): Promise<void>;
@@ -1,70 +0,0 @@
1
- "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
- var __importDefault = (this && this.__importDefault) || function (mod) {
12
- return (mod && mod.__esModule) ? mod : { "default": mod };
13
- };
14
- Object.defineProperty(exports, "__esModule", { value: true });
15
- exports.compileAndClean = compileAndClean;
16
- const typescript_1 = __importDefault(require("typescript"));
17
- const path_1 = __importDefault(require("path"));
18
- const fs_1 = __importDefault(require("fs"));
19
- const glob_1 = require("glob");
20
- /**
21
- * Compile a TS folder and remove .ts files
22
- */
23
- function compileAndClean(absFolderPath) {
24
- return __awaiter(this, void 0, void 0, function* () {
25
- if (!path_1.default.isAbsolute(absFolderPath)) {
26
- throw new Error("Path must be absolute");
27
- }
28
- if (!fs_1.default.existsSync(absFolderPath)) {
29
- throw new Error("Folder does not exist");
30
- }
31
- console.log("Compiling:", absFolderPath);
32
- // Find all .ts files
33
- const tsFiles = (0, glob_1.globSync)("**/*.ts", {
34
- cwd: absFolderPath,
35
- absolute: true,
36
- ignore: ["**/node_modules/**"]
37
- });
38
- if (!tsFiles.length) {
39
- console.log("No TypeScript files found.");
40
- return;
41
- }
42
- // Create TS program
43
- const program = typescript_1.default.createProgram(tsFiles, {
44
- target: typescript_1.default.ScriptTarget.ES2020,
45
- module: typescript_1.default.ModuleKind.CommonJS,
46
- outDir: absFolderPath,
47
- rootDir: absFolderPath,
48
- experimentalDecorators: true,
49
- emitDecoratorMetadata: true,
50
- useDefineForClassFields: false,
51
- strict: true,
52
- noEmitOnError: false
53
- });
54
- // Compile
55
- const emitResult = program.emit();
56
- // const diagnostics = ts.getPreEmitDiagnostics(program).concat(emitResult.diagnostics);
57
- // diagnostics.forEach(d => {
58
- // console.error(ts.flattenDiagnosticMessageText(d.messageText, "\n"));
59
- // });
60
- if (emitResult.emitSkipped) {
61
- throw new Error("Compilation failed");
62
- }
63
- console.log("Compilation done.");
64
- // Remove .ts files
65
- for (const file of tsFiles) {
66
- yield fs_1.default.promises.rm(file);
67
- }
68
- console.log("TS files removed.");
69
- });
70
- }