boxwood 2.13.0 → 2.15.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.
@@ -0,0 +1,115 @@
1
+ /**
2
+ * Resolve a path like "images[0].src" or "user.name" from a data object
3
+ * @param {Object} data - The data object to resolve the path from
4
+ * @param {string} path - The path to resolve (e.g., "images[0].src", "user.name")
5
+ * @returns {*} - The resolved value or undefined
6
+ */
7
+ function resolvePath(data, path) {
8
+ // Handle simple variable names (backwards compatibility)
9
+ if (!/[.\[]/.test(path)) {
10
+ return data[path]
11
+ }
12
+
13
+ // Split the path into parts, handling both dot notation and bracket notation
14
+ // e.g., "images[0].src" -> ["images", "0", "src"]
15
+ const parts = path
16
+ .replace(/\[(\d+)\]/g, ".$1") // Convert [0] to .0
17
+ .split(".")
18
+ .filter(Boolean)
19
+
20
+ let current = data
21
+ for (const part of parts) {
22
+ if (current === null || current === undefined) {
23
+ return undefined
24
+ }
25
+ current = current[part]
26
+ }
27
+
28
+ return current
29
+ }
30
+
31
+ /**
32
+ * Replace {variableName} placeholders in text with actual values from data
33
+ * Supports:
34
+ * - Simple variables: {name}
35
+ * - Array indexing: {images[0]}
36
+ * - Property access: {user.name}
37
+ * - Combined: {images[0].src}
38
+ * @param {string} text - Text containing variable placeholders
39
+ * @param {Object} data - Data object with variable values
40
+ * @returns {string|Array} - Text with variables replaced, or array if mixed content
41
+ */
42
+ function replaceVariables(text, data) {
43
+ if (!text || typeof text !== "string") {
44
+ return text
45
+ }
46
+
47
+ if (!data || typeof data !== "object") {
48
+ return text
49
+ }
50
+
51
+ // Check if text contains any variables
52
+ if (!text.includes("{") || !text.includes("}")) {
53
+ return text
54
+ }
55
+
56
+ const result = []
57
+ let i = 0
58
+ let lastIndex = 0
59
+
60
+ while (i < text.length) {
61
+ if (text[i] === "\\" && text[i + 1] === "{") {
62
+ // Escaped opening brace
63
+ result.push(text.substring(lastIndex, i))
64
+ result.push("{")
65
+ i += 2
66
+ lastIndex = i
67
+ continue
68
+ }
69
+
70
+ if (text[i] === "{") {
71
+ const closeIndex = text.indexOf("}", i + 1)
72
+
73
+ if (closeIndex !== -1) {
74
+ // Found a variable placeholder
75
+ const variablePath = text.substring(i + 1, closeIndex).trim()
76
+
77
+ if (variablePath) {
78
+ // Add text before the variable
79
+ if (i > lastIndex) {
80
+ result.push(text.substring(lastIndex, i))
81
+ }
82
+
83
+ // Resolve the variable value (supports paths like "images[0].src")
84
+ const value = resolvePath(data, variablePath)
85
+ if (value !== undefined && value !== null) {
86
+ result.push(String(value))
87
+ } else {
88
+ // Variable not found, keep the placeholder
89
+ result.push(text.substring(i, closeIndex + 1))
90
+ }
91
+
92
+ i = closeIndex + 1
93
+ lastIndex = i
94
+ continue
95
+ }
96
+ }
97
+ }
98
+
99
+ i++
100
+ }
101
+
102
+ // Add remaining text
103
+ if (lastIndex < text.length) {
104
+ result.push(text.substring(lastIndex))
105
+ }
106
+
107
+ // If no substitutions were made, return original text
108
+ if (result.length === 0) {
109
+ return text
110
+ }
111
+
112
+ return result.join("")
113
+ }
114
+
115
+ module.exports = { replaceVariables, resolvePath }
@@ -1,49 +0,0 @@
1
- // Example of using boxwood with TypeScript
2
- import { Div, H1, Button, Form, Input, component, classes } from 'boxwood';
3
-
4
- // Define typed component props
5
- interface UserCardProps {
6
- name: string;
7
- email: string;
8
- isActive: boolean;
9
- }
10
-
11
- // Create a typed component
12
- const UserCard = component<UserCardProps>(
13
- ({ name, email, isActive }, children) => {
14
- return Div({
15
- className: classes('user-card', { active: isActive })
16
- }, [
17
- H1({}, name),
18
- Div({ className: 'email' }, email),
19
- children
20
- ]);
21
- }
22
- );
23
-
24
- // Use the component with type checking
25
- const app = Div({ id: 'app' }, [
26
- UserCard({
27
- name: 'John Doe',
28
- email: 'john@example.com',
29
- isActive: true
30
- },
31
- Button({ onclick: () => alert('Hello!') }, 'Click me')
32
- ),
33
-
34
- Form({ method: 'post' }, [
35
- Input({
36
- type: 'email',
37
- name: 'email',
38
- required: true,
39
- placeholder: 'Enter email'
40
- }),
41
- Button({ type: 'submit' }, 'Submit')
42
- ])
43
- ]);
44
-
45
- // TypeScript will provide:
46
- // - Autocomplete for all element attributes
47
- // - Type checking for attribute values
48
- // - Error highlighting for invalid props
49
- // - IntelliSense documentation