glost-registry 0.5.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/LICENSE +21 -0
- package/README.md +283 -0
- package/dist/discovery.d.ts +146 -0
- package/dist/discovery.d.ts.map +1 -0
- package/dist/discovery.js +262 -0
- package/dist/discovery.js.map +1 -0
- package/dist/index.d.ts +35 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +34 -0
- package/dist/index.js.map +1 -0
- package/dist/registry.d.ts +193 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +466 -0
- package/dist/registry.js.map +1 -0
- package/dist/types.d.ts +208 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +9 -0
- package/dist/types.js.map +1 -0
- package/dist/validation.d.ts +53 -0
- package/dist/validation.d.ts.map +1 -0
- package/dist/validation.js +204 -0
- package/dist/validation.js.map +1 -0
- package/package.json +45 -0
- package/src/discovery.ts +315 -0
- package/src/index.ts +50 -0
- package/src/registry.ts +557 -0
- package/src/types.ts +275 -0
- package/src/validation.ts +240 -0
package/src/types.ts
ADDED
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plugin Registry Types
|
|
3
|
+
*
|
|
4
|
+
* Type definitions for the enhanced plugin registry.
|
|
5
|
+
*
|
|
6
|
+
* @packageDocumentation
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { GLOSTExtension } from "glost-extensions";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Plugin category
|
|
13
|
+
*/
|
|
14
|
+
export type PluginCategory =
|
|
15
|
+
| "transformer"
|
|
16
|
+
| "enhancer"
|
|
17
|
+
| "generator"
|
|
18
|
+
| "analyzer"
|
|
19
|
+
| "utility";
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Plugin metadata
|
|
23
|
+
*
|
|
24
|
+
* Extended metadata for plugins beyond the basic extension interface.
|
|
25
|
+
*/
|
|
26
|
+
export interface PluginMetadata {
|
|
27
|
+
/** Unique plugin identifier */
|
|
28
|
+
id: string;
|
|
29
|
+
|
|
30
|
+
/** Human-readable name */
|
|
31
|
+
name: string;
|
|
32
|
+
|
|
33
|
+
/** Plugin version (semver) */
|
|
34
|
+
version: string;
|
|
35
|
+
|
|
36
|
+
/** Description of what the plugin does */
|
|
37
|
+
description: string;
|
|
38
|
+
|
|
39
|
+
/** Plugin author */
|
|
40
|
+
author?: string;
|
|
41
|
+
|
|
42
|
+
/** Plugin repository URL */
|
|
43
|
+
repository?: string;
|
|
44
|
+
|
|
45
|
+
/** Plugin homepage/documentation URL */
|
|
46
|
+
homepage?: string;
|
|
47
|
+
|
|
48
|
+
/** Plugin category */
|
|
49
|
+
category: PluginCategory;
|
|
50
|
+
|
|
51
|
+
/** Tags for searching/filtering */
|
|
52
|
+
tags: string[];
|
|
53
|
+
|
|
54
|
+
/** Plugin capabilities */
|
|
55
|
+
supports: PluginCapabilities;
|
|
56
|
+
|
|
57
|
+
/** Dependencies */
|
|
58
|
+
requires?: PluginRequirements;
|
|
59
|
+
|
|
60
|
+
/** Conflicting plugins */
|
|
61
|
+
conflicts?: string[];
|
|
62
|
+
|
|
63
|
+
/** Configuration options schema */
|
|
64
|
+
options?: PluginOptionsSchema;
|
|
65
|
+
|
|
66
|
+
/** Usage examples */
|
|
67
|
+
examples?: PluginExample[];
|
|
68
|
+
|
|
69
|
+
/** When the plugin was registered */
|
|
70
|
+
registeredAt?: Date;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Plugin capabilities
|
|
75
|
+
*/
|
|
76
|
+
export interface PluginCapabilities {
|
|
77
|
+
/** Supported language codes */
|
|
78
|
+
languages?: string[];
|
|
79
|
+
|
|
80
|
+
/** Supported node types */
|
|
81
|
+
nodeTypes?: string[];
|
|
82
|
+
|
|
83
|
+
/** Whether the plugin supports async operations */
|
|
84
|
+
async: boolean;
|
|
85
|
+
|
|
86
|
+
/** Whether the plugin can run in parallel with others */
|
|
87
|
+
parallel?: boolean;
|
|
88
|
+
|
|
89
|
+
/** Custom capabilities */
|
|
90
|
+
custom?: Record<string, any>;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Plugin requirements
|
|
95
|
+
*/
|
|
96
|
+
export interface PluginRequirements {
|
|
97
|
+
/** Required plugins (IDs) */
|
|
98
|
+
plugins?: string[];
|
|
99
|
+
|
|
100
|
+
/** Required GLOST version (semver range) */
|
|
101
|
+
glostVersion?: string;
|
|
102
|
+
|
|
103
|
+
/** Required Node.js version (semver range) */
|
|
104
|
+
nodeVersion?: string;
|
|
105
|
+
|
|
106
|
+
/** Custom requirements */
|
|
107
|
+
custom?: Record<string, any>;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Plugin options schema
|
|
112
|
+
*/
|
|
113
|
+
export interface PluginOptionsSchema {
|
|
114
|
+
/** Schema type */
|
|
115
|
+
type: "object";
|
|
116
|
+
|
|
117
|
+
/** Properties definition */
|
|
118
|
+
properties?: Record<string, PropertySchema>;
|
|
119
|
+
|
|
120
|
+
/** Required properties */
|
|
121
|
+
required?: string[];
|
|
122
|
+
|
|
123
|
+
/** Allow additional properties */
|
|
124
|
+
additionalProperties?: boolean;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Property schema
|
|
129
|
+
*/
|
|
130
|
+
export interface PropertySchema {
|
|
131
|
+
/** Property type */
|
|
132
|
+
type: "string" | "number" | "boolean" | "array" | "object";
|
|
133
|
+
|
|
134
|
+
/** Property description */
|
|
135
|
+
description?: string;
|
|
136
|
+
|
|
137
|
+
/** Default value */
|
|
138
|
+
default?: any;
|
|
139
|
+
|
|
140
|
+
/** Enum values */
|
|
141
|
+
enum?: any[];
|
|
142
|
+
|
|
143
|
+
/** Array items schema */
|
|
144
|
+
items?: PropertySchema;
|
|
145
|
+
|
|
146
|
+
/** Object properties schema */
|
|
147
|
+
properties?: Record<string, PropertySchema>;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Plugin example
|
|
152
|
+
*/
|
|
153
|
+
export interface PluginExample {
|
|
154
|
+
/** Example title */
|
|
155
|
+
title: string;
|
|
156
|
+
|
|
157
|
+
/** Example description */
|
|
158
|
+
description?: string;
|
|
159
|
+
|
|
160
|
+
/** Example code */
|
|
161
|
+
code: string;
|
|
162
|
+
|
|
163
|
+
/** Expected output description */
|
|
164
|
+
output?: string;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Plugin query for searching
|
|
169
|
+
*/
|
|
170
|
+
export interface PluginQuery {
|
|
171
|
+
/** Search by keyword */
|
|
172
|
+
keyword?: string;
|
|
173
|
+
|
|
174
|
+
/** Filter by category */
|
|
175
|
+
category?: PluginCategory;
|
|
176
|
+
|
|
177
|
+
/** Filter by language support */
|
|
178
|
+
language?: string;
|
|
179
|
+
|
|
180
|
+
/** Filter by tags */
|
|
181
|
+
tags?: string[];
|
|
182
|
+
|
|
183
|
+
/** Filter by author */
|
|
184
|
+
author?: string;
|
|
185
|
+
|
|
186
|
+
/** Filter by capability */
|
|
187
|
+
capability?: string;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Conflict report
|
|
192
|
+
*/
|
|
193
|
+
export interface ConflictReport {
|
|
194
|
+
/** Whether conflicts were found */
|
|
195
|
+
hasConflicts: boolean;
|
|
196
|
+
|
|
197
|
+
/** Conflict details */
|
|
198
|
+
conflicts: PluginConflict[];
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Plugin conflict
|
|
203
|
+
*/
|
|
204
|
+
export interface PluginConflict {
|
|
205
|
+
/** First plugin in conflict */
|
|
206
|
+
plugin1: string;
|
|
207
|
+
|
|
208
|
+
/** Second plugin in conflict */
|
|
209
|
+
plugin2: string;
|
|
210
|
+
|
|
211
|
+
/** Conflict reason */
|
|
212
|
+
reason: string;
|
|
213
|
+
|
|
214
|
+
/** Conflict severity */
|
|
215
|
+
severity: "error" | "warning";
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Validation result
|
|
220
|
+
*/
|
|
221
|
+
export interface ValidationResult {
|
|
222
|
+
/** Whether validation passed */
|
|
223
|
+
valid: boolean;
|
|
224
|
+
|
|
225
|
+
/** Validation errors */
|
|
226
|
+
errors: ValidationError[];
|
|
227
|
+
|
|
228
|
+
/** Validation warnings */
|
|
229
|
+
warnings: ValidationWarning[];
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Validation error
|
|
234
|
+
*/
|
|
235
|
+
export interface ValidationError {
|
|
236
|
+
/** Plugin ID */
|
|
237
|
+
plugin: string;
|
|
238
|
+
|
|
239
|
+
/** Error message */
|
|
240
|
+
message: string;
|
|
241
|
+
|
|
242
|
+
/** Error code */
|
|
243
|
+
code: string;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Validation warning
|
|
248
|
+
*/
|
|
249
|
+
export interface ValidationWarning {
|
|
250
|
+
/** Plugin ID */
|
|
251
|
+
plugin: string;
|
|
252
|
+
|
|
253
|
+
/** Warning message */
|
|
254
|
+
message: string;
|
|
255
|
+
|
|
256
|
+
/** Warning code */
|
|
257
|
+
code: string;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Registry statistics
|
|
262
|
+
*/
|
|
263
|
+
export interface RegistryStatistics {
|
|
264
|
+
/** Total number of plugins */
|
|
265
|
+
total: number;
|
|
266
|
+
|
|
267
|
+
/** Plugins by category */
|
|
268
|
+
byCategory: Record<PluginCategory, number>;
|
|
269
|
+
|
|
270
|
+
/** Plugins by language */
|
|
271
|
+
byLanguage: Record<string, number>;
|
|
272
|
+
|
|
273
|
+
/** Most popular tags */
|
|
274
|
+
topTags: Array<{ tag: string; count: number }>;
|
|
275
|
+
}
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plugin Validation
|
|
3
|
+
*
|
|
4
|
+
* Validation utilities for plugin configurations and dependencies.
|
|
5
|
+
*
|
|
6
|
+
* @packageDocumentation
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type {
|
|
10
|
+
PluginMetadata,
|
|
11
|
+
ValidationResult,
|
|
12
|
+
ValidationError,
|
|
13
|
+
ValidationWarning,
|
|
14
|
+
} from "./types.js";
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Plugin validator
|
|
18
|
+
*/
|
|
19
|
+
export class PluginValidator {
|
|
20
|
+
/**
|
|
21
|
+
* Validate plugin metadata
|
|
22
|
+
*
|
|
23
|
+
* @param metadata - Plugin metadata to validate
|
|
24
|
+
* @returns Validation result
|
|
25
|
+
*/
|
|
26
|
+
static validateMetadata(metadata: PluginMetadata): ValidationResult {
|
|
27
|
+
const errors: ValidationError[] = [];
|
|
28
|
+
const warnings: ValidationWarning[] = [];
|
|
29
|
+
|
|
30
|
+
// Check required fields
|
|
31
|
+
if (!metadata.id) {
|
|
32
|
+
errors.push({
|
|
33
|
+
plugin: metadata.id || "unknown",
|
|
34
|
+
message: "Plugin ID is required",
|
|
35
|
+
code: "MISSING_ID",
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (!metadata.name) {
|
|
40
|
+
errors.push({
|
|
41
|
+
plugin: metadata.id,
|
|
42
|
+
message: "Plugin name is required",
|
|
43
|
+
code: "MISSING_NAME",
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (!metadata.version) {
|
|
48
|
+
errors.push({
|
|
49
|
+
plugin: metadata.id,
|
|
50
|
+
message: "Plugin version is required",
|
|
51
|
+
code: "MISSING_VERSION",
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (!metadata.description) {
|
|
56
|
+
warnings.push({
|
|
57
|
+
plugin: metadata.id,
|
|
58
|
+
message: "Plugin description is recommended",
|
|
59
|
+
code: "MISSING_DESCRIPTION",
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Validate version format (basic semver check)
|
|
64
|
+
if (metadata.version && !/^\d+\.\d+\.\d+/.test(metadata.version)) {
|
|
65
|
+
warnings.push({
|
|
66
|
+
plugin: metadata.id,
|
|
67
|
+
message: "Version should follow semver format (e.g., 1.0.0)",
|
|
68
|
+
code: "INVALID_VERSION_FORMAT",
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Validate category
|
|
73
|
+
const validCategories = [
|
|
74
|
+
"transformer",
|
|
75
|
+
"enhancer",
|
|
76
|
+
"generator",
|
|
77
|
+
"analyzer",
|
|
78
|
+
"utility",
|
|
79
|
+
];
|
|
80
|
+
if (!validCategories.includes(metadata.category)) {
|
|
81
|
+
errors.push({
|
|
82
|
+
plugin: metadata.id,
|
|
83
|
+
message: `Invalid category "${metadata.category}". Must be one of: ${validCategories.join(", ")}`,
|
|
84
|
+
code: "INVALID_CATEGORY",
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Validate tags
|
|
89
|
+
if (!metadata.tags || metadata.tags.length === 0) {
|
|
90
|
+
warnings.push({
|
|
91
|
+
plugin: metadata.id,
|
|
92
|
+
message: "At least one tag is recommended for discoverability",
|
|
93
|
+
code: "MISSING_TAGS",
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Validate URLs
|
|
98
|
+
if (metadata.repository && !this.isValidUrl(metadata.repository)) {
|
|
99
|
+
warnings.push({
|
|
100
|
+
plugin: metadata.id,
|
|
101
|
+
message: "Repository URL appears to be invalid",
|
|
102
|
+
code: "INVALID_REPOSITORY_URL",
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (metadata.homepage && !this.isValidUrl(metadata.homepage)) {
|
|
107
|
+
warnings.push({
|
|
108
|
+
plugin: metadata.id,
|
|
109
|
+
message: "Homepage URL appears to be invalid",
|
|
110
|
+
code: "INVALID_HOMEPAGE_URL",
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return {
|
|
115
|
+
valid: errors.length === 0,
|
|
116
|
+
errors,
|
|
117
|
+
warnings,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Validate plugin compatibility with system
|
|
123
|
+
*
|
|
124
|
+
* @param metadata - Plugin metadata
|
|
125
|
+
* @param glostVersion - Current GLOST version
|
|
126
|
+
* @param nodeVersion - Current Node.js version
|
|
127
|
+
* @returns Validation result
|
|
128
|
+
*/
|
|
129
|
+
static validateCompatibility(
|
|
130
|
+
metadata: PluginMetadata,
|
|
131
|
+
glostVersion?: string,
|
|
132
|
+
nodeVersion?: string
|
|
133
|
+
): ValidationResult {
|
|
134
|
+
const errors: ValidationError[] = [];
|
|
135
|
+
const warnings: ValidationWarning[] = [];
|
|
136
|
+
|
|
137
|
+
// Check GLOST version requirement
|
|
138
|
+
if (metadata.requires?.glostVersion && glostVersion) {
|
|
139
|
+
if (!this.isVersionCompatible(glostVersion, metadata.requires.glostVersion)) {
|
|
140
|
+
errors.push({
|
|
141
|
+
plugin: metadata.id,
|
|
142
|
+
message: `Plugin requires GLOST ${metadata.requires.glostVersion}, but ${glostVersion} is installed`,
|
|
143
|
+
code: "INCOMPATIBLE_GLOST_VERSION",
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Check Node.js version requirement
|
|
149
|
+
if (metadata.requires?.nodeVersion && nodeVersion) {
|
|
150
|
+
if (!this.isVersionCompatible(nodeVersion, metadata.requires.nodeVersion)) {
|
|
151
|
+
errors.push({
|
|
152
|
+
plugin: metadata.id,
|
|
153
|
+
message: `Plugin requires Node.js ${metadata.requires.nodeVersion}, but ${nodeVersion} is running`,
|
|
154
|
+
code: "INCOMPATIBLE_NODE_VERSION",
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return {
|
|
160
|
+
valid: errors.length === 0,
|
|
161
|
+
errors,
|
|
162
|
+
warnings,
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Validate plugin dependencies
|
|
168
|
+
*
|
|
169
|
+
* @param metadata - Plugin metadata
|
|
170
|
+
* @param availablePlugins - Set of available plugin IDs
|
|
171
|
+
* @returns Validation result
|
|
172
|
+
*/
|
|
173
|
+
static validateDependencies(
|
|
174
|
+
metadata: PluginMetadata,
|
|
175
|
+
availablePlugins: Set<string>
|
|
176
|
+
): ValidationResult {
|
|
177
|
+
const errors: ValidationError[] = [];
|
|
178
|
+
const warnings: ValidationWarning[] = [];
|
|
179
|
+
|
|
180
|
+
if (metadata.requires?.plugins) {
|
|
181
|
+
for (const dep of metadata.requires.plugins) {
|
|
182
|
+
if (!availablePlugins.has(dep)) {
|
|
183
|
+
errors.push({
|
|
184
|
+
plugin: metadata.id,
|
|
185
|
+
message: `Required plugin "${dep}" is not available`,
|
|
186
|
+
code: "MISSING_DEPENDENCY",
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
return {
|
|
193
|
+
valid: errors.length === 0,
|
|
194
|
+
errors,
|
|
195
|
+
warnings,
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Check if a version is compatible with a requirement
|
|
201
|
+
*
|
|
202
|
+
* @param version - Actual version
|
|
203
|
+
* @param requirement - Required version or range
|
|
204
|
+
* @returns True if compatible
|
|
205
|
+
*/
|
|
206
|
+
private static isVersionCompatible(
|
|
207
|
+
version: string,
|
|
208
|
+
requirement: string
|
|
209
|
+
): boolean {
|
|
210
|
+
// Simple comparison - in production would use semver library
|
|
211
|
+
// For now, just check if version >= requirement
|
|
212
|
+
const versionParts = version.split(".").map(Number);
|
|
213
|
+
const requirementParts = requirement.replace(/[^\d.]/g, "").split(".").map(Number);
|
|
214
|
+
|
|
215
|
+
for (let i = 0; i < 3; i++) {
|
|
216
|
+
const v = versionParts[i] || 0;
|
|
217
|
+
const r = requirementParts[i] || 0;
|
|
218
|
+
|
|
219
|
+
if (v > r) return true;
|
|
220
|
+
if (v < r) return false;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
return true;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Check if a string is a valid URL
|
|
228
|
+
*
|
|
229
|
+
* @param url - URL to check
|
|
230
|
+
* @returns True if valid
|
|
231
|
+
*/
|
|
232
|
+
private static isValidUrl(url: string): boolean {
|
|
233
|
+
try {
|
|
234
|
+
new URL(url);
|
|
235
|
+
return true;
|
|
236
|
+
} catch {
|
|
237
|
+
return false;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|