@jay-framework/plugin-validator 0.10.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/dist/index.d.ts +46 -0
- package/dist/index.js +413 -0
- package/package.json +42 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { PluginManifest } from '@jay-framework/editor-protocol';
|
|
2
|
+
|
|
3
|
+
interface ValidatePluginOptions {
|
|
4
|
+
pluginPath?: string;
|
|
5
|
+
local?: boolean;
|
|
6
|
+
verbose?: boolean;
|
|
7
|
+
strict?: boolean;
|
|
8
|
+
generateTypes?: boolean;
|
|
9
|
+
}
|
|
10
|
+
interface ValidationResult {
|
|
11
|
+
valid: boolean;
|
|
12
|
+
errors: ValidationError[];
|
|
13
|
+
warnings: ValidationWarning[];
|
|
14
|
+
pluginName?: string;
|
|
15
|
+
contractsChecked?: number;
|
|
16
|
+
componentsChecked?: number;
|
|
17
|
+
packageJsonChecked?: boolean;
|
|
18
|
+
typesGenerated?: number;
|
|
19
|
+
}
|
|
20
|
+
interface ValidationError {
|
|
21
|
+
type: 'schema' | 'file-missing' | 'export-mismatch' | 'contract-invalid' | 'type-generation-failed';
|
|
22
|
+
message: string;
|
|
23
|
+
location?: string;
|
|
24
|
+
suggestion?: string;
|
|
25
|
+
}
|
|
26
|
+
interface ValidationWarning {
|
|
27
|
+
type: string;
|
|
28
|
+
message: string;
|
|
29
|
+
location?: string;
|
|
30
|
+
suggestion?: string;
|
|
31
|
+
}
|
|
32
|
+
interface PluginContext {
|
|
33
|
+
manifest: PluginManifest;
|
|
34
|
+
pluginPath: string;
|
|
35
|
+
isNpmPackage: boolean;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Validates a Jay Stack plugin package or local plugin directory.
|
|
40
|
+
*
|
|
41
|
+
* @param options - Validation options
|
|
42
|
+
* @returns Validation result with errors and warnings
|
|
43
|
+
*/
|
|
44
|
+
declare function validatePlugin(options?: ValidatePluginOptions): Promise<ValidationResult>;
|
|
45
|
+
|
|
46
|
+
export { type PluginContext, type ValidatePluginOptions, type ValidationError, type ValidationResult, type ValidationWarning, validatePlugin };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,413 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import YAML from "yaml";
|
|
4
|
+
import { loadPluginManifest } from "@jay-framework/compiler-shared";
|
|
5
|
+
async function validatePlugin(options = {}) {
|
|
6
|
+
const pluginPath = options.pluginPath || process.cwd();
|
|
7
|
+
if (options.local) {
|
|
8
|
+
return validateLocalPlugins(pluginPath, options);
|
|
9
|
+
} else {
|
|
10
|
+
return validatePluginPackage(pluginPath, options);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
async function validatePluginPackage(pluginPath, options) {
|
|
14
|
+
const result = {
|
|
15
|
+
valid: true,
|
|
16
|
+
errors: [],
|
|
17
|
+
warnings: [],
|
|
18
|
+
contractsChecked: 0,
|
|
19
|
+
componentsChecked: 0
|
|
20
|
+
};
|
|
21
|
+
const pluginYamlPath = path.join(pluginPath, "plugin.yaml");
|
|
22
|
+
const pluginManifest = loadPluginManifest(pluginPath);
|
|
23
|
+
if (!pluginManifest) {
|
|
24
|
+
if (!fs.existsSync(pluginYamlPath)) {
|
|
25
|
+
result.errors.push({
|
|
26
|
+
type: "file-missing",
|
|
27
|
+
message: "plugin.yaml not found",
|
|
28
|
+
location: pluginPath,
|
|
29
|
+
suggestion: "Create a plugin.yaml file in the plugin root directory"
|
|
30
|
+
});
|
|
31
|
+
} else {
|
|
32
|
+
result.errors.push({
|
|
33
|
+
type: "schema",
|
|
34
|
+
message: "Invalid YAML syntax or format",
|
|
35
|
+
location: pluginYamlPath
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
result.valid = false;
|
|
39
|
+
return result;
|
|
40
|
+
}
|
|
41
|
+
result.pluginName = pluginManifest.name;
|
|
42
|
+
const context = {
|
|
43
|
+
manifest: pluginManifest,
|
|
44
|
+
pluginPath,
|
|
45
|
+
isNpmPackage: fs.existsSync(path.join(pluginPath, "package.json"))
|
|
46
|
+
};
|
|
47
|
+
await validateSchema(context, result);
|
|
48
|
+
if (pluginManifest.contracts) {
|
|
49
|
+
for (let i = 0; i < pluginManifest.contracts.length; i++) {
|
|
50
|
+
await validateContract(
|
|
51
|
+
pluginManifest.contracts[i],
|
|
52
|
+
i,
|
|
53
|
+
context,
|
|
54
|
+
options.generateTypes || false,
|
|
55
|
+
result
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
if (pluginManifest.contracts) {
|
|
60
|
+
for (let i = 0; i < pluginManifest.contracts.length; i++) {
|
|
61
|
+
await validateComponent(pluginManifest.contracts[i], i, context, result);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
if (context.isNpmPackage) {
|
|
65
|
+
await validatePackageJson(context, result);
|
|
66
|
+
result.packageJsonChecked = true;
|
|
67
|
+
}
|
|
68
|
+
if (pluginManifest.dynamic_contracts) {
|
|
69
|
+
await validateDynamicContracts(context, result);
|
|
70
|
+
}
|
|
71
|
+
result.valid = result.errors.length === 0;
|
|
72
|
+
return result;
|
|
73
|
+
}
|
|
74
|
+
async function validateLocalPlugins(projectPath, options) {
|
|
75
|
+
const pluginsPath = path.join(projectPath, "src/plugins");
|
|
76
|
+
if (!fs.existsSync(pluginsPath)) {
|
|
77
|
+
return {
|
|
78
|
+
valid: false,
|
|
79
|
+
errors: [
|
|
80
|
+
{
|
|
81
|
+
type: "file-missing",
|
|
82
|
+
message: "src/plugins/ directory not found",
|
|
83
|
+
location: projectPath,
|
|
84
|
+
suggestion: "Create src/plugins/ directory for local plugins"
|
|
85
|
+
}
|
|
86
|
+
],
|
|
87
|
+
warnings: []
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
const pluginDirs = fs.readdirSync(pluginsPath, { withFileTypes: true }).filter((d) => d.isDirectory());
|
|
91
|
+
const allResults = [];
|
|
92
|
+
for (const pluginDir of pluginDirs) {
|
|
93
|
+
const pluginPath = path.join(pluginsPath, pluginDir.name);
|
|
94
|
+
const result = await validatePluginPackage(pluginPath, options);
|
|
95
|
+
allResults.push(result);
|
|
96
|
+
}
|
|
97
|
+
return {
|
|
98
|
+
valid: allResults.every((r) => r.valid),
|
|
99
|
+
errors: allResults.flatMap((r) => r.errors),
|
|
100
|
+
warnings: allResults.flatMap((r) => r.warnings),
|
|
101
|
+
contractsChecked: allResults.reduce((sum, r) => sum + (r.contractsChecked || 0), 0),
|
|
102
|
+
componentsChecked: allResults.reduce((sum, r) => sum + (r.componentsChecked || 0), 0),
|
|
103
|
+
typesGenerated: allResults.reduce((sum, r) => sum + (r.typesGenerated || 0), 0)
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
async function validateSchema(context, result) {
|
|
107
|
+
const { manifest } = context;
|
|
108
|
+
if (!manifest.name) {
|
|
109
|
+
result.errors.push({
|
|
110
|
+
type: "schema",
|
|
111
|
+
message: "Missing required field: name",
|
|
112
|
+
location: "plugin.yaml",
|
|
113
|
+
suggestion: 'Add a "name" field with a kebab-case plugin name'
|
|
114
|
+
});
|
|
115
|
+
} else if (!/^[a-z0-9]+(-[a-z0-9]+)*$/.test(manifest.name)) {
|
|
116
|
+
result.errors.push({
|
|
117
|
+
type: "schema",
|
|
118
|
+
message: `Invalid plugin name: "${manifest.name}". Must be kebab-case.`,
|
|
119
|
+
location: "plugin.yaml",
|
|
120
|
+
suggestion: 'Use lowercase letters, numbers, and hyphens only (e.g., "my-plugin")'
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
if (manifest.contracts) {
|
|
124
|
+
if (!Array.isArray(manifest.contracts)) {
|
|
125
|
+
result.errors.push({
|
|
126
|
+
type: "schema",
|
|
127
|
+
message: 'Field "contracts" must be an array',
|
|
128
|
+
location: "plugin.yaml"
|
|
129
|
+
});
|
|
130
|
+
} else {
|
|
131
|
+
manifest.contracts.forEach((contract, index) => {
|
|
132
|
+
if (!contract.name) {
|
|
133
|
+
result.errors.push({
|
|
134
|
+
type: "schema",
|
|
135
|
+
message: `Contract at index ${index} is missing "name" field`,
|
|
136
|
+
location: "plugin.yaml"
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
if (!contract.contract) {
|
|
140
|
+
result.errors.push({
|
|
141
|
+
type: "schema",
|
|
142
|
+
message: `Contract "${contract.name || index}" is missing "contract" field`,
|
|
143
|
+
location: "plugin.yaml",
|
|
144
|
+
suggestion: "Specify path to .jay-contract file"
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
if (!contract.component) {
|
|
148
|
+
result.errors.push({
|
|
149
|
+
type: "schema",
|
|
150
|
+
message: `Contract "${contract.name || index}" is missing "component" field`,
|
|
151
|
+
location: "plugin.yaml",
|
|
152
|
+
suggestion: 'Specify the exported member name from the module (e.g., "moodTracker")'
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
if (manifest.dynamic_contracts) {
|
|
159
|
+
if (!manifest.dynamic_contracts.component) {
|
|
160
|
+
result.errors.push({
|
|
161
|
+
type: "schema",
|
|
162
|
+
message: 'dynamic_contracts is missing "component" field',
|
|
163
|
+
location: "plugin.yaml",
|
|
164
|
+
suggestion: "Specify path to shared component for dynamic contracts"
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
if (!manifest.dynamic_contracts.generator) {
|
|
168
|
+
result.errors.push({
|
|
169
|
+
type: "schema",
|
|
170
|
+
message: 'dynamic_contracts is missing "generator" field',
|
|
171
|
+
location: "plugin.yaml",
|
|
172
|
+
suggestion: "Specify path to generator file"
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
if (!manifest.dynamic_contracts.prefix) {
|
|
176
|
+
result.errors.push({
|
|
177
|
+
type: "schema",
|
|
178
|
+
message: 'dynamic_contracts is missing "prefix" field',
|
|
179
|
+
location: "plugin.yaml",
|
|
180
|
+
suggestion: 'Specify prefix for dynamic contract names (e.g., "cms")'
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
if (!manifest.contracts && !manifest.dynamic_contracts) {
|
|
185
|
+
result.warnings.push({
|
|
186
|
+
type: "schema",
|
|
187
|
+
message: "Plugin has no contracts or dynamic_contracts defined",
|
|
188
|
+
location: "plugin.yaml",
|
|
189
|
+
suggestion: 'Add either "contracts" or "dynamic_contracts" to expose functionality'
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
async function validateContract(contract, index, context, generateTypes, result) {
|
|
194
|
+
result.contractsChecked = (result.contractsChecked || 0) + 1;
|
|
195
|
+
let contractPath;
|
|
196
|
+
if (context.isNpmPackage) {
|
|
197
|
+
const contractSpec = contract.contract;
|
|
198
|
+
const possiblePaths = [
|
|
199
|
+
path.join(context.pluginPath, "dist", contractSpec),
|
|
200
|
+
path.join(context.pluginPath, "lib", contractSpec),
|
|
201
|
+
path.join(context.pluginPath, contractSpec)
|
|
202
|
+
];
|
|
203
|
+
let found = false;
|
|
204
|
+
for (const possiblePath of possiblePaths) {
|
|
205
|
+
if (fs.existsSync(possiblePath)) {
|
|
206
|
+
contractPath = possiblePath;
|
|
207
|
+
found = true;
|
|
208
|
+
break;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
if (!found) {
|
|
212
|
+
result.errors.push({
|
|
213
|
+
type: "file-missing",
|
|
214
|
+
message: `Contract file not found: ${contractSpec}`,
|
|
215
|
+
location: `plugin.yaml contracts[${index}]`,
|
|
216
|
+
suggestion: `Ensure the contract file exists (looked in dist/, lib/, and root)`
|
|
217
|
+
});
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
} else {
|
|
221
|
+
contractPath = path.join(context.pluginPath, contract.contract);
|
|
222
|
+
if (!fs.existsSync(contractPath)) {
|
|
223
|
+
result.errors.push({
|
|
224
|
+
type: "file-missing",
|
|
225
|
+
message: `Contract file not found: ${contract.contract}`,
|
|
226
|
+
location: `plugin.yaml contracts[${index}]`,
|
|
227
|
+
suggestion: `Create the contract file at ${contractPath}`
|
|
228
|
+
});
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
try {
|
|
233
|
+
const contractContent = await fs.promises.readFile(contractPath, "utf-8");
|
|
234
|
+
const parsedContract = YAML.parse(contractContent);
|
|
235
|
+
if (!parsedContract.name) {
|
|
236
|
+
result.errors.push({
|
|
237
|
+
type: "contract-invalid",
|
|
238
|
+
message: `Contract file ${contract.contract} is missing "name" field`,
|
|
239
|
+
location: contractPath
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
if (!parsedContract.tags || !Array.isArray(parsedContract.tags)) {
|
|
243
|
+
result.errors.push({
|
|
244
|
+
type: "contract-invalid",
|
|
245
|
+
message: `Contract file ${contract.contract} is missing "tags" array`,
|
|
246
|
+
location: contractPath
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
} catch (error) {
|
|
250
|
+
result.errors.push({
|
|
251
|
+
type: "contract-invalid",
|
|
252
|
+
message: `Invalid contract YAML: ${error.message}`,
|
|
253
|
+
location: contractPath,
|
|
254
|
+
suggestion: "Check YAML syntax and ensure it follows Jay contract format"
|
|
255
|
+
});
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
if (generateTypes) {
|
|
259
|
+
try {
|
|
260
|
+
const { compileContractFile } = await import("@jay-framework/compiler-jay-html");
|
|
261
|
+
const dtsPath = contractPath + ".d.ts";
|
|
262
|
+
await compileContractFile(contractPath, dtsPath);
|
|
263
|
+
result.typesGenerated = (result.typesGenerated || 0) + 1;
|
|
264
|
+
} catch (error) {
|
|
265
|
+
result.errors.push({
|
|
266
|
+
type: "type-generation-failed",
|
|
267
|
+
message: `Failed to generate types for ${contract.contract}: ${error.message}`,
|
|
268
|
+
location: contractPath
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
async function validateComponent(contract, index, context, result) {
|
|
274
|
+
result.componentsChecked = (result.componentsChecked || 0) + 1;
|
|
275
|
+
if (typeof contract.component !== "string" || contract.component.length === 0) {
|
|
276
|
+
result.errors.push({
|
|
277
|
+
type: "schema",
|
|
278
|
+
message: `Invalid component name: ${contract.component}`,
|
|
279
|
+
location: `plugin.yaml contracts[${index}]`,
|
|
280
|
+
suggestion: 'Component should be the exported member name (e.g., "moodTracker")'
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
if (contract.component.includes("/") || contract.component.includes(".")) {
|
|
284
|
+
result.warnings.push({
|
|
285
|
+
type: "schema",
|
|
286
|
+
message: `Component "${contract.component}" looks like a path. Should it be an export name?`,
|
|
287
|
+
location: `plugin.yaml contracts[${index}]`,
|
|
288
|
+
suggestion: 'Component should be the exported member name (e.g., "moodTracker"), not a file path'
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
async function validatePackageJson(context, result) {
|
|
293
|
+
const packageJsonPath = path.join(context.pluginPath, "package.json");
|
|
294
|
+
if (!fs.existsSync(packageJsonPath)) {
|
|
295
|
+
result.warnings.push({
|
|
296
|
+
type: "file-missing",
|
|
297
|
+
message: "package.json not found",
|
|
298
|
+
location: context.pluginPath,
|
|
299
|
+
suggestion: "Create a package.json file for NPM package distribution"
|
|
300
|
+
});
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
try {
|
|
304
|
+
const packageJson = JSON.parse(await fs.promises.readFile(packageJsonPath, "utf-8"));
|
|
305
|
+
if (!packageJson.exports) {
|
|
306
|
+
result.warnings.push({
|
|
307
|
+
type: "export-mismatch",
|
|
308
|
+
message: 'package.json missing "exports" field',
|
|
309
|
+
location: packageJsonPath,
|
|
310
|
+
suggestion: "Add exports field to define entry points for server/client builds"
|
|
311
|
+
});
|
|
312
|
+
} else {
|
|
313
|
+
if (!packageJson.exports["."]) {
|
|
314
|
+
result.warnings.push({
|
|
315
|
+
type: "export-mismatch",
|
|
316
|
+
message: 'package.json exports missing "." entry point',
|
|
317
|
+
location: packageJsonPath,
|
|
318
|
+
suggestion: 'Add "." export for the main module entry'
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
if (context.manifest.contracts) {
|
|
322
|
+
for (const contract of context.manifest.contracts) {
|
|
323
|
+
const contractExport = "./" + contract.contract;
|
|
324
|
+
if (!packageJson.exports[contractExport]) {
|
|
325
|
+
result.errors.push({
|
|
326
|
+
type: "export-mismatch",
|
|
327
|
+
message: `Contract "${contract.name}" not exported in package.json`,
|
|
328
|
+
location: packageJsonPath,
|
|
329
|
+
suggestion: `Add "${contractExport}": "./dist/${contract.contract}" to exports field`
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
if (!packageJson.exports["."]) {
|
|
335
|
+
result.errors.push({
|
|
336
|
+
type: "export-mismatch",
|
|
337
|
+
message: 'NPM package missing "." export in package.json',
|
|
338
|
+
location: packageJsonPath,
|
|
339
|
+
suggestion: 'Add ".": "./dist/index.js" (or your main file) to exports field'
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
if (context.manifest.module) {
|
|
343
|
+
const moduleName = context.manifest.module;
|
|
344
|
+
result.warnings.push({
|
|
345
|
+
type: "schema",
|
|
346
|
+
message: 'NPM packages should omit the "module" field - the package main export will be used',
|
|
347
|
+
location: "plugin.yaml",
|
|
348
|
+
suggestion: 'Remove the "module" field from plugin.yaml'
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
if (!packageJson.exports || !packageJson.exports["./plugin.yaml"]) {
|
|
353
|
+
result.errors.push({
|
|
354
|
+
type: "export-mismatch",
|
|
355
|
+
message: "plugin.yaml not exported in package.json (required for plugin resolution)",
|
|
356
|
+
location: packageJsonPath,
|
|
357
|
+
suggestion: 'Add "./plugin.yaml": "./plugin.yaml" to exports field'
|
|
358
|
+
});
|
|
359
|
+
}
|
|
360
|
+
} catch (error) {
|
|
361
|
+
result.errors.push({
|
|
362
|
+
type: "schema",
|
|
363
|
+
message: `Invalid package.json: ${error.message}`,
|
|
364
|
+
location: packageJsonPath
|
|
365
|
+
});
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
async function validateDynamicContracts(context, result) {
|
|
369
|
+
const { dynamic_contracts } = context.manifest;
|
|
370
|
+
if (!dynamic_contracts)
|
|
371
|
+
return;
|
|
372
|
+
if (dynamic_contracts.generator) {
|
|
373
|
+
const generatorPath = path.join(context.pluginPath, dynamic_contracts.generator);
|
|
374
|
+
const possibleExtensions = [".ts", ".js", "/index.ts", "/index.js"];
|
|
375
|
+
let found = false;
|
|
376
|
+
for (const ext of possibleExtensions) {
|
|
377
|
+
if (fs.existsSync(generatorPath + ext)) {
|
|
378
|
+
found = true;
|
|
379
|
+
break;
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
if (!found && !context.isNpmPackage) {
|
|
383
|
+
result.errors.push({
|
|
384
|
+
type: "file-missing",
|
|
385
|
+
message: `Generator file not found: ${dynamic_contracts.generator}`,
|
|
386
|
+
location: "plugin.yaml dynamic_contracts",
|
|
387
|
+
suggestion: `Create generator file at ${generatorPath}.ts`
|
|
388
|
+
});
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
if (dynamic_contracts.component) {
|
|
392
|
+
const componentPath = path.join(context.pluginPath, dynamic_contracts.component);
|
|
393
|
+
const possibleExtensions = [".ts", ".js", "/index.ts", "/index.js"];
|
|
394
|
+
let found = false;
|
|
395
|
+
for (const ext of possibleExtensions) {
|
|
396
|
+
if (fs.existsSync(componentPath + ext)) {
|
|
397
|
+
found = true;
|
|
398
|
+
break;
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
if (!found && !context.isNpmPackage) {
|
|
402
|
+
result.errors.push({
|
|
403
|
+
type: "file-missing",
|
|
404
|
+
message: `Dynamic contracts component not found: ${dynamic_contracts.component}`,
|
|
405
|
+
location: "plugin.yaml dynamic_contracts",
|
|
406
|
+
suggestion: `Create component file at ${componentPath}.ts`
|
|
407
|
+
});
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
export {
|
|
412
|
+
validatePlugin
|
|
413
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@jay-framework/plugin-validator",
|
|
3
|
+
"version": "0.10.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"license": "Apache-2.0",
|
|
6
|
+
"description": "Validation tool for Jay Stack plugins",
|
|
7
|
+
"main": "dist/index.js",
|
|
8
|
+
"types": "dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": "./dist/index.js"
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"dist",
|
|
14
|
+
"readme.md"
|
|
15
|
+
],
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build": "npm run build:js && npm run build:types",
|
|
18
|
+
"build:watch": "npm run build:js -- --watch & npm run build:types -- --watch",
|
|
19
|
+
"build:js": "vite build",
|
|
20
|
+
"build:types": "tsup lib/index.ts --dts-only --format esm",
|
|
21
|
+
"build:check-types": "tsc",
|
|
22
|
+
"clean": "rimraf dist",
|
|
23
|
+
"confirm": "npm run clean && npm run build && npm run build:check-types && npm run test",
|
|
24
|
+
"test": ":",
|
|
25
|
+
"test:watch": ":"
|
|
26
|
+
},
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"@jay-framework/compiler-jay-html": "^0.10.0",
|
|
29
|
+
"@jay-framework/editor-protocol": "^0.10.0",
|
|
30
|
+
"chalk": "^4.1.2",
|
|
31
|
+
"yaml": "^2.3.4"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@jay-framework/dev-environment": "^0.10.0",
|
|
35
|
+
"@types/node": "^22.15.21",
|
|
36
|
+
"rimraf": "^5.0.5",
|
|
37
|
+
"tsup": "^8.0.1",
|
|
38
|
+
"typescript": "^5.3.3",
|
|
39
|
+
"vite": "^5.0.11",
|
|
40
|
+
"vitest": "^1.2.1"
|
|
41
|
+
}
|
|
42
|
+
}
|