@cldmv/slothlet 3.3.0 → 3.4.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.
Files changed (139) hide show
  1. package/README.md +9 -10
  2. package/REFERENCE.md +23 -0
  3. package/dist/lib/builders/api-assignment.mjs +1 -589
  4. package/dist/lib/builders/api_builder.mjs +1 -1385
  5. package/dist/lib/builders/builder.mjs +1 -78
  6. package/dist/lib/builders/modes-processor.mjs +1 -1800
  7. package/dist/lib/errors.mjs +9 -211
  8. package/dist/lib/factories/component-base.mjs +1 -80
  9. package/dist/lib/factories/context.mjs +1 -22
  10. package/dist/lib/handlers/api-cache-manager.mjs +1 -200
  11. package/dist/lib/handlers/api-manager.mjs +1 -2536
  12. package/dist/lib/handlers/context-async.mjs +1 -172
  13. package/dist/lib/handlers/context-live.mjs +1 -173
  14. package/dist/lib/handlers/hook-manager.mjs +1 -667
  15. package/dist/lib/handlers/lifecycle-token.mjs +1 -28
  16. package/dist/lib/handlers/lifecycle.mjs +1 -115
  17. package/dist/lib/handlers/materialize-manager.mjs +1 -48
  18. package/dist/lib/handlers/metadata.mjs +1 -501
  19. package/dist/lib/handlers/ownership.mjs +1 -322
  20. package/dist/lib/handlers/permission-manager.mjs +1 -392
  21. package/dist/lib/handlers/unified-wrapper.mjs +1 -3110
  22. package/dist/lib/handlers/version-manager.mjs +1 -885
  23. package/dist/lib/helpers/class-instance-wrapper.mjs +1 -109
  24. package/dist/lib/helpers/config.mjs +1 -439
  25. package/dist/lib/helpers/eventemitter-context.mjs +1 -349
  26. package/dist/lib/helpers/hint-detector.mjs +1 -47
  27. package/dist/lib/helpers/modes-utils.mjs +1 -37
  28. package/dist/lib/helpers/pattern-matcher.mjs +1 -125
  29. package/dist/lib/helpers/resolve-from-caller.mjs +1 -169
  30. package/dist/lib/helpers/sanitize.mjs +1 -340
  31. package/dist/lib/helpers/utilities.mjs +1 -70
  32. package/dist/lib/i18n/languages/de-de.json +1 -0
  33. package/dist/lib/i18n/languages/en-gb.json +1 -0
  34. package/dist/lib/i18n/languages/en-us.json +1 -0
  35. package/dist/lib/i18n/languages/es-es.json +412 -0
  36. package/dist/lib/i18n/languages/es-mx.json +1 -0
  37. package/dist/lib/i18n/languages/fr-fr.json +1 -0
  38. package/dist/lib/i18n/languages/hi-in.json +2 -1
  39. package/dist/lib/i18n/languages/ja-jp.json +1 -0
  40. package/dist/lib/i18n/languages/ko-kr.json +1 -0
  41. package/dist/lib/i18n/languages/pt-br.json +21 -20
  42. package/dist/lib/i18n/languages/ru-ru.json +2 -1
  43. package/dist/lib/i18n/languages/zh-cn.json +6 -5
  44. package/dist/lib/i18n/translations.mjs +1 -126
  45. package/dist/lib/modes/eager.mjs +1 -59
  46. package/dist/lib/modes/lazy.mjs +1 -81
  47. package/dist/lib/processors/flatten.mjs +1 -437
  48. package/dist/lib/processors/loader.mjs +1 -339
  49. package/dist/lib/processors/type-generator.mjs +1 -275
  50. package/dist/lib/processors/typescript.mjs +1 -172
  51. package/dist/lib/runtime/runtime-asynclocalstorage.mjs +1 -113
  52. package/dist/lib/runtime/runtime-livebindings.mjs +1 -78
  53. package/dist/lib/runtime/runtime.mjs +1 -102
  54. package/dist/slothlet.mjs +1 -817
  55. package/package.json +35 -31
  56. package/types/dist/lib/builders/api-assignment.d.mts +3 -92
  57. package/types/dist/lib/builders/api-assignment.d.mts.map +1 -1
  58. package/types/dist/lib/builders/api_builder.d.mts +102 -91
  59. package/types/dist/lib/builders/api_builder.d.mts.map +1 -1
  60. package/types/dist/lib/builders/builder.d.mts +1 -55
  61. package/types/dist/lib/builders/builder.d.mts.map +1 -1
  62. package/types/dist/lib/builders/modes-processor.d.mts +3 -27
  63. package/types/dist/lib/builders/modes-processor.d.mts.map +1 -1
  64. package/types/dist/lib/errors.d.mts +19 -109
  65. package/types/dist/lib/errors.d.mts.map +1 -1
  66. package/types/dist/lib/factories/component-base.d.mts +7 -177
  67. package/types/dist/lib/factories/component-base.d.mts.map +1 -1
  68. package/types/dist/lib/factories/context.d.mts +4 -22
  69. package/types/dist/lib/factories/context.d.mts.map +1 -1
  70. package/types/dist/lib/handlers/api-cache-manager.d.mts +20 -203
  71. package/types/dist/lib/handlers/api-cache-manager.d.mts.map +1 -1
  72. package/types/dist/lib/handlers/api-manager.d.mts +34 -408
  73. package/types/dist/lib/handlers/api-manager.d.mts.map +1 -1
  74. package/types/dist/lib/handlers/context-async.d.mts +23 -61
  75. package/types/dist/lib/handlers/context-async.d.mts.map +1 -1
  76. package/types/dist/lib/handlers/context-live.d.mts +22 -59
  77. package/types/dist/lib/handlers/context-live.d.mts.map +1 -1
  78. package/types/dist/lib/handlers/hook-manager.d.mts +46 -185
  79. package/types/dist/lib/handlers/hook-manager.d.mts.map +1 -1
  80. package/types/dist/lib/handlers/lifecycle-token.d.mts +3 -48
  81. package/types/dist/lib/handlers/lifecycle-token.d.mts.map +1 -1
  82. package/types/dist/lib/handlers/lifecycle.d.mts +5 -82
  83. package/types/dist/lib/handlers/lifecycle.d.mts.map +1 -1
  84. package/types/dist/lib/handlers/materialize-manager.d.mts +8 -70
  85. package/types/dist/lib/handlers/materialize-manager.d.mts.map +1 -1
  86. package/types/dist/lib/handlers/metadata.d.mts +17 -221
  87. package/types/dist/lib/handlers/metadata.d.mts.map +1 -1
  88. package/types/dist/lib/handlers/ownership.d.mts +44 -160
  89. package/types/dist/lib/handlers/ownership.d.mts.map +1 -1
  90. package/types/dist/lib/handlers/permission-manager.d.mts +40 -141
  91. package/types/dist/lib/handlers/permission-manager.d.mts.map +1 -1
  92. package/types/dist/lib/handlers/unified-wrapper.d.mts +26 -239
  93. package/types/dist/lib/handlers/unified-wrapper.d.mts.map +1 -1
  94. package/types/dist/lib/handlers/version-manager.d.mts +28 -225
  95. package/types/dist/lib/handlers/version-manager.d.mts.map +1 -1
  96. package/types/dist/lib/helpers/class-instance-wrapper.d.mts +2 -52
  97. package/types/dist/lib/helpers/class-instance-wrapper.d.mts.map +1 -1
  98. package/types/dist/lib/helpers/config.d.mts +125 -139
  99. package/types/dist/lib/helpers/config.d.mts.map +1 -1
  100. package/types/dist/lib/helpers/eventemitter-context.d.mts +3 -29
  101. package/types/dist/lib/helpers/eventemitter-context.d.mts.map +1 -1
  102. package/types/dist/lib/helpers/hint-detector.d.mts +2 -15
  103. package/types/dist/lib/helpers/hint-detector.d.mts.map +1 -1
  104. package/types/dist/lib/helpers/modes-utils.d.mts +3 -30
  105. package/types/dist/lib/helpers/modes-utils.d.mts.map +1 -1
  106. package/types/dist/lib/helpers/pattern-matcher.d.mts +3 -43
  107. package/types/dist/lib/helpers/pattern-matcher.d.mts.map +1 -1
  108. package/types/dist/lib/helpers/resolve-from-caller.d.mts +3 -27
  109. package/types/dist/lib/helpers/resolve-from-caller.d.mts.map +1 -1
  110. package/types/dist/lib/helpers/sanitize.d.mts +4 -92
  111. package/types/dist/lib/helpers/sanitize.d.mts.map +1 -1
  112. package/types/dist/lib/helpers/utilities.d.mts +4 -52
  113. package/types/dist/lib/helpers/utilities.d.mts.map +1 -1
  114. package/types/dist/lib/i18n/translations.d.mts +4 -37
  115. package/types/dist/lib/i18n/translations.d.mts.map +1 -1
  116. package/types/dist/lib/modes/eager.d.mts +8 -30
  117. package/types/dist/lib/modes/eager.d.mts.map +1 -1
  118. package/types/dist/lib/modes/lazy.d.mts +10 -43
  119. package/types/dist/lib/modes/lazy.d.mts.map +1 -1
  120. package/types/dist/lib/processors/flatten.d.mts +56 -107
  121. package/types/dist/lib/processors/flatten.d.mts.map +1 -1
  122. package/types/dist/lib/processors/loader.d.mts +6 -41
  123. package/types/dist/lib/processors/loader.d.mts.map +1 -1
  124. package/types/dist/lib/processors/type-generator.d.mts +2 -16
  125. package/types/dist/lib/processors/type-generator.d.mts.map +1 -1
  126. package/types/dist/lib/processors/typescript.d.mts +6 -53
  127. package/types/dist/lib/processors/typescript.d.mts.map +1 -1
  128. package/types/dist/lib/runtime/runtime-asynclocalstorage.d.mts +3 -71
  129. package/types/dist/lib/runtime/runtime-asynclocalstorage.d.mts.map +1 -1
  130. package/types/dist/lib/runtime/runtime-livebindings.d.mts +2 -37
  131. package/types/dist/lib/runtime/runtime-livebindings.d.mts.map +1 -1
  132. package/types/dist/lib/runtime/runtime.d.mts +3 -39
  133. package/types/dist/lib/runtime/runtime.d.mts.map +1 -1
  134. package/types/dist/slothlet.d.mts +3 -249
  135. package/types/dist/slothlet.d.mts.map +1 -1
  136. package/types/index.d.mts +36 -16
  137. package/types/index.d.mts.map +1 -0
  138. package/AGENT-USAGE.md +0 -736
  139. package/docs/API-RULES.md +0 -712
