reliant-type 2.1.3 → 2.1.5
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 +122 -688
- package/dist/cjs/core/schema/mode/interfaces/precompilation/FieldPrecompilers.js +86 -55
- package/dist/cjs/core/schema/mode/interfaces/precompilation/FieldPrecompilers.js.map +1 -1
- package/dist/cjs/core/schema/mode/interfaces/validators/mods/securityValidator.js +1 -1
- package/dist/cjs/core/schema/mode/interfaces/validators/mods/securityValidator.js.map +1 -1
- package/dist/esm/core/schema/mode/interfaces/precompilation/FieldPrecompilers.js +86 -55
- package/dist/esm/core/schema/mode/interfaces/precompilation/FieldPrecompilers.js.map +1 -1
- package/dist/esm/core/schema/mode/interfaces/validators/mods/securityValidator.js +1 -1
- package/dist/esm/core/schema/mode/interfaces/validators/mods/securityValidator.js.map +1 -1
- package/docs/GETTING-STARTED.md +56 -53
- package/docs/VSCODE-EXTENSION.md +58 -47
- package/package.json +2 -2
- package/src/core/schema/mode/interfaces/precompilation/FieldPrecompilers.ts +100 -71
- package/src/core/schema/mode/interfaces/validators/mods/securityValidator.ts +1 -1
|
@@ -705,9 +705,52 @@ export class FieldPrecompilers {
|
|
|
705
705
|
|
|
706
706
|
/**
|
|
707
707
|
* Precompile function field types (fn(() => void), etc.)
|
|
708
|
-
* ENHANCED:
|
|
708
|
+
* ENHANCED: Parses signature once at compilation time and enforces arity check at validation time.
|
|
709
709
|
*/
|
|
710
710
|
static precompileFunction(functionType: string): CompiledFieldValidator {
|
|
711
|
+
// 1. Static Parsing (Done once)
|
|
712
|
+
const type = functionType.endsWith("?")
|
|
713
|
+
? functionType.slice(0, -1)
|
|
714
|
+
: functionType;
|
|
715
|
+
const signature = type.slice(3, -1); // remove fn( and )
|
|
716
|
+
const arrowIndex = signature.lastIndexOf("=>");
|
|
717
|
+
|
|
718
|
+
let argDefs: string[] = [];
|
|
719
|
+
let returnPart = "any";
|
|
720
|
+
let minRequiredArgs = 0;
|
|
721
|
+
let hasRest = false;
|
|
722
|
+
|
|
723
|
+
if (arrowIndex !== -1) {
|
|
724
|
+
const argsPart = signature.slice(0, arrowIndex).trim();
|
|
725
|
+
returnPart = signature.slice(arrowIndex + 2).trim();
|
|
726
|
+
|
|
727
|
+
const cleanArgsPart =
|
|
728
|
+
argsPart.startsWith("(") && argsPart.endsWith(")")
|
|
729
|
+
? argsPart.slice(1, -1)
|
|
730
|
+
: argsPart;
|
|
731
|
+
|
|
732
|
+
if (cleanArgsPart && cleanArgsPart !== "()") {
|
|
733
|
+
argDefs = cleanArgsPart.split(",").map((s) => s.trim());
|
|
734
|
+
|
|
735
|
+
// Calculate minimum required arguments
|
|
736
|
+
for (const def of argDefs) {
|
|
737
|
+
const parts = def.split(":");
|
|
738
|
+
const namePart = parts[0].trim();
|
|
739
|
+
let typePart = parts.slice(1).join(":").trim() || "any";
|
|
740
|
+
if (typePart === "TYPE") typePart = "any";
|
|
741
|
+
|
|
742
|
+
const isRest = namePart.startsWith("...");
|
|
743
|
+
const isOptional = namePart.endsWith("?") || typePart.endsWith("?");
|
|
744
|
+
|
|
745
|
+
if (isRest) hasRest = true;
|
|
746
|
+
if (!isRest && !isOptional) {
|
|
747
|
+
minRequiredArgs++;
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
// 2. Validator (Runs on safeParse)
|
|
711
754
|
const validator = (value: any): SchemaValidationResult => {
|
|
712
755
|
if (typeof value !== "function") {
|
|
713
756
|
return {
|
|
@@ -718,80 +761,69 @@ export class FieldPrecompilers {
|
|
|
718
761
|
};
|
|
719
762
|
}
|
|
720
763
|
|
|
721
|
-
//
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
764
|
+
// ARITY CHECK: Validate argument count immediately
|
|
765
|
+
// Note: value.length excludes rest parameters and default values
|
|
766
|
+
if (!hasRest && value.length < minRequiredArgs) {
|
|
767
|
+
return {
|
|
768
|
+
success: false,
|
|
769
|
+
errors: [
|
|
770
|
+
{
|
|
771
|
+
message: `Function signature mismatch. Expected at least ${minRequiredArgs} arguments, but received a function with ${value.length}.`,
|
|
772
|
+
path: [],
|
|
773
|
+
code: "INVALID_FUNCTION_ARITY",
|
|
774
|
+
expected: `${minRequiredArgs} arguments`,
|
|
775
|
+
received: `${value.length} arguments`,
|
|
776
|
+
receivedType: "function",
|
|
777
|
+
},
|
|
778
|
+
],
|
|
779
|
+
warnings: [],
|
|
780
|
+
data: undefined,
|
|
781
|
+
};
|
|
730
782
|
}
|
|
731
783
|
|
|
732
|
-
const argsPart = signature.slice(0, arrowIndex).trim();
|
|
733
|
-
const returnPart = signature.slice(arrowIndex + 2).trim();
|
|
734
|
-
|
|
735
|
-
// Clean argsPart: remove outer parentheses if present
|
|
736
|
-
const cleanArgsPart =
|
|
737
|
-
argsPart.startsWith("(") && argsPart.endsWith(")")
|
|
738
|
-
? argsPart.slice(1, -1)
|
|
739
|
-
: argsPart;
|
|
740
|
-
|
|
741
784
|
// Create a wrapped function that validates on call
|
|
742
785
|
const ReliantFunction = (...args: any[]) => {
|
|
743
786
|
// 1. Validate Arguments
|
|
744
|
-
|
|
745
|
-
const
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
// Check for missing required arguments
|
|
761
|
-
// We check if the index exists in args. explicitly passing undefined is allowed if the type allows it,
|
|
762
|
-
// but not passing it at all is a missing argument error for required params.
|
|
763
|
-
if (!isRest && !isOptional && i >= args.length) {
|
|
764
|
-
throw new Error(
|
|
765
|
-
`[ReliantType] Missing required argument at index ${i} ('${namePart}'). Expected ${typePart}.`
|
|
766
|
-
);
|
|
767
|
-
}
|
|
787
|
+
for (let i = 0; i < argDefs.length; i++) {
|
|
788
|
+
const def = argDefs[i];
|
|
789
|
+
const parts = def.split(":");
|
|
790
|
+
const namePart = parts[0].trim();
|
|
791
|
+
let typePart = parts.slice(1).join(":").trim() || "any";
|
|
792
|
+
if (typePart === "TYPE") typePart = "any";
|
|
793
|
+
|
|
794
|
+
const isRest = namePart.startsWith("...");
|
|
795
|
+
const isOptional = namePart.endsWith("?") || typePart.endsWith("?");
|
|
796
|
+
|
|
797
|
+
// Check for missing required arguments
|
|
798
|
+
if (!isRest && !isOptional && i >= args.length) {
|
|
799
|
+
throw new Error(
|
|
800
|
+
`[ReliantType] Missing required argument at index ${i} ('${namePart}'). Expected ${typePart}.`
|
|
801
|
+
);
|
|
802
|
+
}
|
|
768
803
|
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
}
|
|
804
|
+
if (isRest) {
|
|
805
|
+
const restType = typePart.endsWith("[]")
|
|
806
|
+
? typePart.slice(0, -2)
|
|
807
|
+
: typePart;
|
|
808
|
+
const restArgs = args.slice(i);
|
|
809
|
+
const restValidator = FieldPrecompilers.parseAndCompile(restType);
|
|
810
|
+
for (const restArg of restArgs) {
|
|
811
|
+
const res = restValidator(restArg);
|
|
812
|
+
if (!res.success) {
|
|
813
|
+
throw new Error(
|
|
814
|
+
`[ReliantType] Argument validation failed for rest parameter at index ${i}: ${res.errors[0].message}`
|
|
815
|
+
);
|
|
782
816
|
}
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
);
|
|
794
|
-
}
|
|
817
|
+
}
|
|
818
|
+
break;
|
|
819
|
+
} else {
|
|
820
|
+
if (i < args.length) {
|
|
821
|
+
const argValidator = FieldPrecompilers.parseAndCompile(typePart);
|
|
822
|
+
const res = argValidator(args[i]);
|
|
823
|
+
if (!res.success) {
|
|
824
|
+
throw new Error(
|
|
825
|
+
`[ReliantType] Argument validation failed for argument at index ${i} ('${namePart}'): ${res.errors[0].message}`
|
|
826
|
+
);
|
|
795
827
|
}
|
|
796
828
|
}
|
|
797
829
|
}
|
|
@@ -802,9 +834,7 @@ export class FieldPrecompilers {
|
|
|
802
834
|
|
|
803
835
|
// 3. Validate Return Value
|
|
804
836
|
if (returnPart && returnPart !== "void") {
|
|
805
|
-
// Handle TYPE placeholder as any
|
|
806
837
|
const returnType = returnPart === "TYPE" ? "any" : returnPart;
|
|
807
|
-
|
|
808
838
|
if (returnType !== "any") {
|
|
809
839
|
const returnValidator =
|
|
810
840
|
FieldPrecompilers.parseAndCompile(returnType);
|
|
@@ -816,7 +846,6 @@ export class FieldPrecompilers {
|
|
|
816
846
|
}
|
|
817
847
|
}
|
|
818
848
|
}
|
|
819
|
-
|
|
820
849
|
return result;
|
|
821
850
|
};
|
|
822
851
|
|
|
@@ -44,7 +44,7 @@ export class SecurityValidators {
|
|
|
44
44
|
// security schema with more comprehensive protections
|
|
45
45
|
this.ajv.addSchema(
|
|
46
46
|
{
|
|
47
|
-
$id: "https://nehonix.
|
|
47
|
+
$id: "https://nehonix.com/lib/v/reliant-type",
|
|
48
48
|
type: ["object", "array", "string", "number", "boolean", "null"],
|
|
49
49
|
definitions: {
|
|
50
50
|
secureObject: {
|