xdbc 1.0.73

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/src/DBC.ts ADDED
@@ -0,0 +1,355 @@
1
+ /**
2
+ * Provides a [D]esign [B]y [C]ontract Framework using decorators.
3
+ *
4
+ * @remarks
5
+ * Maintainer: Callari, Salvatore (XDBC@WaXCode.net) */
6
+ export class DBC {
7
+ // #region Parameter-value requests.
8
+ /** Stores all request for parameter values registered by {@link decPrecondition }. */
9
+ static paramValueRequests: Map<
10
+ object,
11
+ // biome-ignore lint/suspicious/noExplicitAny: Gotta be any since parameter-values may be undefined.
12
+ Map<string | symbol, Map<number, Array<(value: any) => undefined>>>
13
+ > = new Map<
14
+ object,
15
+ // biome-ignore lint/suspicious/noExplicitAny: Gotta be any since parameter-values may be undefined.
16
+ Map<string | symbol, Map<number, Array<(value: any) => undefined>>>
17
+ >();
18
+ /**
19
+ * Make a request to get the value of a certain parameter of specific method in a specific {@link object }.
20
+ * That request gets enlisted in {@link paramValueRequests } which is used by {@link ParamvalueProvider} to invoke the
21
+ * given "receptor" with the parameter value stored in there. Thus a parameter decorator using this method will
22
+ * not receive any value of the top method is not tagged with {@link ParamvalueProvider}.
23
+ *
24
+ * @param target The {@link object } containing the method with the parameter which's value is requested.
25
+ * @param methodName The name of the method with the parameter which's value is requested.
26
+ * @param index The index of the parameter which's value is requested.
27
+ * @param receptor The method the requested parameter-value shall be passed to when it becomes available. */
28
+ protected static requestParamValue(
29
+ target: object,
30
+ methodName: string | symbol,
31
+ index: number,
32
+ // biome-ignore lint/suspicious/noExplicitAny: Gotta be any since parameter-values may be undefined.
33
+ receptor: (value: any) => undefined,
34
+ ): undefined {
35
+ if (DBC.paramValueRequests.has(target)) {
36
+ if (DBC.paramValueRequests.get(target).has(methodName)) {
37
+ if (DBC.paramValueRequests.get(target).get(methodName).has(index)) {
38
+ DBC.paramValueRequests
39
+ .get(target)
40
+ .get(methodName)
41
+ .get(index)
42
+ .push(receptor);
43
+ } else {
44
+ DBC.paramValueRequests
45
+ .get(target)
46
+ .get(methodName)
47
+ .set(index, new Array<(value: unknown) => undefined>(receptor));
48
+ }
49
+ } else {
50
+ DBC.paramValueRequests
51
+ .get(target)
52
+ .set(
53
+ methodName,
54
+ new Map<number, Array<(value: unknown) => undefined>>([
55
+ [index, new Array<(value: unknown) => undefined>(receptor)],
56
+ ]),
57
+ );
58
+ }
59
+ } else {
60
+ DBC.paramValueRequests.set(
61
+ target,
62
+ new Map<
63
+ string | symbol,
64
+ Map<number, Array<(value: unknown) => undefined>>
65
+ >([
66
+ [
67
+ methodName,
68
+ new Map<number, Array<(value: unknown) => undefined>>([
69
+ [index, new Array<(value: unknown) => undefined>(receptor)],
70
+ ]),
71
+ ],
72
+ ]),
73
+ );
74
+ }
75
+
76
+ return undefined;
77
+ }
78
+ /**
79
+ * A method-decorator factory checking the {@link paramValueRequests } for value-requests of the method's parameter.
80
+ * When found it will invoke the "receptor" registered there, inter alia by {@link requestParamValue }, with the
81
+ * parameter's value.
82
+ *
83
+ * @param target The {@link object } hosting the tagged method as provided by the runtime.
84
+ * @param propertyKey The tagged method's name as provided by the runtime.
85
+ * @param descriptor The {@link PropertyDescriptor } as provided by the runtime.
86
+ *
87
+ * @returns The {@link PropertyDescriptor } that was passed by the runtime. */
88
+ public static ParamvalueProvider(
89
+ target: object,
90
+ propertyKey: string,
91
+ descriptor: PropertyDescriptor,
92
+ ): PropertyDescriptor {
93
+ const originalMethod = descriptor.value;
94
+ // biome-ignore lint/suspicious/noExplicitAny: Gotta be any since parameter-values may be undefined.
95
+ descriptor.value = (...args: any[]) => {
96
+ // #region Check if a value of one of the method's parameter has been requested and pass it to the
97
+ // receptor, if so.
98
+ if (
99
+ DBC.paramValueRequests.has(target) &&
100
+ DBC.paramValueRequests.get(target).has(propertyKey)
101
+ ) {
102
+ for (const index of DBC.paramValueRequests
103
+ .get(target)
104
+ .get(propertyKey)
105
+ .keys()) {
106
+ if (index < args.length) {
107
+ for (const receptor of DBC.paramValueRequests
108
+ .get(target)
109
+ .get(propertyKey)
110
+ .get(index)) {
111
+ receptor(args[index]);
112
+ }
113
+ }
114
+ }
115
+ }
116
+ // #endregion Check if a value of one of the method's parameter has been requested and pass it to the
117
+ // receptor, if so.
118
+ // biome-ignore lint/complexity/noThisInStatic: <explanation>
119
+ return originalMethod.apply(this, args);
120
+ };
121
+
122
+ return descriptor;
123
+ }
124
+ // #endregion Parameter-value requests.
125
+ // #region Postcondition
126
+ /**
127
+ *
128
+ * @param check
129
+ * @param dbc
130
+ * @param path
131
+ * @returns
132
+ */
133
+ public static decPostcondition(
134
+ // biome-ignore lint/suspicious/noExplicitAny: Gotta be any since parameter-values may be undefined.
135
+ check: (toCheck: any, object, string) => boolean | string,
136
+ dbc: string,
137
+ path: string | undefined = undefined,
138
+ ) {
139
+ return (
140
+ target: object,
141
+ propertyKey: string,
142
+ descriptor: PropertyDescriptor,
143
+ ): PropertyDescriptor => {
144
+ const originalMethod = descriptor.value;
145
+ // biome-ignore lint/suspicious/noExplicitAny: Gotta be any since parameter-values may be undefined.
146
+ descriptor.value = (...args: any[]) => {
147
+ // biome-ignore lint/complexity/noThisInStatic: <explanation>
148
+ const result = originalMethod.apply(this, args);
149
+ const realValue = path
150
+ ? path
151
+ ?.split(".")
152
+ .reduce((accumulator, current) => accumulator[current], result)
153
+ : result;
154
+ const checkResult = check(realValue, target, propertyKey);
155
+
156
+ if (typeof checkResult === "string") {
157
+ DBC.resolveDBCPath(window, dbc).reportReturnvalueInfringement(
158
+ checkResult,
159
+ target,
160
+ path,
161
+ propertyKey,
162
+ realValue,
163
+ );
164
+ }
165
+
166
+ return result;
167
+ };
168
+
169
+ return descriptor;
170
+ };
171
+ }
172
+ // #endregion Postcondition
173
+ // #region Decorator
174
+ // #region Parameter
175
+ /**
176
+ * A parameter-decorator factory that requests the tagged parameter's value passing it to the provided
177
+ * "check"-method when the value becomes available.
178
+ *
179
+ * @param check The "( unknown ) => void" to be invoked along with the tagged parameter's value as soon
180
+ * as it becomes available.
181
+ * @param path The dotted path referring to the actual value to check, starting form the specified one.
182
+ * @param dbc See {@link DBC.resolveDBCPath }.
183
+ *
184
+ * @returns The { (target: object, methodName: string | symbol, parameterIndex: number ) => void } invoked by Typescript- */
185
+ protected static decPrecondition(
186
+ check: (unknown, object, string, number) => boolean | string,
187
+ dbc: string,
188
+ path: string | undefined = undefined,
189
+ ): (
190
+ target: object,
191
+ methodName: string | symbol,
192
+ parameterIndex: number,
193
+ ) => void {
194
+ return (
195
+ target: object,
196
+ methodName: string | symbol,
197
+ parameterIndex: number,
198
+ ): void => {
199
+ DBC.requestParamValue(
200
+ target,
201
+ methodName,
202
+ parameterIndex,
203
+ (value: unknown) => {
204
+ const realValue = path
205
+ ? path
206
+ ?.split(".")
207
+ .reduce((accumulator, current) => accumulator[current], value)
208
+ : value;
209
+ const result = check(realValue, target, methodName, parameterIndex);
210
+
211
+ if (typeof result === "string") {
212
+ DBC.resolveDBCPath(window, dbc).reportParameterInfringement(
213
+ result,
214
+ target,
215
+ path,
216
+ methodName as string,
217
+ parameterIndex,
218
+ realValue,
219
+ );
220
+ }
221
+ },
222
+ );
223
+ };
224
+ }
225
+ // #endregion Parameter
226
+ // #endregion Decorator
227
+ // #region Warning handling.
228
+ /** Stores settings concerning warnings. */
229
+ public warningSettings: {
230
+ logToConsole: boolean;
231
+ } = { logToConsole: true };
232
+ /**
233
+ * Reports a warning.
234
+ *
235
+ * @param message The message containing the warning. */
236
+ protected reportWarning(message: string): undefined {
237
+ if (this.warningSettings.logToConsole) {
238
+ console.warn(message);
239
+ }
240
+ }
241
+ // #endregion Warning handling.
242
+ // #region infringement handling.
243
+ /** Stores the setting concerning infringements */
244
+ public infringementSettings: {
245
+ throwException: boolean;
246
+ logToConsole: boolean;
247
+ } = { throwException: true, logToConsole: false };
248
+ /**
249
+ * Reports an infringement according to the {@link infringementSettings } also generating a proper {@link string }-wrapper
250
+ * for the given "message" & violator.
251
+ *
252
+ * @param message The {@link string } describing the infringement and it's provenience.
253
+ * @param violator The {@link string } describing or naming the violator. */
254
+ protected reportInfringement(
255
+ message: string,
256
+ violator: string,
257
+ target: object,
258
+ path: string,
259
+ ): undefined {
260
+ const finalMessage: string = `[ From "${violator}"${path ? `'s member "${path}"` : ""}${typeof target === "function" ? ` in "${target.name}"` : typeof target === "object" && target !== null && typeof target.constructor === "function" ? ` in "${target.constructor.name}"` : ""}: ${message}]`;
261
+
262
+ if (this.infringementSettings.throwException) {
263
+ throw new DBC.Infringement(finalMessage);
264
+ }
265
+
266
+ if (this.infringementSettings.logToConsole) {
267
+ console.log(finalMessage);
268
+ }
269
+ }
270
+ /**
271
+ * Reports a parameter-infringement according via {@link reportInfringement } also generating a proper {@link string }-wrapper
272
+ * for the given "message","method", parameter-"index" & value.
273
+ *
274
+ * @param message The {@link string } describing the infringement and it's provenience.
275
+ * @param method The {@link string } describing or naming the violator.
276
+ * @param index The index of the parameter within the argument listing.
277
+ * @param value The parameter's value. */
278
+ public reportParameterInfringement(
279
+ message: string,
280
+ target: object,
281
+ path: string,
282
+ method: string,
283
+ index: number,
284
+ value: unknown,
285
+ ): undefined {
286
+ const properIndex = index + 1;
287
+
288
+ this.reportInfringement(
289
+ `[ Parameter-value "${value}" of the ${properIndex}${properIndex === 1 ? "st" : properIndex === 2 ? "nd" : properIndex === 3 ? "rd" : "th"} parameter did not fulfill one of it's contracts: ${message}]`,
290
+ method,
291
+ target,
292
+ path,
293
+ );
294
+ }
295
+ /**
296
+ * Reports a returnvalue-infringement according via {@link reportInfringement } also generating a proper {@link string }-wrapper
297
+ * for the given "message","method" & value.
298
+ *
299
+ * @param message The {@link string } describing the infringement and it's provenience.
300
+ * @param method The {@link string } describing or naming the violator.
301
+ * @param value The parameter's value. */
302
+ public reportReturnvalueInfringement(
303
+ message: string,
304
+ target: object,
305
+ path: string,
306
+ method: string,
307
+ // biome-ignore lint/suspicious/noExplicitAny: <explanation>
308
+ value: any,
309
+ ) {
310
+ this.reportInfringement(
311
+ `[ Return-value "${value}" did not fulfill one of it's contracts: ${message}]`,
312
+ method,
313
+ target,
314
+ path,
315
+ );
316
+ }
317
+ // #region Classes
318
+ // #region Errors
319
+ /** An {@link Error } to be thrown whenever an infringement is detected. */
320
+ public static Infringement = class extends Error {
321
+ /**
322
+ * Constructs this {@link Error } by tagging the specified message-{@link string } as an XDBC-Infringement.
323
+ *
324
+ * @param message The {@link string } describing the infringement. */
325
+ constructor(message: string) {
326
+ super(`[ XDBC Infringement ${message}]`);
327
+ }
328
+ };
329
+ // #endregion Errors
330
+ // #endregion Classes
331
+ // #endregion infringement handling.
332
+ static resolveDBCPath = (obj, path): DBC =>
333
+ path
334
+ ?.split(".")
335
+ .reduce((accumulator, current) => accumulator[current], obj);
336
+ /**
337
+ *
338
+ * @param infringementSettings
339
+ */
340
+ constructor(
341
+ infringementSettings: {
342
+ throwException: boolean;
343
+ logToConsole: boolean;
344
+ } = { throwException: true, logToConsole: false },
345
+ ) {
346
+ this.infringementSettings = infringementSettings;
347
+
348
+ // biome-ignore lint/suspicious/noExplicitAny: <explanation>
349
+ if ((window as any).WaXCode === undefined) (window as any).WaXCode = {};
350
+ // biome-ignore lint/suspicious/noExplicitAny: <explanation>
351
+ (window as any).WaXCode.DBC = this;
352
+ }
353
+ }
354
+
355
+ new DBC();
package/src/test.ts ADDED
@@ -0,0 +1,61 @@
1
+ import { DBC } from "./DBC.js";
2
+ import { REGEX } from "./DBC/REGEX.js";
3
+ import { EQ } from "./DBC/EQ.js";
4
+ import { TYPE } from "./DBC/TYPE.js";
5
+ import { AE } from "./DBC/AE.js";
6
+ import { INSTANCE } from "./DBC/INSTANCE.js";
7
+
8
+ export class Calculator {
9
+ @REGEX.POST(/xxxx*/g)
10
+ @DBC.ParamvalueProvider
11
+ public divide(@REGEX.PRE(/holla*/g) a: string, b: number): string {
12
+ console.log(a);
13
+
14
+ return a;
15
+ }
16
+ @DBC.ParamvalueProvider
17
+ public HT(
18
+ @EQ.PRE("SELECT" as unknown as object, true, "tagName") o: HTMLElement,
19
+ ) {}
20
+ @DBC.ParamvalueProvider
21
+ public type(@TYPE.PRE("string") o: unknown) {}
22
+
23
+ @DBC.ParamvalueProvider
24
+ public array(@AE.PRE([new TYPE("string")]) x: Array<unknown>) {}
25
+
26
+ @DBC.ParamvalueProvider
27
+ public regex(
28
+ @AE.PRE(new REGEX(/^(?i:(NOW)|([+-]\d+[dmy]))$/i)) x: Array<string>,
29
+ ) {}
30
+
31
+ @DBC.ParamvalueProvider
32
+ public index(
33
+ @AE.PRE(new REGEX(/^\d$/i), 0)
34
+ @AE.PRE(new REGEX(/^(?i:(NOW)|([+-]\d+[dmy]))$/i), 1)
35
+ x: Array<string>,
36
+ ) {}
37
+
38
+ @DBC.ParamvalueProvider
39
+ // biome-ignore lint/suspicious/noExplicitAny: Test
40
+ public instance(@INSTANCE.PRE(Date) candidate: any): undefined {}
41
+ @DBC.ParamvalueProvider
42
+ public range(
43
+ // biome-ignore lint/suspicious/noExplicitAny: Test
44
+ @AE.PRE([new TYPE("string"), new REGEX(/^abc$/)], 1, 2) x: Array<any>,
45
+ ) {}
46
+ // biome-ignore lint/suspicious/noExplicitAny: Test
47
+ @AE.POST(new EQ(null, true), 0)
48
+ public invert(g: string) {
49
+ return null;
50
+ }
51
+ }
52
+
53
+ console.log("s");
54
+ //new Calculator().divide("xxxx", 1);
55
+ //new Calculator().HT(document.createElement("select"));
56
+ //new Calculator().type("10");
57
+ //new Calculator().array([11, "10", "b"]);
58
+ //new Calculator().index(["1a", "+d1m", "-x10y"]);
59
+ //new Calculator().instance(new Date());
60
+ //new Calculator().range([11, "abc", "abc"]);
61
+ new Calculator().invert("");
package/test.js ADDED
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Calculator = void 0;
4
+ var Calculator = /** @class */ (function () {
5
+ function Calculator() {
6
+ }
7
+ // @DBC.log
8
+ Calculator.prototype.divide = function (@REGEX.PRE("r") a, b) {
9
+ return a / b;
10
+ };
11
+ return Calculator;
12
+ }());
13
+ exports.Calculator = Calculator;
14
+ alert(new Calculator().divide(2, 1));
package/test.ts ADDED
@@ -0,0 +1,11 @@
1
+ import { DBC } from "./DBC.js";
2
+ import { REGEX } from "./DBC/REGEX.js";
3
+
4
+ export class Calculator {
5
+ @DBC.log
6
+ public divide(@REGEX.PRE("r") a: number, b: number): number {
7
+ return a / b;
8
+ }
9
+ }
10
+
11
+ alert(new Calculator().divide(2, 1));
package/tsconfig.json ADDED
@@ -0,0 +1,15 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES6",
4
+ "experimentalDecorators": true,
5
+ "emitDecoratorMetadata": true,
6
+ "outDir": "./dist",
7
+ "module": "es6",
8
+ "typeRoots": []
9
+ },
10
+
11
+ "include": [
12
+ "./src/**/*.ts" // or your source directories
13
+ ],
14
+ "exclude": ["node_modules"]
15
+ }