@@ -14,172 +14,4 @@
14
14
  limitations under the License.
15
15
  */
16
16
 
17
-
18
-
19
-
20
-
21
- import fs from "node:fs";
22
- import path from "node:path";
23
- import { fileURLToPath } from "node:url";
24
- import { ComponentBase } from "@cldmv/slothlet/factories/component-base";
25
-
26
-
27
- const __filename = fileURLToPath(import.meta.url);
28
- const __dirname = path.dirname(__filename);
29
- const SLOTHLET_LIB_ROOT = path.resolve(__dirname, "../..");
30
- const SLOTHLET_PKG_ROOT = path.normalize(path.resolve(__dirname, "../../.."));
31
-
32
- export class Resolver extends ComponentBase {
33
- static slothletProperty = "resolver";
34
-
35
-
36
- getStack(skipFn) {
37
- const orig = Error.prepareStackTrace;
38
- try {
39
- Error.prepareStackTrace = (_, s) => s;
40
- const e = new Error("Stack trace");
41
- if (skipFn) Error.captureStackTrace(e, skipFn);
42
- return e.stack;
43
- } finally {
44
- Error.prepareStackTrace = orig;
45
- }
46
- }
47
-
48
-
49
- #getStack() {
50
- const originalPrepare = Error.prepareStackTrace;
51
- Error.prepareStackTrace = (___, stack) => stack;
52
- const stack = new Error().stack;
53
- Error.prepareStackTrace = originalPrepare;
54
- return stack;
55
- }
56
-
57
-
58
- toFsPath(v) {
59
- if (!v) return null;
60
- const str = String(v);
61
- return str.startsWith("file://") ? fileURLToPath(str) : str;
62
- }
63
-
64
-
65
- #isSlothletInternal(filePath) {
66
-
67
- const normalized = path.normalize(filePath);
68
- const normalizedLibRoot = path.normalize(SLOTHLET_LIB_ROOT);
69
-
70
-
71
- if (normalized.startsWith(normalizedLibRoot)) {
72
- return true;
73
- }
74
-
75
-
76
-
77
-
78
-
79
-
80
- const basename = path.basename(normalized);
81
- if (basename === "index.mjs" || basename === "index.cjs") {
82
-
83
-
84
-
85
-
86
- if (path.dirname(normalized) === SLOTHLET_PKG_ROOT) return true;
87
- }
88
-
89
- return false;
90
- }
91
-
92
-
93
- #findCallerBase() {
94
- const stack = this.#getStack();
95
- const files = stack.map((s) => this.toFsPath(s.getFileName())).filter(Boolean);
96
-
97
-
98
- const slothletIndex = files.findIndex((f) => path.basename(f).toLowerCase() === "slothlet.mjs");
99
-
100
- if (slothletIndex === -1) {
101
-
102
- for (const file of files) {
103
- if (!this.#isSlothletInternal(file)) {
104
- return file;
105
- }
106
- }
107
-
108
-
109
-
110
-
111
-
112
- return null;
113
- }
114
-
115
-
116
- for (let i = slothletIndex + 1; i < files.length; i++) {
117
- const file = files[i];
118
-
119
-
120
- if (file.startsWith?.("node:")) continue;
121
-
122
-
123
- if (this.#isSlothletInternal(file)) continue;
124
-
125
-
126
- return file;
127
- }
128
-
129
-
130
-
131
-
132
-
133
-
134
-
135
- for (const file of files) {
136
- if (!this.#isSlothletInternal(file)) {
137
- return file;
138
- }
139
- }
140
-
141
-
142
-
143
-
144
-
145
- return null;
146
- }
147
-
148
-
149
- resolvePathFromCaller(rel) {
150
-
151
- if (rel.startsWith?.("file://")) return fileURLToPath(rel);
152
- if (path.isAbsolute(rel)) return rel;
153
-
154
-
155
- const callerFile = this.#findCallerBase();
156
-
157
-
158
-
159
-
160
-
161
- if (!callerFile) {
162
-
163
- return path.resolve(process.cwd(), rel);
164
- }
165
-
166
-
167
- const callerDir = path.dirname(callerFile);
168
- const resolved = path.resolve(callerDir, rel);
169
-
170
-
171
- if (fs.existsSync(resolved)) {
172
- return resolved;
173
- }
174
-
175
-
176
- const cwdResolved = path.resolve(process.cwd(), rel);
177
- if (fs.existsSync(cwdResolved)) {
178
- return cwdResolved;
179
- }
180
-
181
-
182
-
183
- return resolved;
184
- }
185
- }
17
+ import fs from"node:fs";import path from"node:path";import{fileURLToPath}from"node:url";import{ComponentBase}from"@cldmv/slothlet/factories/component-base";const __filename=fileURLToPath(import.meta.url);const __dirname=path.dirname(__filename);const SLOTHLET_LIB_ROOT=path.resolve(__dirname,"../..");const SLOTHLET_PKG_ROOT=path.normalize(path.resolve(__dirname,"../../.."));class Resolver extends ComponentBase{static slothletProperty="resolver";getStack(skipFn){const orig=Error.prepareStackTrace;try{Error.prepareStackTrace=(_,s)=>s;const e=new Error("Stack trace");if(skipFn)Error.captureStackTrace(e,skipFn);return e.stack}finally{Error.prepareStackTrace=orig}}#getStack(){const originalPrepare=Error.prepareStackTrace;Error.prepareStackTrace=(___,stack2)=>stack2;const stack=new Error().stack;Error.prepareStackTrace=originalPrepare;return stack}toFsPath(v){if(!v)return null;const str=String(v);return str.startsWith("file://")?fileURLToPath(str):str}#isSlothletInternal(filePath){const normalized=path.normalize(filePath);const normalizedLibRoot=path.normalize(SLOTHLET_LIB_ROOT);if(normalized.startsWith(normalizedLibRoot)){return true}const basename=path.basename(normalized);if(basename==="index.mjs"||basename==="index.cjs"){if(path.dirname(normalized)===SLOTHLET_PKG_ROOT)return true}return false}#findCallerBase(){const stack=this.#getStack();const files=stack.map(s=>this.toFsPath(s.getFileName())).filter(Boolean);const slothletIndex=files.findIndex(f=>path.basename(f).toLowerCase()==="slothlet.mjs");if(slothletIndex===-1){for(const file of files){if(!this.#isSlothletInternal(file)){return file}}return null}for(let i=slothletIndex+1;i<files.length;i++){const file=files[i];if(file.startsWith?.("node:"))continue;if(this.#isSlothletInternal(file))continue;return file}for(const file of files){if(!this.#isSlothletInternal(file)){return file}}return null}resolvePathFromCaller(rel){if(rel.startsWith?.("file://"))return fileURLToPath(rel);if(path.isAbsolute(rel))return rel;const callerFile=this.#findCallerBase();if(!callerFile){return path.resolve(process.cwd(),rel)}const callerDir=path.dirname(callerFile);const resolved=path.resolve(callerDir,rel);if(fs.existsSync(resolved)){return resolved}const cwdResolved=path.resolve(process.cwd(),rel);if(fs.existsSync(cwdResolved)){return cwdResolved}return resolved}}export{Resolver};
@@ -14,343 +14,4 @@
14
14
  limitations under the License.
15
15
  */
16
16
 
17
-
18
-
19
-
20
-
21
- import { ComponentBase } from "@cldmv/slothlet/factories/component-base";
22
-
23
-
24
-
25
-
26
-
27
-
28
- export class Sanitize extends ComponentBase {
29
- static slothletProperty = "sanitize";
30
-
31
-
32
-
33
-
34
-
35
-
36
- #compileGlobPattern(pattern, caseSensitive = true) {
37
-
38
- if (pattern.startsWith("**") && pattern.endsWith("**") && pattern.length > 4) {
39
- const innerString = pattern.slice(2, -2);
40
- const escapedString = innerString.replace(/[.+^${}()|[\]\\*?]/g, "\\$&");
41
- const flags = caseSensitive ? "" : "i";
42
- return new RegExp(`(?<=.)${escapedString}(?=.)`, flags);
43
- }
44
-
45
-
46
- const regexPattern = pattern
47
- .replace(/[.+^${}()|[\]\\]/g, "\\$&")
48
- .replace(/\*/g, ".*")
49
- .replace(/\?/g, ".");
50
-
51
- const flags = caseSensitive ? "" : "i";
52
- return new RegExp(`^${regexPattern}$`, flags);
53
- }
54
-
55
-
56
- #matchesAnyPattern(input, patterns, caseSensitive = false) {
57
- for (const pattern of patterns) {
58
- if (pattern.includes("*") || pattern.includes("?")) {
59
- const regex = this.#compileGlobPattern(pattern, caseSensitive);
60
- if (regex && regex.test(input)) return true;
61
- } else {
62
- const match = caseSensitive ? input === pattern : input.toLowerCase() === pattern.toLowerCase();
63
- if (match) return true;
64
- }
65
- }
66
- return false;
67
- }
68
-
69
-
70
- #extractPatternLiterals(pattern) {
71
- return pattern.split(/[*?]+/).filter(Boolean);
72
- }
73
-
74
-
75
-
76
-
77
-
78
-
79
- #applySegmentRules(segment, index, originalString, config) {
80
- const { preserveAllUpper, preserveAllLower, leaveRules, leaveInsensitiveRules, upperRules, lowerRules } = config;
81
-
82
-
83
- if (this.#matchesAnyPattern(segment, leaveRules, true)) {
84
- return segment;
85
- }
86
-
87
-
88
- if (this.#matchesAnyPattern(segment, leaveInsensitiveRules, false)) {
89
- return segment;
90
- }
91
-
92
-
93
-
94
- if (preserveAllUpper && segment === segment.toUpperCase() && segment !== segment.toLowerCase() && /[A-Z]/.test(segment)) {
95
- return segment;
96
- }
97
-
98
-
99
-
100
- if (preserveAllLower && segment === segment.toLowerCase() && segment !== segment.toUpperCase() && /[a-z]/.test(segment)) {
101
- return segment;
102
- }
103
-
104
-
105
-
106
- for (const pattern of [...upperRules, ...lowerRules]) {
107
- if (pattern.includes("*") || pattern.includes("?")) {
108
- const regex = this.#compileGlobPattern(pattern, false);
109
- if (regex && regex.test(originalString)) {
110
-
111
- const literals = this.#extractPatternLiterals(pattern);
112
- for (const literal of literals) {
113
-
114
- const cleanLiteral = literal.replace(/[^A-Za-z0-9_$]/g, "").replace(/^_+|_+$/g, "");
115
- if (cleanLiteral && segment.toLowerCase() === cleanLiteral.toLowerCase()) {
116
- return upperRules.includes(pattern) ? segment.toUpperCase() : segment.toLowerCase();
117
- }
118
- }
119
- }
120
- } else {
121
-
122
- if (segment.toLowerCase() === pattern.toLowerCase()) {
123
- return upperRules.includes(pattern) ? segment.toUpperCase() : segment.toLowerCase();
124
- }
125
- }
126
- }
127
-
128
-
129
- let transformed = this.#applyWithinSegmentPatterns(segment, upperRules, lowerRules);
130
- if (transformed !== segment) {
131
- return transformed;
132
- }
133
-
134
-
135
-
136
- return segment;
137
- }
138
-
139
-
140
- #applyWithinSegmentPatterns(segment, upperRules, lowerRules) {
141
- let result = segment;
142
-
143
- const applyBoundaryPattern = (pattern, toUpper) => {
144
-
145
- if (pattern.startsWith("**") && pattern.endsWith("**") && pattern.length > 4) {
146
- const innerString = pattern.slice(2, -2);
147
- const innerRegex = new RegExp(innerString.replace(/[.+^${}()|[\]\\*?]/g, "\\$&"), "gi");
148
- const matches = [...result.matchAll(innerRegex)];
149
-
150
- for (const match of matches) {
151
- const startPos = match.index;
152
- const endPos = startPos + match[0].length;
153
- const hasCharBefore = startPos > 0;
154
- const hasCharAfter = endPos < result.length;
155
-
156
- if (hasCharBefore && hasCharAfter) {
157
- const replacement = toUpper ? innerString.toUpperCase() : innerString.toLowerCase();
158
- result = result.substring(0, startPos) + replacement + result.substring(endPos);
159
- break;
160
- }
161
- }
162
- }
163
-
164
- else if (pattern.includes("*") && !pattern.startsWith("**")) {
165
-
166
- const literalParts = pattern.split("*").filter(Boolean);
167
- for (const literal of literalParts) {
168
- const literalRegex = new RegExp(literal.replace(/[.+^${}()|[\]\\]/g, "\\$&"), "gi");
169
- const replacement = toUpper ? literal.toUpperCase() : literal.toLowerCase();
170
- result = result.replace(literalRegex, replacement);
171
- }
172
- }
173
- };
174
-
175
- upperRules.forEach((pattern) => applyBoundaryPattern(pattern, true));
176
- lowerRules.forEach((pattern) => applyBoundaryPattern(pattern, false));
177
-
178
- return result;
179
- }
180
-
181
-
182
-
183
-
184
-
185
-
186
- sanitizePropertyName(input, options = {}) {
187
- const { lowerFirst = true, preserveAllUpper = false, preserveAllLower = false, rules = {} } = options;
188
-
189
-
190
- const leaveRules = (rules.leave || []).map((s) => String(s));
191
- const leaveInsensitiveRules = (rules.leaveInsensitive || []).map((s) => String(s));
192
- const upperRules = (rules.upper || []).map((s) => String(s));
193
- const lowerRules = (rules.lower || []).map((s) => String(s));
194
-
195
- const originalString = String(input).trim();
196
-
197
-
198
- const isAllUpper =
199
- originalString === originalString.toUpperCase() && originalString !== originalString.toLowerCase() && /[A-Z]/.test(originalString);
200
- const isAllLower =
201
- originalString === originalString.toLowerCase() && originalString !== originalString.toUpperCase() && /[a-z]/.test(originalString);
202
-
203
- if (preserveAllUpper && isAllUpper) {
204
- return originalString;
205
- }
206
-
207
-
208
- if (preserveAllLower && isAllLower && !/-/.test(originalString)) {
209
- return originalString;
210
- }
211
-
212
-
213
-
214
- let primarySegments = originalString.split(/[-]+|[^A-Za-z0-9_$]+/).filter(Boolean);
215
-
216
-
217
- if (primarySegments.length === 0) return "_";
218
-
219
-
220
- while (primarySegments.length && !/^[A-Za-z_$]/.test(primarySegments[0][0])) {
221
- primarySegments[0] = primarySegments[0].replace(/^[^A-Za-z_$]+/, "");
222
- if (!primarySegments[0]) primarySegments.shift();
223
- }
224
- if (primarySegments.length === 0) return "_";
225
-
226
-
227
-
228
-
229
-
230
-
231
- const lowerRuleApplied = [];
232
- const processedPrimarySegments = primarySegments.map((primarySeg, primaryIdx) => {
233
-
234
- const parts = primarySeg.split(/(_+)/);
235
-
236
-
237
- const processedParts = parts.map((part, partIdx) => {
238
-
239
- if (partIdx % 2 === 1) return part;
240
- if (!part) return part;
241
-
242
-
243
- const cleanSeg = part.replace(/[^A-Za-z0-9_$]/g, "");
244
-
245
-
246
- const config = { preserveAllUpper, preserveAllLower, leaveRules, leaveInsensitiveRules, upperRules, lowerRules };
247
- const result = this.#applySegmentRules(cleanSeg, 0, originalString, config);
248
-
249
-
250
-
251
- const matchesLower = lowerRules.some((pattern) => {
252
- if (pattern.includes("*") || pattern.includes("?")) {
253
- const regex = this.#compileGlobPattern(pattern, false);
254
- if (regex && regex.test(originalString)) {
255
-
256
- const literals = this.#extractPatternLiterals(pattern);
257
- for (const literal of literals) {
258
- const cleanLiteral = literal.replace(/[^A-Za-z0-9_$]/g, "").replace(/^_+|_+$/g, "");
259
- if (cleanLiteral && cleanSeg.toLowerCase() === cleanLiteral.toLowerCase()) {
260
- return true;
261
- }
262
- }
263
- }
264
- } else {
265
-
266
- if (cleanSeg.toLowerCase() === pattern.toLowerCase()) {
267
- return true;
268
- }
269
- }
270
- return false;
271
- });
272
-
273
- if (matchesLower && result === cleanSeg.toLowerCase()) {
274
- lowerRuleApplied[primaryIdx] = true;
275
- }
276
-
277
- return result;
278
- });
279
-
280
-
281
- return processedParts.join("");
282
- });
283
-
284
-
285
- const camelCasedSegments = processedPrimarySegments.map((seg, idx) => {
286
-
287
- const matchesLeave = this.#matchesAnyPattern(seg, leaveRules, true);
288
- const matchesLeaveInsensitive = this.#matchesAnyPattern(seg, leaveInsensitiveRules, false);
289
- const matchesUpper = this.#matchesAnyPattern(seg, upperRules, false);
290
-
291
-
292
- const hasUnderscores = seg.includes("_");
293
- const isAllUpper = !hasUnderscores && preserveAllUpper && seg === seg.toUpperCase() && seg !== seg.toLowerCase() && /[A-Z]/.test(seg);
294
- const isAllLower = !hasUnderscores && preserveAllLower && seg === seg.toLowerCase() && seg !== seg.toUpperCase() && /[a-z]/.test(seg);
295
-
296
-
297
- if (matchesLeave || matchesLeaveInsensitive || matchesUpper || isAllUpper || isAllLower) {
298
- return seg;
299
- }
300
-
301
-
302
-
303
- let transformed;
304
- if (idx === 0) {
305
-
306
- transformed = lowerFirst ? seg[0].toLowerCase() + seg.slice(1) : seg;
307
- } else {
308
-
309
-
310
- if (lowerRuleApplied[idx]) {
311
- transformed = seg;
312
- } else {
313
- transformed = seg[0].toUpperCase() + seg.slice(1);
314
- }
315
- }
316
-
317
- return transformed;
318
- });
319
-
320
-
321
- let result = camelCasedSegments.join("");
322
- result = result.replace(/[^A-Za-z0-9_$]/g, "");
323
-
324
- return result;
325
- }
326
-
327
-
328
- getModuleId(filePath, baseDir) {
329
-
330
- let relative = filePath.replace(baseDir, "").replace(/\\/g, "/");
331
- relative = relative.replace(/^\//, "");
332
- relative = relative.replace(/\.(mjs|cjs|js)$/, "");
333
-
334
- return relative;
335
- }
336
-
337
-
338
- shouldPreserveFunctionCase(name) {
339
- const preservePatterns = [
340
- /^[A-Z]{2,}$/,
341
- /[A-Z]{2,}/
342
- ];
343
-
344
- return preservePatterns.some((pattern) => pattern.test(name));
345
- }
346
- }
347
-
348
-
349
-
350
-
351
-
352
-
353
- export function sanitizePropertyName(input, options = {}) {
354
- const sanitizer = new Sanitize(null);
355
- return sanitizer.sanitizePropertyName(input, options);
356
- }
17
+ import{ComponentBase}from"@cldmv/slothlet/factories/component-base";class Sanitize extends ComponentBase{static slothletProperty="sanitize";#compileGlobPattern(pattern,caseSensitive=true){if(pattern.startsWith("**")&&pattern.endsWith("**")&&pattern.length>4){const innerString=pattern.slice(2,-2);const escapedString=innerString.replace(/[.+^${}()|[\]\\*?]/g,"\\$&");const flags2=caseSensitive?"":"i";return new RegExp(`(?<=.)${escapedString}(?=.)`,flags2)}const regexPattern=pattern.replace(/[.+^${}()|[\]\\]/g,"\\$&").replace(/\*/g,".*").replace(/\?/g,".");const flags=caseSensitive?"":"i";return new RegExp(`^${regexPattern}$`,flags)}#matchesAnyPattern(input,patterns,caseSensitive=false){for(const pattern of patterns){if(pattern.includes("*")||pattern.includes("?")){const regex=this.#compileGlobPattern(pattern,caseSensitive);if(regex&&regex.test(input))return true}else{const match=caseSensitive?input===pattern:input.toLowerCase()===pattern.toLowerCase();if(match)return true}}return false}#extractPatternLiterals(pattern){return pattern.split(/[*?]+/).filter(Boolean)}#applySegmentRules(segment,index,originalString,config){const{preserveAllUpper,preserveAllLower,leaveRules,leaveInsensitiveRules,upperRules,lowerRules}=config;if(this.#matchesAnyPattern(segment,leaveRules,true)){return segment}if(this.#matchesAnyPattern(segment,leaveInsensitiveRules,false)){return segment}if(preserveAllUpper&&segment===segment.toUpperCase()&&segment!==segment.toLowerCase()&&/[A-Z]/.test(segment)){return segment}if(preserveAllLower&&segment===segment.toLowerCase()&&segment!==segment.toUpperCase()&&/[a-z]/.test(segment)){return segment}for(const pattern of[...upperRules,...lowerRules]){if(pattern.includes("*")||pattern.includes("?")){const regex=this.#compileGlobPattern(pattern,false);if(regex&&regex.test(originalString)){const literals=this.#extractPatternLiterals(pattern);for(const literal of literals){const cleanLiteral=literal.replace(/[^A-Za-z0-9_$]/g,"").replace(/^_+|_+$/g,"");if(cleanLiteral&&segment.toLowerCase()===cleanLiteral.toLowerCase()){return upperRules.includes(pattern)?segment.toUpperCase():segment.toLowerCase()}}}}else{if(segment.toLowerCase()===pattern.toLowerCase()){return upperRules.includes(pattern)?segment.toUpperCase():segment.toLowerCase()}}}let transformed=this.#applyWithinSegmentPatterns(segment,upperRules,lowerRules);if(transformed!==segment){return transformed}return segment}#applyWithinSegmentPatterns(segment,upperRules,lowerRules){let result=segment;const applyBoundaryPattern=(pattern,toUpper)=>{if(pattern.startsWith("**")&&pattern.endsWith("**")&&pattern.length>4){const innerString=pattern.slice(2,-2);const innerRegex=new RegExp(innerString.replace(/[.+^${}()|[\]\\*?]/g,"\\$&"),"gi");const matches=[...result.matchAll(innerRegex)];for(const match of matches){const startPos=match.index;const endPos=startPos+match[0].length;const hasCharBefore=startPos>0;const hasCharAfter=endPos<result.length;if(hasCharBefore&&hasCharAfter){const replacement=toUpper?innerString.toUpperCase():innerString.toLowerCase();result=result.substring(0,startPos)+replacement+result.substring(endPos);break}}}else if(pattern.includes("*")&&!pattern.startsWith("**")){const literalParts=pattern.split("*").filter(Boolean);for(const literal of literalParts){const literalRegex=new RegExp(literal.replace(/[.+^${}()|[\]\\]/g,"\\$&"),"gi");const replacement=toUpper?literal.toUpperCase():literal.toLowerCase();result=result.replace(literalRegex,replacement)}}};upperRules.forEach(pattern=>applyBoundaryPattern(pattern,true));lowerRules.forEach(pattern=>applyBoundaryPattern(pattern,false));return result}sanitizePropertyName(input,options={}){const{lowerFirst=true,preserveAllUpper=false,preserveAllLower=false,rules={}}=options;const leaveRules=(rules.leave||[]).map(s=>String(s));const leaveInsensitiveRules=(rules.leaveInsensitive||[]).map(s=>String(s));const upperRules=(rules.upper||[]).map(s=>String(s));const lowerRules=(rules.lower||[]).map(s=>String(s));const originalString=String(input).trim();const isAllUpper=originalString===originalString.toUpperCase()&&originalString!==originalString.toLowerCase()&&/[A-Z]/.test(originalString);const isAllLower=originalString===originalString.toLowerCase()&&originalString!==originalString.toUpperCase()&&/[a-z]/.test(originalString);if(preserveAllUpper&&isAllUpper){return originalString}if(preserveAllLower&&isAllLower&&!/-/.test(originalString)){return originalString}let primarySegments=originalString.split(/[-]+|[^A-Za-z0-9_$]+/).filter(Boolean);if(primarySegments.length===0)return"_";while(primarySegments.length&&!/^[A-Za-z_$]/.test(primarySegments[0][0])){primarySegments[0]=primarySegments[0].replace(/^[^A-Za-z_$]+/,"");if(!primarySegments[0])primarySegments.shift()}if(primarySegments.length===0)return"_";const lowerRuleApplied=[];const processedPrimarySegments=primarySegments.map((primarySeg,primaryIdx)=>{const parts=primarySeg.split(/(_+)/);const processedParts=parts.map((part,partIdx)=>{if(partIdx%2===1)return part;if(!part)return part;const cleanSeg=part.replace(/[^A-Za-z0-9_$]/g,"");const config={preserveAllUpper,preserveAllLower,leaveRules,leaveInsensitiveRules,upperRules,lowerRules};const result2=this.#applySegmentRules(cleanSeg,0,originalString,config);const matchesLower=lowerRules.some(pattern=>{if(pattern.includes("*")||pattern.includes("?")){const regex=this.#compileGlobPattern(pattern,false);if(regex&&regex.test(originalString)){const literals=this.#extractPatternLiterals(pattern);for(const literal of literals){const cleanLiteral=literal.replace(/[^A-Za-z0-9_$]/g,"").replace(/^_+|_+$/g,"");if(cleanLiteral&&cleanSeg.toLowerCase()===cleanLiteral.toLowerCase()){return true}}}}else{if(cleanSeg.toLowerCase()===pattern.toLowerCase()){return true}}return false});if(matchesLower&&result2===cleanSeg.toLowerCase()){lowerRuleApplied[primaryIdx]=true}return result2});return processedParts.join("")});const camelCasedSegments=processedPrimarySegments.map((seg,idx)=>{const matchesLeave=this.#matchesAnyPattern(seg,leaveRules,true);const matchesLeaveInsensitive=this.#matchesAnyPattern(seg,leaveInsensitiveRules,false);const matchesUpper=this.#matchesAnyPattern(seg,upperRules,false);const hasUnderscores=seg.includes("_");const isAllUpper2=!hasUnderscores&&preserveAllUpper&&seg===seg.toUpperCase()&&seg!==seg.toLowerCase()&&/[A-Z]/.test(seg);const isAllLower2=!hasUnderscores&&preserveAllLower&&seg===seg.toLowerCase()&&seg!==seg.toUpperCase()&&/[a-z]/.test(seg);if(matchesLeave||matchesLeaveInsensitive||matchesUpper||isAllUpper2||isAllLower2){return seg}let transformed;if(idx===0){transformed=lowerFirst?seg[0].toLowerCase()+seg.slice(1):seg}else{if(lowerRuleApplied[idx]){transformed=seg}else{transformed=seg[0].toUpperCase()+seg.slice(1)}}return transformed});let result=camelCasedSegments.join("");result=result.replace(/[^A-Za-z0-9_$]/g,"");return result}getModuleId(filePath,baseDir){let relative=filePath.replace(baseDir,"").replace(/\\/g,"/");relative=relative.replace(/^\//,"");relative=relative.replace(/\.(mjs|cjs|js)$/,"");return relative}shouldPreserveFunctionCase(name){const preservePatterns=[/^[A-Z]{2,}$/,/[A-Z]{2,}/];return preservePatterns.some(pattern=>pattern.test(name))}}function sanitizePropertyName(input,options={}){const sanitizer=new Sanitize(null);return sanitizer.sanitizePropertyName(input,options)}export{Sanitize,sanitizePropertyName};
@@ -14,73 +14,4 @@
14
14
  limitations under the License.
15
15
  */
16
16
 
17
-
18
-
19
-
20
-
21
- import { ComponentBase } from "@cldmv/slothlet/factories/component-base";
22
-
23
-
24
- export class Utilities extends ComponentBase {
25
- static slothletProperty = "utilities";
26
-
27
-
28
- isPlainObject(obj) {
29
- if (typeof obj !== "object" || obj === null) return false;
30
- const proto = Object.getPrototypeOf(obj);
31
- return proto === null || proto === Object.prototype;
32
- }
33
-
34
-
35
- deepMerge(target, source) {
36
- if (!this.isPlainObject(target) || !this.isPlainObject(source)) {
37
- return source;
38
- }
39
-
40
- const result = { ...target };
41
-
42
- for (const key in source) {
43
- if (Object.prototype.hasOwnProperty.call(source, key)) {
44
- if (this.isPlainObject(source[key])) {
45
-
46
-
47
- result[key] = this.deepMerge(this.isPlainObject(target[key]) ? target[key] : {}, source[key]);
48
- } else {
49
- result[key] = source[key];
50
- }
51
- }
52
- }
53
-
54
- return result;
55
- }
56
-
57
-
58
- deepClone(obj) {
59
- try {
60
- return structuredClone(obj);
61
- } catch {
62
-
63
-
64
- const objType = obj?.__type || typeof obj;
65
- if (obj === null || (objType !== "object" && objType !== "function")) return obj;
66
- if (obj instanceof Date) return new Date(obj.getTime());
67
- if (Array.isArray(obj)) return obj.map((item) => this.deepClone(item));
68
-
69
- const cloned = {};
70
- for (const key in obj) {
71
- try {
72
- cloned[key] = this.deepClone(obj[key]);
73
- } catch {
74
-
75
- cloned[key] = obj[key];
76
- }
77
- }
78
- return cloned;
79
- }
80
- }
81
-
82
-
83
- generateId() {
84
- return `slothlet_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
85
- }
86
- }
17
+ import{ComponentBase}from"@cldmv/slothlet/factories/component-base";class Utilities extends ComponentBase{static slothletProperty="utilities";isPlainObject(obj){if(typeof obj!=="object"||obj===null)return false;const proto=Object.getPrototypeOf(obj);return proto===null||proto===Object.prototype}deepMerge(target,source){if(!this.isPlainObject(target)||!this.isPlainObject(source)){return source}const result={...target};for(const key in source){if(Object.prototype.hasOwnProperty.call(source,key)){if(this.isPlainObject(source[key])){result[key]=this.deepMerge(this.isPlainObject(target[key])?target[key]:{},source[key])}else{result[key]=source[key]}}}return result}deepClone(obj){try{return structuredClone(obj)}catch{const objType=obj?.__type||typeof obj;if(obj===null||objType!=="object"&&objType!=="function")return obj;if(obj instanceof Date)return new Date(obj.getTime());if(Array.isArray(obj))return obj.map(item=>this.deepClone(item));const cloned={};for(const key in obj){try{cloned[key]=this.deepClone(obj[key])}catch{cloned[key]=obj[key]}}return cloned}}generateId(){return`slothlet_${Date.now()}_${Math.random().toString(36).substr(2,9)}`}}export{Utilities};
@@ -399,6 +399,7 @@
399
399
  "PERM_RULE_CALLER_REQUIRED": "rule.caller muss eine nicht-leere Zeichenkette sein",
400
400
  "PERM_RULE_TARGET_REQUIRED": "rule.target muss eine nicht-leere Zeichenkette sein",
401
401
  "PERM_RULE_EFFECT_INVALID": "rule.effect muss 'allow' oder 'deny' sein",
402
+ "PERM_RULE_CONDITION_INVALID": "rule.condition muss ein einfaches Objekt, eine Funktion oder ein Array sein, bei dem jeder Eintrag ein einfaches Objekt oder eine Funktion ist",
402
403
  "BRACE_EXPANSION_MAX_DEPTH": "Klammerauflösung hat die maximale Tiefe von {maxDepth} überschritten",
403
404
  "HINT_BRACE_EXPANSION_MAX_DEPTH": "Verringern Sie die Verschachtelung in Ihren Klammermustern oder erhöhen Sie die maxDepth-Option.",
404
405
  "PERMISSION_MANAGER_NOT_AVAILABLE": "Berechtigungsmanager ist nicht in dieser Slothlet-Instanz verfügbar"
@@ -399,6 +399,7 @@
399
399
  "PERM_RULE_CALLER_REQUIRED": "rule.caller must be a non-empty string",
400
400
  "PERM_RULE_TARGET_REQUIRED": "rule.target must be a non-empty string",
401
401
  "PERM_RULE_EFFECT_INVALID": "rule.effect must be 'allow' or 'deny'",
402
+ "PERM_RULE_CONDITION_INVALID": "rule.condition must be a plain object, a function, or an array where each entry is a plain object or function",
402
403
  "BRACE_EXPANSION_MAX_DEPTH": "Brace expansion exceeded maximum depth of {maxDepth}",
403
404
  "HINT_BRACE_EXPANSION_MAX_DEPTH": "Reduce nesting in your brace patterns or increase the maxDepth option.",
404
405
  "PERMISSION_MANAGER_NOT_AVAILABLE": "Permission manager is not available in this Slothlet instance"
@@ -399,6 +399,7 @@
399
399
  "PERM_RULE_CALLER_REQUIRED": "rule.caller must be a non-empty string",
400
400
  "PERM_RULE_TARGET_REQUIRED": "rule.target must be a non-empty string",
401
401
  "PERM_RULE_EFFECT_INVALID": "rule.effect must be 'allow' or 'deny'",
402
+ "PERM_RULE_CONDITION_INVALID": "rule.condition must be a plain object, a function, or an array where each entry is a plain object or function",
402
403
  "BRACE_EXPANSION_MAX_DEPTH": "Brace expansion exceeded maximum depth of {maxDepth}",
403
404
  "HINT_BRACE_EXPANSION_MAX_DEPTH": "Reduce nesting in your brace patterns or increase the maxDepth option.",
404
405
  "PERMISSION_MANAGER_NOT_AVAILABLE": "Permission manager is not available in this Slothlet instance"