@jay-framework/plugin-validator 0.22.1 → 0.23.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 +25 -1
- package/dist/index.js +184 -8
- package/package.json +5 -6
package/dist/index.d.ts
CHANGED
|
@@ -153,4 +153,28 @@ declare function lintAddMenuCatalog(items: AddMenuItem[], sourcePath: string): {
|
|
|
153
153
|
/** Human-readable fix hints for validate-plugin output. */
|
|
154
154
|
declare const ADD_MENU_VALIDATION_SUGGESTIONS: Record<string, string>;
|
|
155
155
|
|
|
156
|
-
|
|
156
|
+
/**
|
|
157
|
+
* AIditor Project settings contribution schema (materialized YAML).
|
|
158
|
+
* Source of truth for plugin-validator and AIditor runtime discovery.
|
|
159
|
+
*/
|
|
160
|
+
type AiditorSettingsRequire = {
|
|
161
|
+
plugin: string;
|
|
162
|
+
status: 'configured';
|
|
163
|
+
};
|
|
164
|
+
type AiditorSettingsFile = {
|
|
165
|
+
label: string;
|
|
166
|
+
route: string;
|
|
167
|
+
pluginName?: string;
|
|
168
|
+
requires?: AiditorSettingsRequire[];
|
|
169
|
+
};
|
|
170
|
+
type AiditorSettingsValidationError = {
|
|
171
|
+
path: string;
|
|
172
|
+
message: string;
|
|
173
|
+
code?: string;
|
|
174
|
+
};
|
|
175
|
+
declare function validateAiditorSettingsFile(raw: unknown, sourcePath: string): {
|
|
176
|
+
file?: AiditorSettingsFile;
|
|
177
|
+
errors: AiditorSettingsValidationError[];
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
export { ADD_MENU_VALIDATION_SUGGESTIONS, type AddMenuBrowseSize, type AddMenuCatalogFile, type AddMenuCatalogLintWarning, type AddMenuInteraction, type AddMenuItem, type AddMenuPresentation, type AddMenuValidationError, type AiditorSettingsFile, type AiditorSettingsRequire, type AiditorSettingsValidationError, type PluginContext, type ValidatePluginOptions, type ValidationError, type ValidationResult, type ValidationWarning, checkComponentPropsAndParams, lintAddMenuCatalog, validateAddMenuCatalogFile, validateAddMenuItem, validateAiditorSettingsFile, validatePlugin };
|
package/dist/index.js
CHANGED
|
@@ -279,7 +279,7 @@ const FOLDER_PATH_MAX_SEGMENTS = 32;
|
|
|
279
279
|
const BLOCKED_TAGS = /<\s*(script|iframe|object|embed)\b[^>]*>[\s\S]*?<\/\s*\1\s*>|<\s*(script|iframe|object|embed)\b[^>]*\/?>/gi;
|
|
280
280
|
const EVENT_HANDLER_ATTR = /\s+on[a-z]+\s*=\s*("[^"]*"|'[^']*'|[^\s>]+)/gi;
|
|
281
281
|
const JAVASCRIPT_URL = /\b(href|src|xlink:href)\s*=\s*("|')\s*javascript:/gi;
|
|
282
|
-
function isRecord(value) {
|
|
282
|
+
function isRecord$1(value) {
|
|
283
283
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
284
284
|
}
|
|
285
285
|
function byteLengthUtf8(value) {
|
|
@@ -349,7 +349,7 @@ function optionalString(obj, field) {
|
|
|
349
349
|
function validateInteraction(raw, itemPath, errors) {
|
|
350
350
|
if (raw === void 0)
|
|
351
351
|
return void 0;
|
|
352
|
-
if (!isRecord(raw)) {
|
|
352
|
+
if (!isRecord$1(raw)) {
|
|
353
353
|
errors.push({
|
|
354
354
|
path: itemPath,
|
|
355
355
|
message: "interaction must be an object",
|
|
@@ -374,7 +374,7 @@ function validateInteraction(raw, itemPath, errors) {
|
|
|
374
374
|
function validatePresentation(raw, itemPath, errors) {
|
|
375
375
|
if (raw === void 0)
|
|
376
376
|
return void 0;
|
|
377
|
-
if (!isRecord(raw)) {
|
|
377
|
+
if (!isRecord$1(raw)) {
|
|
378
378
|
errors.push({
|
|
379
379
|
path: itemPath,
|
|
380
380
|
message: "presentation must be an object",
|
|
@@ -447,7 +447,7 @@ const BROWSE_SIZES = /* @__PURE__ */ new Set(["large", "medium", "small"]);
|
|
|
447
447
|
function validateBrowse(raw, itemPath, errors) {
|
|
448
448
|
if (raw === void 0)
|
|
449
449
|
return void 0;
|
|
450
|
-
if (!isRecord(raw)) {
|
|
450
|
+
if (!isRecord$1(raw)) {
|
|
451
451
|
errors.push({
|
|
452
452
|
path: itemPath,
|
|
453
453
|
message: "browse must be an object",
|
|
@@ -530,7 +530,7 @@ function validateFolderPath(raw, itemPath, errors) {
|
|
|
530
530
|
}
|
|
531
531
|
function validateAddMenuItem(raw, itemPath) {
|
|
532
532
|
const errors = [];
|
|
533
|
-
if (!isRecord(raw)) {
|
|
533
|
+
if (!isRecord$1(raw)) {
|
|
534
534
|
return {
|
|
535
535
|
item: null,
|
|
536
536
|
errors: [
|
|
@@ -581,7 +581,7 @@ function validateAddMenuItem(raw, itemPath) {
|
|
|
581
581
|
}
|
|
582
582
|
function validateAddMenuCatalogFile(raw, sourcePath) {
|
|
583
583
|
const errors = [];
|
|
584
|
-
if (!isRecord(raw)) {
|
|
584
|
+
if (!isRecord$1(raw)) {
|
|
585
585
|
return {
|
|
586
586
|
file: null,
|
|
587
587
|
errors: [
|
|
@@ -940,7 +940,7 @@ function suggestionForCode(code) {
|
|
|
940
940
|
return `See ${CONTRIBUTOR_GUIDE} for schema and validation rules`;
|
|
941
941
|
return ADD_MENU_VALIDATION_SUGGESTIONS[code] ?? `See ${CONTRIBUTOR_GUIDE} for schema and validation rules`;
|
|
942
942
|
}
|
|
943
|
-
function mapSchemaError(error, catalogPath) {
|
|
943
|
+
function mapSchemaError$1(error, catalogPath) {
|
|
944
944
|
const code = error.code ?? "catalog-validation-error";
|
|
945
945
|
return {
|
|
946
946
|
type: "add-menu-catalog",
|
|
@@ -1014,7 +1014,7 @@ async function validateAddMenuCatalogFileAtPath(catalogPath, relPath, result) {
|
|
|
1014
1014
|
return;
|
|
1015
1015
|
}
|
|
1016
1016
|
const validated = validateAddMenuCatalogFile(parsed, relPath);
|
|
1017
|
-
result.errors.push(...validated.errors.map((error) => mapSchemaError(error, relPath)));
|
|
1017
|
+
result.errors.push(...validated.errors.map((error) => mapSchemaError$1(error, relPath)));
|
|
1018
1018
|
if (!validated.file?.items.length) {
|
|
1019
1019
|
return;
|
|
1020
1020
|
}
|
|
@@ -1035,6 +1035,173 @@ async function validateAddMenuCatalog(context, result) {
|
|
|
1035
1035
|
await validateAddMenuCatalogFileAtPath(catalogPath, relPath, result);
|
|
1036
1036
|
}
|
|
1037
1037
|
}
|
|
1038
|
+
function isRecord(value) {
|
|
1039
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1040
|
+
}
|
|
1041
|
+
function parseRequires(raw, filePath) {
|
|
1042
|
+
const errors = [];
|
|
1043
|
+
if (raw === void 0) {
|
|
1044
|
+
return { requires: [], errors };
|
|
1045
|
+
}
|
|
1046
|
+
if (!Array.isArray(raw)) {
|
|
1047
|
+
errors.push({
|
|
1048
|
+
path: `${filePath}.requires`,
|
|
1049
|
+
message: "requires must be an array",
|
|
1050
|
+
code: "settings-requires-type"
|
|
1051
|
+
});
|
|
1052
|
+
return { requires: [], errors };
|
|
1053
|
+
}
|
|
1054
|
+
const requires = [];
|
|
1055
|
+
raw.forEach((entry, index) => {
|
|
1056
|
+
if (!isRecord(entry)) {
|
|
1057
|
+
errors.push({
|
|
1058
|
+
path: `${filePath}.requires[${index}]`,
|
|
1059
|
+
message: "require entry must be an object",
|
|
1060
|
+
code: "settings-require-shape"
|
|
1061
|
+
});
|
|
1062
|
+
return;
|
|
1063
|
+
}
|
|
1064
|
+
if (typeof entry.plugin !== "string" || !entry.plugin.trim()) {
|
|
1065
|
+
errors.push({
|
|
1066
|
+
path: `${filePath}.requires[${index}].plugin`,
|
|
1067
|
+
message: "plugin is required",
|
|
1068
|
+
code: "settings-require-plugin"
|
|
1069
|
+
});
|
|
1070
|
+
return;
|
|
1071
|
+
}
|
|
1072
|
+
if (entry.status !== "configured") {
|
|
1073
|
+
errors.push({
|
|
1074
|
+
path: `${filePath}.requires[${index}].status`,
|
|
1075
|
+
message: 'status must be "configured"',
|
|
1076
|
+
code: "settings-require-status"
|
|
1077
|
+
});
|
|
1078
|
+
return;
|
|
1079
|
+
}
|
|
1080
|
+
requires.push({ plugin: entry.plugin.trim(), status: "configured" });
|
|
1081
|
+
});
|
|
1082
|
+
return { requires, errors };
|
|
1083
|
+
}
|
|
1084
|
+
function validateAiditorSettingsFile(raw, sourcePath) {
|
|
1085
|
+
const errors = [];
|
|
1086
|
+
if (!isRecord(raw)) {
|
|
1087
|
+
return {
|
|
1088
|
+
errors: [
|
|
1089
|
+
{
|
|
1090
|
+
path: sourcePath,
|
|
1091
|
+
message: "settings file must be a YAML object",
|
|
1092
|
+
code: "settings-root-type"
|
|
1093
|
+
}
|
|
1094
|
+
]
|
|
1095
|
+
};
|
|
1096
|
+
}
|
|
1097
|
+
if (typeof raw.label !== "string" || !raw.label.trim()) {
|
|
1098
|
+
errors.push({
|
|
1099
|
+
path: `${sourcePath}.label`,
|
|
1100
|
+
message: "label is required",
|
|
1101
|
+
code: "settings-label"
|
|
1102
|
+
});
|
|
1103
|
+
}
|
|
1104
|
+
if (typeof raw.route !== "string" || !raw.route.trim()) {
|
|
1105
|
+
errors.push({
|
|
1106
|
+
path: `${sourcePath}.route`,
|
|
1107
|
+
message: "route is required",
|
|
1108
|
+
code: "settings-route"
|
|
1109
|
+
});
|
|
1110
|
+
} else if (!raw.route.startsWith("/")) {
|
|
1111
|
+
errors.push({
|
|
1112
|
+
path: `${sourcePath}.route`,
|
|
1113
|
+
message: "route must start with /",
|
|
1114
|
+
code: "settings-route-format"
|
|
1115
|
+
});
|
|
1116
|
+
}
|
|
1117
|
+
if (raw.pluginName !== void 0 && typeof raw.pluginName !== "string") {
|
|
1118
|
+
errors.push({
|
|
1119
|
+
path: `${sourcePath}.pluginName`,
|
|
1120
|
+
message: "pluginName must be a string",
|
|
1121
|
+
code: "settings-plugin-name-type"
|
|
1122
|
+
});
|
|
1123
|
+
}
|
|
1124
|
+
const { requires, errors: requireErrors } = parseRequires(raw.requires, sourcePath);
|
|
1125
|
+
errors.push(...requireErrors);
|
|
1126
|
+
if (errors.length > 0) {
|
|
1127
|
+
return { errors };
|
|
1128
|
+
}
|
|
1129
|
+
return {
|
|
1130
|
+
file: {
|
|
1131
|
+
label: raw.label.trim(),
|
|
1132
|
+
route: raw.route.trim(),
|
|
1133
|
+
...typeof raw.pluginName === "string" && raw.pluginName.trim() ? { pluginName: raw.pluginName.trim() } : {},
|
|
1134
|
+
...requires.length > 0 ? { requires } : {}
|
|
1135
|
+
},
|
|
1136
|
+
errors: []
|
|
1137
|
+
};
|
|
1138
|
+
}
|
|
1139
|
+
const AIDITOR_SETTINGS_TEMPLATE_REL_PATH = "agent-kit/aiditor/settings.template.yaml";
|
|
1140
|
+
function mapSchemaError(error, relPath) {
|
|
1141
|
+
return {
|
|
1142
|
+
type: "schema",
|
|
1143
|
+
message: error.message,
|
|
1144
|
+
location: error.path || relPath,
|
|
1145
|
+
code: error.code
|
|
1146
|
+
};
|
|
1147
|
+
}
|
|
1148
|
+
function validateSettingsTemplateAtPath(catalogPath, relPath, result, manifest) {
|
|
1149
|
+
let parsed;
|
|
1150
|
+
try {
|
|
1151
|
+
parsed = YAML.parse(fs.readFileSync(catalogPath, "utf-8"));
|
|
1152
|
+
} catch (err) {
|
|
1153
|
+
result.errors.push({
|
|
1154
|
+
type: "schema",
|
|
1155
|
+
message: `Invalid YAML in ${relPath}: ${err instanceof Error ? err.message : String(err)}`,
|
|
1156
|
+
location: relPath
|
|
1157
|
+
});
|
|
1158
|
+
return;
|
|
1159
|
+
}
|
|
1160
|
+
const validated = validateAiditorSettingsFile(parsed, relPath);
|
|
1161
|
+
result.errors.push(...validated.errors.map((error) => mapSchemaError(error, relPath)));
|
|
1162
|
+
if (!validated.file) {
|
|
1163
|
+
return;
|
|
1164
|
+
}
|
|
1165
|
+
const routeEntry = manifest.routes?.find((route) => route.path === validated.file.route);
|
|
1166
|
+
if (!routeEntry) {
|
|
1167
|
+
result.warnings.push({
|
|
1168
|
+
type: "schema",
|
|
1169
|
+
message: `settings route "${validated.file.route}" is not declared in plugin.yaml routes[]`,
|
|
1170
|
+
location: relPath,
|
|
1171
|
+
code: "settings-route-missing",
|
|
1172
|
+
suggestion: "Add a matching routes[] entry or fix the route in settings.template.yaml"
|
|
1173
|
+
});
|
|
1174
|
+
} else if (routeEntry.devOnly !== true) {
|
|
1175
|
+
result.warnings.push({
|
|
1176
|
+
type: "schema",
|
|
1177
|
+
message: `settings route "${validated.file.route}" should declare devOnly: true on routes[]`,
|
|
1178
|
+
location: "plugin.yaml routes",
|
|
1179
|
+
code: "settings-route-dev-only",
|
|
1180
|
+
suggestion: "Add devOnly: true when the settings page is dev-server tooling (see Design Log #171)"
|
|
1181
|
+
});
|
|
1182
|
+
}
|
|
1183
|
+
}
|
|
1184
|
+
async function validateAiditorSettings(context, result) {
|
|
1185
|
+
const templatePath = path.join(context.pluginPath, AIDITOR_SETTINGS_TEMPLATE_REL_PATH);
|
|
1186
|
+
if (!fs.existsSync(templatePath)) {
|
|
1187
|
+
return;
|
|
1188
|
+
}
|
|
1189
|
+
validateSettingsTemplateAtPath(
|
|
1190
|
+
templatePath,
|
|
1191
|
+
AIDITOR_SETTINGS_TEMPLATE_REL_PATH,
|
|
1192
|
+
result,
|
|
1193
|
+
context.manifest
|
|
1194
|
+
);
|
|
1195
|
+
if (!context.manifest.agentkit) {
|
|
1196
|
+
result.warnings.push({
|
|
1197
|
+
type: "schema",
|
|
1198
|
+
message: "Plugin ships agent-kit/aiditor/settings.template.yaml but has no agentkit handler",
|
|
1199
|
+
location: "plugin.yaml",
|
|
1200
|
+
code: "settings-missing-agentkit-handler",
|
|
1201
|
+
suggestion: "Declare agentkit in plugin.yaml and materialize to agent-kit/aiditor/settings/<plugin>.yaml on jay-stack agent-kit — see agent-kit/plugin/aiditor-settings-guide.md"
|
|
1202
|
+
});
|
|
1203
|
+
}
|
|
1204
|
+
}
|
|
1038
1205
|
async function validatePlugin(options = {}) {
|
|
1039
1206
|
const pluginPath = options.pluginPath || process.cwd();
|
|
1040
1207
|
if (options.local) {
|
|
@@ -1102,6 +1269,7 @@ async function validatePluginPackage(pluginPath, options) {
|
|
|
1102
1269
|
await validateDynamicContracts(context, result);
|
|
1103
1270
|
}
|
|
1104
1271
|
await validateAddMenuCatalog(context, result);
|
|
1272
|
+
await validateAiditorSettings(context, result);
|
|
1105
1273
|
result.valid = result.errors.length === 0;
|
|
1106
1274
|
return result;
|
|
1107
1275
|
}
|
|
@@ -1411,6 +1579,13 @@ async function validateSchema(context, result) {
|
|
|
1411
1579
|
if (route.css) {
|
|
1412
1580
|
validateDocFile(route.css, `route "${route.path}" css`, context, result);
|
|
1413
1581
|
}
|
|
1582
|
+
if (route.devOnly !== void 0 && typeof route.devOnly !== "boolean") {
|
|
1583
|
+
result.errors.push({
|
|
1584
|
+
type: "schema",
|
|
1585
|
+
message: `Route "${route.path}" devOnly must be a boolean`,
|
|
1586
|
+
location: "plugin.yaml"
|
|
1587
|
+
});
|
|
1588
|
+
}
|
|
1414
1589
|
});
|
|
1415
1590
|
}
|
|
1416
1591
|
}
|
|
@@ -1942,5 +2117,6 @@ export {
|
|
|
1942
2117
|
lintAddMenuCatalog,
|
|
1943
2118
|
validateAddMenuCatalogFile,
|
|
1944
2119
|
validateAddMenuItem,
|
|
2120
|
+
validateAiditorSettingsFile,
|
|
1945
2121
|
validatePlugin
|
|
1946
2122
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jay-framework/plugin-validator",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.23.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"description": "Validation tool for Jay Stack plugins",
|
|
@@ -25,15 +25,14 @@
|
|
|
25
25
|
"test:watch": "vitest"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@jay-framework/compiler-jay-html": "^0.
|
|
29
|
-
"@jay-framework/compiler-shared": "^0.
|
|
30
|
-
"@jay-framework/
|
|
31
|
-
"@jay-framework/typescript-bridge": "^0.22.1",
|
|
28
|
+
"@jay-framework/compiler-jay-html": "^0.23.0",
|
|
29
|
+
"@jay-framework/compiler-shared": "^0.23.0",
|
|
30
|
+
"@jay-framework/typescript-bridge": "^0.23.0",
|
|
32
31
|
"chalk": "^4.1.2",
|
|
33
32
|
"yaml": "^2.3.4"
|
|
34
33
|
},
|
|
35
34
|
"devDependencies": {
|
|
36
|
-
"@jay-framework/dev-environment": "^0.
|
|
35
|
+
"@jay-framework/dev-environment": "^0.23.0",
|
|
37
36
|
"@types/node": "^22.15.21",
|
|
38
37
|
"rimraf": "^5.0.5",
|
|
39
38
|
"tsup": "^8.0.1",
|