@rexeus/typeweaver-gen 0.2.0 → 0.3.0
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/README.md +5 -5
- package/dist/index.cjs +278 -0
- package/dist/index.d.cts +276 -0
- package/dist/index.d.ts +1 -2
- package/dist/index.js +52 -34
- package/package.json +14 -7
package/README.md
CHANGED
|
@@ -121,18 +121,18 @@ output.
|
|
|
121
121
|
- Copy them:
|
|
122
122
|
|
|
123
123
|
```ts
|
|
124
|
-
import path from "path";
|
|
125
|
-
import { fileURLToPath } from "url";
|
|
124
|
+
import path from "node:path";
|
|
125
|
+
import { fileURLToPath } from "node:url";
|
|
126
126
|
import { BasePlugin, type GeneratorContext } from "@rexeus/typeweaver-gen";
|
|
127
127
|
|
|
128
|
-
//
|
|
129
|
-
const
|
|
128
|
+
// Resolve the directory of the current module
|
|
129
|
+
const moduleDir = path.dirname(fileURLToPath(import.meta.url));
|
|
130
130
|
|
|
131
131
|
export default class MyPlugin extends BasePlugin {
|
|
132
132
|
name = "my-plugin";
|
|
133
133
|
|
|
134
134
|
generate(context: GeneratorContext) {
|
|
135
|
-
const libSourceDir = path.join(
|
|
135
|
+
const libSourceDir = path.join(moduleDir, "lib");
|
|
136
136
|
this.copyLibFiles(context, libSourceDir, this.name); // -> <output>/lib/my-plugin
|
|
137
137
|
}
|
|
138
138
|
}
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/index.ts
|
|
31
|
+
var index_exports = {};
|
|
32
|
+
__export(index_exports, {
|
|
33
|
+
BasePlugin: () => BasePlugin,
|
|
34
|
+
BaseTemplatePlugin: () => BaseTemplatePlugin,
|
|
35
|
+
Path: () => Path,
|
|
36
|
+
PluginContextBuilder: () => PluginContextBuilder,
|
|
37
|
+
PluginDependencyError: () => PluginDependencyError,
|
|
38
|
+
PluginLoadError: () => PluginLoadError,
|
|
39
|
+
PluginRegistry: () => PluginRegistry
|
|
40
|
+
});
|
|
41
|
+
module.exports = __toCommonJS(index_exports);
|
|
42
|
+
|
|
43
|
+
// src/plugins/types.ts
|
|
44
|
+
var PluginLoadError = class extends Error {
|
|
45
|
+
constructor(pluginName, message) {
|
|
46
|
+
super(`Failed to load plugin '${pluginName}': ${message}`);
|
|
47
|
+
this.pluginName = pluginName;
|
|
48
|
+
this.name = "PluginLoadError";
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
var PluginDependencyError = class extends Error {
|
|
52
|
+
constructor(pluginName, missingDependency) {
|
|
53
|
+
super(
|
|
54
|
+
`Plugin '${pluginName}' depends on '${missingDependency}' which is not loaded`
|
|
55
|
+
);
|
|
56
|
+
this.pluginName = pluginName;
|
|
57
|
+
this.missingDependency = missingDependency;
|
|
58
|
+
this.name = "PluginDependencyError";
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
// src/plugins/BasePlugin.ts
|
|
63
|
+
var import_node_fs = __toESM(require("node:fs"), 1);
|
|
64
|
+
var import_node_path = __toESM(require("node:path"), 1);
|
|
65
|
+
var BasePlugin = class {
|
|
66
|
+
description;
|
|
67
|
+
author;
|
|
68
|
+
depends;
|
|
69
|
+
config;
|
|
70
|
+
constructor(config = {}) {
|
|
71
|
+
this.config = config;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Default implementation - override in subclasses if needed
|
|
75
|
+
*/
|
|
76
|
+
async initialize(context) {
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Default implementation - override in subclasses if needed
|
|
80
|
+
*/
|
|
81
|
+
collectResources(resources) {
|
|
82
|
+
return resources;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Default implementation - override in subclasses if needed
|
|
86
|
+
*/
|
|
87
|
+
async finalize(context) {
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Copy lib files from plugin package to generated lib folder
|
|
91
|
+
*/
|
|
92
|
+
copyLibFiles(context, libSourceDir, libNamespace) {
|
|
93
|
+
const libDir = import_node_path.default.join(context.outputDir, "lib", libNamespace);
|
|
94
|
+
import_node_fs.default.mkdirSync(libDir, { recursive: true });
|
|
95
|
+
if (import_node_fs.default.existsSync(libSourceDir)) {
|
|
96
|
+
const files = import_node_fs.default.readdirSync(libSourceDir);
|
|
97
|
+
for (const file of files) {
|
|
98
|
+
const sourcePath = import_node_path.default.join(libSourceDir, file);
|
|
99
|
+
const targetPath = import_node_path.default.join(libDir, file);
|
|
100
|
+
if (import_node_fs.default.statSync(sourcePath).isFile()) {
|
|
101
|
+
import_node_fs.default.copyFileSync(sourcePath, targetPath);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
// src/plugins/BaseTemplatePlugin.ts
|
|
109
|
+
var import_node_fs2 = __toESM(require("node:fs"), 1);
|
|
110
|
+
var import_node_path2 = __toESM(require("node:path"), 1);
|
|
111
|
+
var import_ejs = require("ejs");
|
|
112
|
+
var BaseTemplatePlugin = class extends BasePlugin {
|
|
113
|
+
/**
|
|
114
|
+
* Render an EJS template with the given data
|
|
115
|
+
*/
|
|
116
|
+
renderTemplate(templatePath, data) {
|
|
117
|
+
const template = import_node_fs2.default.readFileSync(templatePath, "utf8");
|
|
118
|
+
return (0, import_ejs.render)(template, data);
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Write a file relative to the output directory
|
|
122
|
+
*/
|
|
123
|
+
writeFile(context, relativePath, content) {
|
|
124
|
+
context.writeFile(relativePath, content);
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Ensure a directory exists
|
|
128
|
+
*/
|
|
129
|
+
ensureDir(context, relativePath) {
|
|
130
|
+
const fullPath = import_node_path2.default.join(context.outputDir, relativePath);
|
|
131
|
+
import_node_fs2.default.mkdirSync(fullPath, { recursive: true });
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Get the template path for this plugin
|
|
135
|
+
*/
|
|
136
|
+
getTemplatePath(context, templateName) {
|
|
137
|
+
return import_node_path2.default.join(context.templateDir, templateName);
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
// src/plugins/PluginRegistry.ts
|
|
142
|
+
var PluginRegistry = class {
|
|
143
|
+
plugins;
|
|
144
|
+
constructor() {
|
|
145
|
+
this.plugins = /* @__PURE__ */ new Map();
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Register a plugin
|
|
149
|
+
*/
|
|
150
|
+
register(plugin, config) {
|
|
151
|
+
if (this.plugins.has(plugin.name)) {
|
|
152
|
+
console.info(
|
|
153
|
+
`Skipping duplicate registration of required plugin: ${plugin.name}`
|
|
154
|
+
);
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
const registration = {
|
|
158
|
+
name: plugin.name,
|
|
159
|
+
plugin,
|
|
160
|
+
config
|
|
161
|
+
};
|
|
162
|
+
this.plugins.set(plugin.name, registration);
|
|
163
|
+
console.info(`Registered plugin: ${plugin.name}`);
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Get a registered plugin
|
|
167
|
+
*/
|
|
168
|
+
get(name) {
|
|
169
|
+
return this.plugins.get(name);
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Get all registered plugins
|
|
173
|
+
*/
|
|
174
|
+
getAll() {
|
|
175
|
+
return Array.from(this.plugins.values());
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Check if a plugin is registered
|
|
179
|
+
*/
|
|
180
|
+
has(name) {
|
|
181
|
+
return this.plugins.has(name);
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Clear all registered plugins (except required ones)
|
|
185
|
+
*/
|
|
186
|
+
clear() {
|
|
187
|
+
this.plugins.clear();
|
|
188
|
+
}
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
// src/plugins/PluginContext.ts
|
|
192
|
+
var import_node_fs3 = __toESM(require("node:fs"), 1);
|
|
193
|
+
var import_node_path3 = __toESM(require("node:path"), 1);
|
|
194
|
+
var import_ejs2 = require("ejs");
|
|
195
|
+
var PluginContextBuilder = class {
|
|
196
|
+
generatedFiles = /* @__PURE__ */ new Set();
|
|
197
|
+
/**
|
|
198
|
+
* Create a basic plugin context
|
|
199
|
+
*/
|
|
200
|
+
createPluginContext(params) {
|
|
201
|
+
return {
|
|
202
|
+
outputDir: params.outputDir,
|
|
203
|
+
inputDir: params.inputDir,
|
|
204
|
+
config: params.config
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Create a generator context with utilities
|
|
209
|
+
*/
|
|
210
|
+
createGeneratorContext(params) {
|
|
211
|
+
const pluginContext = this.createPluginContext(params);
|
|
212
|
+
return {
|
|
213
|
+
...pluginContext,
|
|
214
|
+
resources: params.resources,
|
|
215
|
+
templateDir: params.templateDir,
|
|
216
|
+
coreDir: params.coreDir,
|
|
217
|
+
// Utility functions
|
|
218
|
+
writeFile: (relativePath, content) => {
|
|
219
|
+
const fullPath = import_node_path3.default.join(params.outputDir, relativePath);
|
|
220
|
+
const dir = import_node_path3.default.dirname(fullPath);
|
|
221
|
+
import_node_fs3.default.mkdirSync(dir, { recursive: true });
|
|
222
|
+
import_node_fs3.default.writeFileSync(fullPath, content);
|
|
223
|
+
this.generatedFiles.add(relativePath);
|
|
224
|
+
console.info(`Generated: ${relativePath}`);
|
|
225
|
+
},
|
|
226
|
+
renderTemplate: (templatePath, data) => {
|
|
227
|
+
const fullTemplatePath = import_node_path3.default.isAbsolute(templatePath) ? templatePath : import_node_path3.default.join(params.templateDir, templatePath);
|
|
228
|
+
const template = import_node_fs3.default.readFileSync(fullTemplatePath, "utf8");
|
|
229
|
+
return (0, import_ejs2.render)(template, data);
|
|
230
|
+
},
|
|
231
|
+
addGeneratedFile: (relativePath) => {
|
|
232
|
+
this.generatedFiles.add(relativePath);
|
|
233
|
+
},
|
|
234
|
+
getGeneratedFiles: () => {
|
|
235
|
+
return Array.from(this.generatedFiles);
|
|
236
|
+
}
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Get all generated files
|
|
241
|
+
*/
|
|
242
|
+
getGeneratedFiles() {
|
|
243
|
+
return Array.from(this.generatedFiles);
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Clear generated files tracking
|
|
247
|
+
*/
|
|
248
|
+
clearGeneratedFiles() {
|
|
249
|
+
this.generatedFiles.clear();
|
|
250
|
+
}
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
// src/helpers/Path.ts
|
|
254
|
+
var import_node_path4 = __toESM(require("node:path"), 1);
|
|
255
|
+
var Path = class {
|
|
256
|
+
static relative(from, to) {
|
|
257
|
+
const relativePath = import_node_path4.default.relative(from, to);
|
|
258
|
+
if (relativePath.includes("node_modules")) {
|
|
259
|
+
const parts = relativePath.split(import_node_path4.default.sep);
|
|
260
|
+
const index = parts.indexOf("node_modules");
|
|
261
|
+
return parts.slice(index + 1).join(import_node_path4.default.sep);
|
|
262
|
+
}
|
|
263
|
+
if (!relativePath.startsWith("./") && !relativePath.startsWith("../")) {
|
|
264
|
+
return `./${relativePath}`;
|
|
265
|
+
}
|
|
266
|
+
return relativePath;
|
|
267
|
+
}
|
|
268
|
+
};
|
|
269
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
270
|
+
0 && (module.exports = {
|
|
271
|
+
BasePlugin,
|
|
272
|
+
BaseTemplatePlugin,
|
|
273
|
+
Path,
|
|
274
|
+
PluginContextBuilder,
|
|
275
|
+
PluginDependencyError,
|
|
276
|
+
PluginLoadError,
|
|
277
|
+
PluginRegistry
|
|
278
|
+
});
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
import { IHttpOperationDefinition, IHttpResponseDefinition } from '@rexeus/typeweaver-core';
|
|
2
|
+
|
|
3
|
+
type GetResourcesResult = {
|
|
4
|
+
entityResources: EntityResources;
|
|
5
|
+
sharedResponseResources: SharedResponseResource[];
|
|
6
|
+
};
|
|
7
|
+
type ExtendedResponseDefinition = IHttpResponseDefinition & {
|
|
8
|
+
statusCodeName: string;
|
|
9
|
+
isReference: boolean;
|
|
10
|
+
};
|
|
11
|
+
type EntityName = string;
|
|
12
|
+
type OperationResource = {
|
|
13
|
+
sourceDir: string;
|
|
14
|
+
sourceFile: string;
|
|
15
|
+
sourceFileName: string;
|
|
16
|
+
definition: Omit<IHttpOperationDefinition, "responses"> & {
|
|
17
|
+
responses: ExtendedResponseDefinition[];
|
|
18
|
+
};
|
|
19
|
+
outputDir: string;
|
|
20
|
+
entityName: EntityName;
|
|
21
|
+
outputRequestFile: string;
|
|
22
|
+
outputRequestFileName: string;
|
|
23
|
+
outputResponseFile: string;
|
|
24
|
+
outputResponseFileName: string;
|
|
25
|
+
outputRequestValidationFile: string;
|
|
26
|
+
outputRequestValidationFileName: string;
|
|
27
|
+
outputResponseValidationFile: string;
|
|
28
|
+
outputResponseValidationFileName: string;
|
|
29
|
+
outputClientFile: string;
|
|
30
|
+
outputClientFileName: string;
|
|
31
|
+
};
|
|
32
|
+
type EntityResources = Record<EntityName, {
|
|
33
|
+
operations: OperationResource[];
|
|
34
|
+
responses: EntityResponseResource[];
|
|
35
|
+
}>;
|
|
36
|
+
type SharedResponseResource = IHttpResponseDefinition & {
|
|
37
|
+
sourceDir: string;
|
|
38
|
+
sourceFile: string;
|
|
39
|
+
sourceFileName: string;
|
|
40
|
+
outputFile: string;
|
|
41
|
+
outputFileName: string;
|
|
42
|
+
outputDir: string;
|
|
43
|
+
};
|
|
44
|
+
type EntityResponseResource = IHttpResponseDefinition & {
|
|
45
|
+
sourceDir: string;
|
|
46
|
+
sourceFile: string;
|
|
47
|
+
sourceFileName: string;
|
|
48
|
+
outputFile: string;
|
|
49
|
+
outputFileName: string;
|
|
50
|
+
outputDir: string;
|
|
51
|
+
entityName: EntityName;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Configuration for a typeweaver plugin
|
|
56
|
+
*/
|
|
57
|
+
type PluginConfig = Record<string, unknown>;
|
|
58
|
+
/**
|
|
59
|
+
* Context provided to plugins during initialization and finalization
|
|
60
|
+
*/
|
|
61
|
+
type PluginContext = {
|
|
62
|
+
outputDir: string;
|
|
63
|
+
inputDir: string;
|
|
64
|
+
config: PluginConfig;
|
|
65
|
+
};
|
|
66
|
+
/**
|
|
67
|
+
* Context provided to plugins during generation
|
|
68
|
+
*/
|
|
69
|
+
type GeneratorContext = PluginContext & {
|
|
70
|
+
resources: GetResourcesResult;
|
|
71
|
+
templateDir: string;
|
|
72
|
+
coreDir: string;
|
|
73
|
+
writeFile: (relativePath: string, content: string) => void;
|
|
74
|
+
renderTemplate: (templatePath: string, data: unknown) => string;
|
|
75
|
+
addGeneratedFile: (relativePath: string) => void;
|
|
76
|
+
getGeneratedFiles: () => string[];
|
|
77
|
+
};
|
|
78
|
+
/**
|
|
79
|
+
* Plugin metadata
|
|
80
|
+
*/
|
|
81
|
+
type PluginMetadata = {
|
|
82
|
+
name: string;
|
|
83
|
+
};
|
|
84
|
+
/**
|
|
85
|
+
* typeweaver plugin interface
|
|
86
|
+
*/
|
|
87
|
+
type TypeweaverPlugin = PluginMetadata & {
|
|
88
|
+
/**
|
|
89
|
+
* Initialize the plugin
|
|
90
|
+
* Called before any generation happens
|
|
91
|
+
*/
|
|
92
|
+
initialize?(context: PluginContext): Promise<void> | void;
|
|
93
|
+
/**
|
|
94
|
+
* Collect and transform resources
|
|
95
|
+
* Allows plugins to modify the resource collection
|
|
96
|
+
*/
|
|
97
|
+
collectResources?(resources: GetResourcesResult): Promise<GetResourcesResult> | GetResourcesResult;
|
|
98
|
+
/**
|
|
99
|
+
* Main generation logic
|
|
100
|
+
* Called with all resources and utilities
|
|
101
|
+
*/
|
|
102
|
+
generate?(context: GeneratorContext): Promise<void> | void;
|
|
103
|
+
/**
|
|
104
|
+
* Finalize the plugin
|
|
105
|
+
* Called after all generation is complete
|
|
106
|
+
*/
|
|
107
|
+
finalize?(context: PluginContext): Promise<void> | void;
|
|
108
|
+
};
|
|
109
|
+
/**
|
|
110
|
+
* Plugin constructor type
|
|
111
|
+
*/
|
|
112
|
+
type PluginConstructor = new (config?: PluginConfig) => TypeweaverPlugin;
|
|
113
|
+
/**
|
|
114
|
+
* Plugin module export
|
|
115
|
+
*/
|
|
116
|
+
type PluginModule = {
|
|
117
|
+
default: PluginConstructor;
|
|
118
|
+
};
|
|
119
|
+
/**
|
|
120
|
+
* Plugin registration entry
|
|
121
|
+
*/
|
|
122
|
+
type PluginRegistration = {
|
|
123
|
+
name: string;
|
|
124
|
+
plugin: TypeweaverPlugin;
|
|
125
|
+
config?: PluginConfig;
|
|
126
|
+
};
|
|
127
|
+
/**
|
|
128
|
+
* typeweaver configuration
|
|
129
|
+
*/
|
|
130
|
+
type TypeweaverConfig = {
|
|
131
|
+
input: string;
|
|
132
|
+
output: string;
|
|
133
|
+
shared?: string;
|
|
134
|
+
plugins?: (string | [string, PluginConfig])[];
|
|
135
|
+
prettier?: boolean;
|
|
136
|
+
clean?: boolean;
|
|
137
|
+
};
|
|
138
|
+
/**
|
|
139
|
+
* Plugin loading error
|
|
140
|
+
*/
|
|
141
|
+
declare class PluginLoadError extends Error {
|
|
142
|
+
pluginName: string;
|
|
143
|
+
constructor(pluginName: string, message: string);
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Plugin dependency error
|
|
147
|
+
*/
|
|
148
|
+
declare class PluginDependencyError extends Error {
|
|
149
|
+
pluginName: string;
|
|
150
|
+
missingDependency: string;
|
|
151
|
+
constructor(pluginName: string, missingDependency: string);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Base class for typeweaver plugins
|
|
156
|
+
* Provides default implementations and common utilities
|
|
157
|
+
*/
|
|
158
|
+
declare abstract class BasePlugin implements TypeweaverPlugin {
|
|
159
|
+
abstract name: string;
|
|
160
|
+
description?: string;
|
|
161
|
+
author?: string;
|
|
162
|
+
depends?: string[];
|
|
163
|
+
protected config: PluginConfig;
|
|
164
|
+
constructor(config?: PluginConfig);
|
|
165
|
+
/**
|
|
166
|
+
* Default implementation - override in subclasses if needed
|
|
167
|
+
*/
|
|
168
|
+
initialize(context: PluginContext): Promise<void>;
|
|
169
|
+
/**
|
|
170
|
+
* Default implementation - override in subclasses if needed
|
|
171
|
+
*/
|
|
172
|
+
collectResources(resources: GetResourcesResult): GetResourcesResult;
|
|
173
|
+
/**
|
|
174
|
+
* Main generation logic - must be implemented by subclasses
|
|
175
|
+
*/
|
|
176
|
+
abstract generate(context: GeneratorContext): Promise<void> | void;
|
|
177
|
+
/**
|
|
178
|
+
* Default implementation - override in subclasses if needed
|
|
179
|
+
*/
|
|
180
|
+
finalize(context: PluginContext): Promise<void>;
|
|
181
|
+
/**
|
|
182
|
+
* Copy lib files from plugin package to generated lib folder
|
|
183
|
+
*/
|
|
184
|
+
protected copyLibFiles(context: GeneratorContext, libSourceDir: string, libNamespace: string): void;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Base class for template-based generator plugins
|
|
189
|
+
* Provides utilities for working with EJS templates
|
|
190
|
+
*/
|
|
191
|
+
declare abstract class BaseTemplatePlugin extends BasePlugin {
|
|
192
|
+
/**
|
|
193
|
+
* Render an EJS template with the given data
|
|
194
|
+
*/
|
|
195
|
+
protected renderTemplate(templatePath: string, data: unknown): string;
|
|
196
|
+
/**
|
|
197
|
+
* Write a file relative to the output directory
|
|
198
|
+
*/
|
|
199
|
+
protected writeFile(context: GeneratorContext, relativePath: string, content: string): void;
|
|
200
|
+
/**
|
|
201
|
+
* Ensure a directory exists
|
|
202
|
+
*/
|
|
203
|
+
protected ensureDir(context: GeneratorContext, relativePath: string): void;
|
|
204
|
+
/**
|
|
205
|
+
* Get the template path for this plugin
|
|
206
|
+
*/
|
|
207
|
+
protected getTemplatePath(context: GeneratorContext, templateName: string): string;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Registry for managing typeweaver plugins
|
|
212
|
+
*/
|
|
213
|
+
declare class PluginRegistry {
|
|
214
|
+
private plugins;
|
|
215
|
+
constructor();
|
|
216
|
+
/**
|
|
217
|
+
* Register a plugin
|
|
218
|
+
*/
|
|
219
|
+
register(plugin: TypeweaverPlugin, config?: unknown): void;
|
|
220
|
+
/**
|
|
221
|
+
* Get a registered plugin
|
|
222
|
+
*/
|
|
223
|
+
get(name: string): PluginRegistration | undefined;
|
|
224
|
+
/**
|
|
225
|
+
* Get all registered plugins
|
|
226
|
+
*/
|
|
227
|
+
getAll(): PluginRegistration[];
|
|
228
|
+
/**
|
|
229
|
+
* Check if a plugin is registered
|
|
230
|
+
*/
|
|
231
|
+
has(name: string): boolean;
|
|
232
|
+
/**
|
|
233
|
+
* Clear all registered plugins (except required ones)
|
|
234
|
+
*/
|
|
235
|
+
clear(): void;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Builder for plugin contexts
|
|
240
|
+
*/
|
|
241
|
+
declare class PluginContextBuilder {
|
|
242
|
+
private generatedFiles;
|
|
243
|
+
/**
|
|
244
|
+
* Create a basic plugin context
|
|
245
|
+
*/
|
|
246
|
+
createPluginContext(params: {
|
|
247
|
+
outputDir: string;
|
|
248
|
+
inputDir: string;
|
|
249
|
+
config: PluginConfig;
|
|
250
|
+
}): PluginContext;
|
|
251
|
+
/**
|
|
252
|
+
* Create a generator context with utilities
|
|
253
|
+
*/
|
|
254
|
+
createGeneratorContext(params: {
|
|
255
|
+
outputDir: string;
|
|
256
|
+
inputDir: string;
|
|
257
|
+
config: PluginConfig;
|
|
258
|
+
resources: GetResourcesResult;
|
|
259
|
+
templateDir: string;
|
|
260
|
+
coreDir: string;
|
|
261
|
+
}): GeneratorContext;
|
|
262
|
+
/**
|
|
263
|
+
* Get all generated files
|
|
264
|
+
*/
|
|
265
|
+
getGeneratedFiles(): string[];
|
|
266
|
+
/**
|
|
267
|
+
* Clear generated files tracking
|
|
268
|
+
*/
|
|
269
|
+
clearGeneratedFiles(): void;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
declare class Path {
|
|
273
|
+
static relative(from: string, to: string): string;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
export { BasePlugin, BaseTemplatePlugin, type EntityName, type EntityResources, type EntityResponseResource, type ExtendedResponseDefinition, type GeneratorContext, type GetResourcesResult, type OperationResource, Path, type PluginConfig, type PluginConstructor, type PluginContext, PluginContextBuilder, PluginDependencyError, PluginLoadError, type PluginMetadata, type PluginModule, type PluginRegistration, PluginRegistry, type SharedResponseResource, type TypeweaverConfig, type TypeweaverPlugin };
|
package/dist/index.d.ts
CHANGED
|
@@ -273,5 +273,4 @@ declare class Path {
|
|
|
273
273
|
static relative(from: string, to: string): string;
|
|
274
274
|
}
|
|
275
275
|
|
|
276
|
-
export { BasePlugin, BaseTemplatePlugin, Path, PluginContextBuilder, PluginDependencyError, PluginLoadError, PluginRegistry };
|
|
277
|
-
export type { EntityName, EntityResources, EntityResponseResource, ExtendedResponseDefinition, GeneratorContext, GetResourcesResult, OperationResource, PluginConfig, PluginConstructor, PluginContext, PluginMetadata, PluginModule, PluginRegistration, SharedResponseResource, TypeweaverConfig, TypeweaverPlugin };
|
|
276
|
+
export { BasePlugin, BaseTemplatePlugin, type EntityName, type EntityResources, type EntityResponseResource, type ExtendedResponseDefinition, type GeneratorContext, type GetResourcesResult, type OperationResource, Path, type PluginConfig, type PluginConstructor, type PluginContext, PluginContextBuilder, PluginDependencyError, PluginLoadError, type PluginMetadata, type PluginModule, type PluginRegistration, PluginRegistry, type SharedResponseResource, type TypeweaverConfig, type TypeweaverPlugin };
|
package/dist/index.js
CHANGED
|
@@ -1,15 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import { render } from 'ejs';
|
|
4
|
-
|
|
5
|
-
class PluginLoadError extends Error {
|
|
1
|
+
// src/plugins/types.ts
|
|
2
|
+
var PluginLoadError = class extends Error {
|
|
6
3
|
constructor(pluginName, message) {
|
|
7
4
|
super(`Failed to load plugin '${pluginName}': ${message}`);
|
|
8
5
|
this.pluginName = pluginName;
|
|
9
6
|
this.name = "PluginLoadError";
|
|
10
7
|
}
|
|
11
|
-
}
|
|
12
|
-
|
|
8
|
+
};
|
|
9
|
+
var PluginDependencyError = class extends Error {
|
|
13
10
|
constructor(pluginName, missingDependency) {
|
|
14
11
|
super(
|
|
15
12
|
`Plugin '${pluginName}' depends on '${missingDependency}' which is not loaded`
|
|
@@ -18,9 +15,12 @@ class PluginDependencyError extends Error {
|
|
|
18
15
|
this.missingDependency = missingDependency;
|
|
19
16
|
this.name = "PluginDependencyError";
|
|
20
17
|
}
|
|
21
|
-
}
|
|
18
|
+
};
|
|
22
19
|
|
|
23
|
-
|
|
20
|
+
// src/plugins/BasePlugin.ts
|
|
21
|
+
import fs from "node:fs";
|
|
22
|
+
import path from "node:path";
|
|
23
|
+
var BasePlugin = class {
|
|
24
24
|
description;
|
|
25
25
|
author;
|
|
26
26
|
depends;
|
|
@@ -61,14 +61,18 @@ class BasePlugin {
|
|
|
61
61
|
}
|
|
62
62
|
}
|
|
63
63
|
}
|
|
64
|
-
}
|
|
64
|
+
};
|
|
65
65
|
|
|
66
|
-
|
|
66
|
+
// src/plugins/BaseTemplatePlugin.ts
|
|
67
|
+
import fs2 from "node:fs";
|
|
68
|
+
import path2 from "node:path";
|
|
69
|
+
import { render } from "ejs";
|
|
70
|
+
var BaseTemplatePlugin = class extends BasePlugin {
|
|
67
71
|
/**
|
|
68
72
|
* Render an EJS template with the given data
|
|
69
73
|
*/
|
|
70
74
|
renderTemplate(templatePath, data) {
|
|
71
|
-
const template =
|
|
75
|
+
const template = fs2.readFileSync(templatePath, "utf8");
|
|
72
76
|
return render(template, data);
|
|
73
77
|
}
|
|
74
78
|
/**
|
|
@@ -81,18 +85,19 @@ class BaseTemplatePlugin extends BasePlugin {
|
|
|
81
85
|
* Ensure a directory exists
|
|
82
86
|
*/
|
|
83
87
|
ensureDir(context, relativePath) {
|
|
84
|
-
const fullPath =
|
|
85
|
-
|
|
88
|
+
const fullPath = path2.join(context.outputDir, relativePath);
|
|
89
|
+
fs2.mkdirSync(fullPath, { recursive: true });
|
|
86
90
|
}
|
|
87
91
|
/**
|
|
88
92
|
* Get the template path for this plugin
|
|
89
93
|
*/
|
|
90
94
|
getTemplatePath(context, templateName) {
|
|
91
|
-
return
|
|
95
|
+
return path2.join(context.templateDir, templateName);
|
|
92
96
|
}
|
|
93
|
-
}
|
|
97
|
+
};
|
|
94
98
|
|
|
95
|
-
|
|
99
|
+
// src/plugins/PluginRegistry.ts
|
|
100
|
+
var PluginRegistry = class {
|
|
96
101
|
plugins;
|
|
97
102
|
constructor() {
|
|
98
103
|
this.plugins = /* @__PURE__ */ new Map();
|
|
@@ -139,9 +144,13 @@ class PluginRegistry {
|
|
|
139
144
|
clear() {
|
|
140
145
|
this.plugins.clear();
|
|
141
146
|
}
|
|
142
|
-
}
|
|
147
|
+
};
|
|
143
148
|
|
|
144
|
-
|
|
149
|
+
// src/plugins/PluginContext.ts
|
|
150
|
+
import fs3 from "node:fs";
|
|
151
|
+
import path3 from "node:path";
|
|
152
|
+
import { render as render2 } from "ejs";
|
|
153
|
+
var PluginContextBuilder = class {
|
|
145
154
|
generatedFiles = /* @__PURE__ */ new Set();
|
|
146
155
|
/**
|
|
147
156
|
* Create a basic plugin context
|
|
@@ -165,17 +174,17 @@ class PluginContextBuilder {
|
|
|
165
174
|
coreDir: params.coreDir,
|
|
166
175
|
// Utility functions
|
|
167
176
|
writeFile: (relativePath, content) => {
|
|
168
|
-
const fullPath =
|
|
169
|
-
const dir =
|
|
170
|
-
|
|
171
|
-
|
|
177
|
+
const fullPath = path3.join(params.outputDir, relativePath);
|
|
178
|
+
const dir = path3.dirname(fullPath);
|
|
179
|
+
fs3.mkdirSync(dir, { recursive: true });
|
|
180
|
+
fs3.writeFileSync(fullPath, content);
|
|
172
181
|
this.generatedFiles.add(relativePath);
|
|
173
182
|
console.info(`Generated: ${relativePath}`);
|
|
174
183
|
},
|
|
175
184
|
renderTemplate: (templatePath, data) => {
|
|
176
|
-
const fullTemplatePath =
|
|
177
|
-
const template =
|
|
178
|
-
return
|
|
185
|
+
const fullTemplatePath = path3.isAbsolute(templatePath) ? templatePath : path3.join(params.templateDir, templatePath);
|
|
186
|
+
const template = fs3.readFileSync(fullTemplatePath, "utf8");
|
|
187
|
+
return render2(template, data);
|
|
179
188
|
},
|
|
180
189
|
addGeneratedFile: (relativePath) => {
|
|
181
190
|
this.generatedFiles.add(relativePath);
|
|
@@ -197,21 +206,30 @@ class PluginContextBuilder {
|
|
|
197
206
|
clearGeneratedFiles() {
|
|
198
207
|
this.generatedFiles.clear();
|
|
199
208
|
}
|
|
200
|
-
}
|
|
209
|
+
};
|
|
201
210
|
|
|
202
|
-
|
|
211
|
+
// src/helpers/Path.ts
|
|
212
|
+
import path4 from "node:path";
|
|
213
|
+
var Path = class {
|
|
203
214
|
static relative(from, to) {
|
|
204
|
-
const relativePath =
|
|
215
|
+
const relativePath = path4.relative(from, to);
|
|
205
216
|
if (relativePath.includes("node_modules")) {
|
|
206
|
-
const parts = relativePath.split(
|
|
217
|
+
const parts = relativePath.split(path4.sep);
|
|
207
218
|
const index = parts.indexOf("node_modules");
|
|
208
|
-
return parts.slice(index + 1).join(
|
|
219
|
+
return parts.slice(index + 1).join(path4.sep);
|
|
209
220
|
}
|
|
210
221
|
if (!relativePath.startsWith("./") && !relativePath.startsWith("../")) {
|
|
211
222
|
return `./${relativePath}`;
|
|
212
223
|
}
|
|
213
224
|
return relativePath;
|
|
214
225
|
}
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
|
|
226
|
+
};
|
|
227
|
+
export {
|
|
228
|
+
BasePlugin,
|
|
229
|
+
BaseTemplatePlugin,
|
|
230
|
+
Path,
|
|
231
|
+
PluginContextBuilder,
|
|
232
|
+
PluginDependencyError,
|
|
233
|
+
PluginLoadError,
|
|
234
|
+
PluginRegistry
|
|
235
|
+
};
|
package/package.json
CHANGED
|
@@ -1,14 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rexeus/typeweaver-gen",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Template-driven engine that turns structured API definitions into production-ready artifacts. Powered by Typeweaver 🧵✨",
|
|
5
5
|
"type": "module",
|
|
6
|
-
"main": "dist/index.
|
|
6
|
+
"main": "dist/index.cjs",
|
|
7
|
+
"module": "dist/index.js",
|
|
7
8
|
"types": "dist/index.d.ts",
|
|
8
9
|
"exports": {
|
|
9
10
|
".": {
|
|
10
|
-
"import":
|
|
11
|
-
|
|
11
|
+
"import": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"default": "./dist/index.js"
|
|
14
|
+
},
|
|
15
|
+
"require": {
|
|
16
|
+
"types": "./dist/index.d.cts",
|
|
17
|
+
"default": "./dist/index.cjs"
|
|
18
|
+
}
|
|
12
19
|
}
|
|
13
20
|
},
|
|
14
21
|
"files": [
|
|
@@ -39,10 +46,10 @@
|
|
|
39
46
|
},
|
|
40
47
|
"homepage": "https://github.com/rexeus/typeweaver#readme",
|
|
41
48
|
"peerDependencies": {
|
|
42
|
-
"@rexeus/typeweaver-core": "^0.
|
|
49
|
+
"@rexeus/typeweaver-core": "^0.3.0"
|
|
43
50
|
},
|
|
44
51
|
"devDependencies": {
|
|
45
|
-
"@rexeus/typeweaver-core": "^0.
|
|
52
|
+
"@rexeus/typeweaver-core": "^0.3.0"
|
|
46
53
|
},
|
|
47
54
|
"dependencies": {
|
|
48
55
|
"ejs": "^3.1.10"
|
|
@@ -50,7 +57,7 @@
|
|
|
50
57
|
"scripts": {
|
|
51
58
|
"typecheck": "tsc --noEmit",
|
|
52
59
|
"format": "prettier --write .",
|
|
53
|
-
"build": "
|
|
60
|
+
"build": "tsup && cp ../../LICENSE ../../NOTICE ./dist/",
|
|
54
61
|
"preversion": "npm run build"
|
|
55
62
|
}
|
|
56
63
|
}
|