lula2 0.0.5 → 0.0.6

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 (108) hide show
  1. package/README.md +291 -8
  2. package/dist/_app/env.js +1 -0
  3. package/dist/_app/immutable/assets/0.DtiRW3lO.css +1 -0
  4. package/dist/_app/immutable/assets/DynamicControlEditor.BkVTzFZ-.css +1 -0
  5. package/dist/_app/immutable/chunks/7x_q-1ab.js +1 -0
  6. package/dist/_app/immutable/chunks/B19gt6-g.js +2 -0
  7. package/dist/_app/immutable/chunks/BR-0Dorr.js +1 -0
  8. package/dist/_app/immutable/chunks/B_3ksxz5.js +2 -0
  9. package/dist/_app/immutable/chunks/Bg_R1qWi.js +3 -0
  10. package/dist/_app/immutable/chunks/D3aNP_lg.js +1 -0
  11. package/dist/_app/immutable/chunks/D4Q_ObIy.js +1 -0
  12. package/dist/_app/immutable/chunks/DsnmJJEf.js +1 -0
  13. package/dist/_app/immutable/chunks/XY2j_owG.js +66 -0
  14. package/dist/_app/immutable/chunks/rzN25oDf.js +1 -0
  15. package/dist/_app/immutable/entry/app.r0uOd9qg.js +2 -0
  16. package/dist/_app/immutable/entry/start.DvoqR0rc.js +1 -0
  17. package/dist/_app/immutable/nodes/0.Ct6FAss_.js +1 -0
  18. package/dist/_app/immutable/nodes/1.DLoKuy8Q.js +1 -0
  19. package/dist/_app/immutable/nodes/2.IRkwSmiB.js +1 -0
  20. package/dist/_app/immutable/nodes/3.BrTg-ZHv.js +1 -0
  21. package/dist/_app/immutable/nodes/4.Blq-4WQS.js +9 -0
  22. package/dist/_app/version.json +1 -0
  23. package/dist/cli/commands/crawl.js +128 -0
  24. package/dist/cli/commands/ui.js +2769 -0
  25. package/dist/cli/commands/version.js +30 -0
  26. package/dist/cli/server/index.js +2713 -0
  27. package/dist/cli/server/server.js +2702 -0
  28. package/dist/cli/server/serverState.js +1199 -0
  29. package/dist/cli/server/spreadsheetRoutes.js +788 -0
  30. package/dist/cli/server/types.js +0 -0
  31. package/dist/cli/server/websocketServer.js +2625 -0
  32. package/dist/cli/utils/debug.js +24 -0
  33. package/dist/favicon.svg +1 -0
  34. package/dist/index.html +38 -0
  35. package/dist/index.js +2924 -37
  36. package/dist/lula.png +0 -0
  37. package/dist/lula2 +2 -0
  38. package/package.json +120 -72
  39. package/src/app.css +192 -0
  40. package/src/app.d.ts +13 -0
  41. package/src/app.html +13 -0
  42. package/src/lib/actions/fadeWhenScrollable.ts +39 -0
  43. package/src/lib/actions/modal.ts +230 -0
  44. package/src/lib/actions/tooltip.ts +82 -0
  45. package/src/lib/components/control-sets/ControlSetInfo.svelte +20 -0
  46. package/src/lib/components/control-sets/ControlSetSelector.svelte +46 -0
  47. package/src/lib/components/control-sets/index.ts +5 -0
  48. package/src/lib/components/controls/ControlDetailsPanel.svelte +235 -0
  49. package/src/lib/components/controls/ControlsList.svelte +608 -0
  50. package/src/lib/components/controls/DynamicControlEditor.svelte +298 -0
  51. package/src/lib/components/controls/MappingCard.svelte +105 -0
  52. package/src/lib/components/controls/MappingForm.svelte +188 -0
  53. package/src/lib/components/controls/index.ts +9 -0
  54. package/src/lib/components/controls/renderers/EditableFieldRenderer.svelte +103 -0
  55. package/src/lib/components/controls/renderers/FieldRenderer.svelte +49 -0
  56. package/src/lib/components/controls/renderers/index.ts +5 -0
  57. package/src/lib/components/controls/tabs/CustomFieldsTab.svelte +130 -0
  58. package/src/lib/components/controls/tabs/ImplementationTab.svelte +127 -0
  59. package/src/lib/components/controls/tabs/MappingsTab.svelte +182 -0
  60. package/src/lib/components/controls/tabs/OverviewTab.svelte +151 -0
  61. package/src/lib/components/controls/tabs/TimelineTab.svelte +41 -0
  62. package/src/lib/components/controls/tabs/index.ts +8 -0
  63. package/src/lib/components/controls/utils/ProcessedTextRenderer.svelte +63 -0
  64. package/src/lib/components/controls/utils/textProcessor.ts +164 -0
  65. package/src/lib/components/forms/DynamicControlForm.svelte +340 -0
  66. package/src/lib/components/forms/DynamicField.svelte +494 -0
  67. package/src/lib/components/forms/FormField.svelte +107 -0
  68. package/src/lib/components/forms/index.ts +6 -0
  69. package/src/lib/components/setup/ExistingControlSets.svelte +284 -0
  70. package/src/lib/components/setup/SpreadsheetImport.svelte +968 -0
  71. package/src/lib/components/setup/index.ts +5 -0
  72. package/src/lib/components/ui/Dropdown.svelte +107 -0
  73. package/src/lib/components/ui/EmptyState.svelte +80 -0
  74. package/src/lib/components/ui/FeatureToggle.svelte +50 -0
  75. package/src/lib/components/ui/SearchBar.svelte +73 -0
  76. package/src/lib/components/ui/StatusBadge.svelte +79 -0
  77. package/src/lib/components/ui/TabNavigation.svelte +48 -0
  78. package/src/lib/components/ui/Tooltip.svelte +120 -0
  79. package/src/lib/components/ui/index.ts +10 -0
  80. package/src/lib/components/version-control/DiffViewer.svelte +292 -0
  81. package/src/lib/components/version-control/TimelineItem.svelte +107 -0
  82. package/src/lib/components/version-control/YamlDiffViewer.svelte +428 -0
  83. package/src/lib/components/version-control/index.ts +6 -0
  84. package/src/lib/form-types.ts +57 -0
  85. package/src/lib/formatUtils.ts +17 -0
  86. package/src/lib/index.ts +5 -0
  87. package/src/lib/types.ts +180 -0
  88. package/src/lib/websocket.ts +359 -0
  89. package/src/routes/+layout.svelte +236 -0
  90. package/src/routes/+page.svelte +38 -0
  91. package/src/routes/control/[id]/+page.svelte +112 -0
  92. package/src/routes/setup/+page.svelte +241 -0
  93. package/src/stores/compliance.ts +95 -0
  94. package/src/styles/highlightjs.css +20 -0
  95. package/src/styles/modal.css +58 -0
  96. package/src/styles/tables.css +111 -0
  97. package/src/styles/tooltip.css +65 -0
  98. package/dist/controls/index.d.ts +0 -18
  99. package/dist/controls/index.d.ts.map +0 -1
  100. package/dist/controls/index.js +0 -18
  101. package/dist/crawl.d.ts +0 -62
  102. package/dist/crawl.d.ts.map +0 -1
  103. package/dist/crawl.js +0 -172
  104. package/dist/index.d.ts +0 -8
  105. package/dist/index.d.ts.map +0 -1
  106. package/src/controls/index.ts +0 -19
  107. package/src/crawl.ts +0 -227
  108. package/src/index.ts +0 -46
@@ -0,0 +1,292 @@
1
+ <!-- SPDX-License-Identifier: Apache-2.0 -->
2
+ <!-- SPDX-FileCopyrightText: 2023-Present The Lula Authors -->
3
+
4
+ <script lang="ts">
5
+ interface Props {
6
+ diff: string;
7
+ fileName?: string;
8
+ language?: string;
9
+ compact?: boolean;
10
+ showToggle?: boolean;
11
+ }
12
+
13
+ let {
14
+ diff,
15
+ fileName = '',
16
+ language = 'yaml',
17
+ compact = false,
18
+ showToggle = true
19
+ }: Props = $props();
20
+
21
+ let isCompact = $state(compact);
22
+ let parsedDiff: DiffLine[] = $derived(
23
+ isCompact ? getCompactDiff(parseDiff(diff)) : parseDiff(diff)
24
+ );
25
+
26
+ interface DiffLine {
27
+ type: 'context' | 'addition' | 'deletion' | 'header' | 'hunk';
28
+ content: string;
29
+ oldLineNumber?: number;
30
+ newLineNumber?: number;
31
+ }
32
+
33
+ function parseDiff(diffText: string): DiffLine[] {
34
+ const lines = diffText.split('\n');
35
+ const parsedLines: DiffLine[] = [];
36
+ let oldLineNumber = 1;
37
+ let newLineNumber = 1;
38
+ let inDiffContent = false;
39
+
40
+ for (let i = 0; i < lines.length; i++) {
41
+ const line = lines[i];
42
+
43
+ // Skip file headers (--- and +++ lines) but include them
44
+ if (line.startsWith('---') || line.startsWith('+++')) {
45
+ parsedLines.push({ type: 'header', content: line });
46
+ continue;
47
+ }
48
+
49
+ // Handle hunk headers like @@ -4,7 +4,7 @@
50
+ if (line.startsWith('@@')) {
51
+ const match = line.match(/@@\s-(\d+)(?:,\d+)?\s\+(\d+)(?:,\d+)?\s@@/);
52
+ if (match) {
53
+ oldLineNumber = parseInt(match[1]);
54
+ newLineNumber = parseInt(match[2]);
55
+ inDiffContent = true;
56
+ }
57
+ parsedLines.push({ type: 'hunk', content: line });
58
+ continue;
59
+ }
60
+
61
+ // If we haven't seen a hunk header yet, check if this looks like diff content anyway
62
+ if (!inDiffContent) {
63
+ // Sometimes diffs don't have proper hunk headers, so check if line looks like diff content
64
+ if (line.startsWith('+') || line.startsWith('-') || line.startsWith(' ')) {
65
+ inDiffContent = true;
66
+ // Set reasonable default line numbers if we don't have hunk info
67
+ if (oldLineNumber === 1 && newLineNumber === 1) {
68
+ oldLineNumber = 1;
69
+ newLineNumber = 1;
70
+ }
71
+ } else {
72
+ continue;
73
+ }
74
+ }
75
+
76
+ // Handle actual diff lines
77
+ if (line.startsWith('+')) {
78
+ parsedLines.push({
79
+ type: 'addition',
80
+ content: line.slice(1),
81
+ newLineNumber: newLineNumber++
82
+ });
83
+ } else if (line.startsWith('-')) {
84
+ parsedLines.push({
85
+ type: 'deletion',
86
+ content: line.slice(1),
87
+ oldLineNumber: oldLineNumber++
88
+ });
89
+ } else if (line.startsWith(' ')) {
90
+ // Context line (unchanged)
91
+ parsedLines.push({
92
+ type: 'context',
93
+ content: line.slice(1),
94
+ oldLineNumber: oldLineNumber++,
95
+ newLineNumber: newLineNumber++
96
+ });
97
+ } else if (line === '' && inDiffContent) {
98
+ // Empty line in diff
99
+ parsedLines.push({
100
+ type: 'context',
101
+ content: '',
102
+ oldLineNumber: oldLineNumber++,
103
+ newLineNumber: newLineNumber++
104
+ });
105
+ } else if (inDiffContent) {
106
+ // Treat unknown lines as context if we're in diff content
107
+ parsedLines.push({
108
+ type: 'context',
109
+ content: line,
110
+ oldLineNumber: oldLineNumber++,
111
+ newLineNumber: newLineNumber++
112
+ });
113
+ }
114
+ }
115
+
116
+ return parsedLines;
117
+ }
118
+
119
+ function highlightYaml(content: string): string {
120
+ // Simple YAML syntax highlighting
121
+ return content
122
+ .replace(
123
+ /^(\s*)([a-zA-Z_][a-zA-Z0-9_-]*)\s*:/gm,
124
+ '$1<span class="text-blue-600 dark:text-blue-400 font-medium">$2</span>:'
125
+ )
126
+ .replace(/:\s*("[^"]*")/g, ': <span class="text-green-600 dark:text-green-400">$1</span>')
127
+ .replace(/:\s*(\d+)/g, ': <span class="text-purple-600 dark:text-purple-400">$1</span>')
128
+ .replace(
129
+ /:\s*(true|false|null)/g,
130
+ ': <span class="text-orange-600 dark:text-orange-400">$1</span>'
131
+ )
132
+ .replace(/^\s*-\s/gm, '<span class="text-gray-500 dark:text-gray-400">-</span> ')
133
+ .replace(/#.*$/gm, '<span class="text-gray-500 dark:text-gray-400 italic">$&</span>');
134
+ }
135
+
136
+ function getCompactDiff(lines: DiffLine[]): DiffLine[] {
137
+ const result: DiffLine[] = [];
138
+ const contextRadius = 2; // Show 2 lines of context around changes
139
+
140
+ // Find all changed lines (additions and deletions)
141
+ const changedLineIndices = new Set<number>();
142
+ lines.forEach((line, index) => {
143
+ if (line.type === 'addition' || line.type === 'deletion') {
144
+ // Add the changed line and context around it
145
+ for (
146
+ let i = Math.max(0, index - contextRadius);
147
+ i <= Math.min(lines.length - 1, index + contextRadius);
148
+ i++
149
+ ) {
150
+ changedLineIndices.add(i);
151
+ }
152
+ }
153
+ });
154
+
155
+ // Always include headers and hunks
156
+ lines.forEach((line, index) => {
157
+ if (line.type === 'header' || line.type === 'hunk' || changedLineIndices.has(index)) {
158
+ result.push(line);
159
+ }
160
+ });
161
+
162
+ return result;
163
+ }
164
+ </script>
165
+
166
+ <div class="diff-viewer border border-gray-200 dark:border-gray-600 rounded-lg overflow-hidden">
167
+ {#if fileName || showToggle}
168
+ <div
169
+ class="bg-gray-50 dark:bg-gray-800 px-4 py-2 border-b border-gray-200 dark:border-gray-600"
170
+ >
171
+ <div class="flex items-center justify-between">
172
+ {#if fileName}
173
+ <div class="flex items-center space-x-2">
174
+ <svg
175
+ class="w-4 h-4 text-gray-500"
176
+ fill="none"
177
+ stroke="currentColor"
178
+ viewBox="0 0 24 24"
179
+ >
180
+ <path
181
+ stroke-linecap="round"
182
+ stroke-linejoin="round"
183
+ stroke-width="2"
184
+ d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"
185
+ />
186
+ </svg>
187
+ <span class="text-sm font-medium text-gray-700 dark:text-gray-300 font-mono"
188
+ >{fileName}</span
189
+ >
190
+ </div>
191
+ {:else}
192
+ <div></div>
193
+ {/if}
194
+
195
+ {#if showToggle}
196
+ <button
197
+ onclick={() => (isCompact = !isCompact)}
198
+ class="inline-flex items-center px-2 py-1 text-xs font-medium text-gray-600 dark:text-gray-400 hover:text-gray-800 dark:hover:text-gray-200 bg-gray-100 dark:bg-gray-700 rounded hover:bg-gray-200 dark:hover:bg-gray-600 transition-colors"
199
+ >
200
+ <svg class="w-3 h-3 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
201
+ <path
202
+ stroke-linecap="round"
203
+ stroke-linejoin="round"
204
+ stroke-width="2"
205
+ d="M4 6h16M4 10h16M4 14h16M4 18h16"
206
+ />
207
+ </svg>
208
+ {isCompact ? 'Full' : 'Compact'}
209
+ </button>
210
+ {/if}
211
+ </div>
212
+ </div>
213
+ {/if}
214
+
215
+ <div class="diff-content max-h-96 overflow-y-auto">
216
+ {#each parsedDiff as line}
217
+ <div
218
+ class="diff-line flex {line.type === 'addition'
219
+ ? 'bg-green-50 dark:bg-green-900/20'
220
+ : line.type === 'deletion'
221
+ ? 'bg-red-50 dark:bg-red-900/20'
222
+ : line.type === 'hunk'
223
+ ? 'bg-gray-100 dark:bg-gray-800'
224
+ : line.type === 'header'
225
+ ? 'bg-gray-100 dark:bg-gray-800'
226
+ : 'bg-white dark:bg-gray-900'}"
227
+ >
228
+ <!-- Line numbers -->
229
+ <div
230
+ class="line-numbers flex text-xs text-gray-400 dark:text-gray-500 font-mono select-none border-r border-gray-200 dark:border-gray-600 bg-gray-50 dark:bg-gray-750"
231
+ >
232
+ <div class="w-8 px-2 py-1 text-right">
233
+ {line.type !== 'addition' && line.oldLineNumber ? line.oldLineNumber : ''}
234
+ </div>
235
+ <div class="w-8 px-2 py-1 text-right">
236
+ {line.type !== 'deletion' && line.newLineNumber ? line.newLineNumber : ''}
237
+ </div>
238
+ </div>
239
+
240
+ <!-- Change indicator -->
241
+ <div
242
+ class="change-indicator w-6 flex items-center justify-center text-sm font-mono {line.type ===
243
+ 'addition'
244
+ ? 'text-green-600 dark:text-green-400 bg-green-50 dark:bg-green-900/20'
245
+ : line.type === 'deletion'
246
+ ? 'text-red-600 dark:text-red-400 bg-red-50 dark:bg-red-900/20'
247
+ : 'text-gray-400 dark:text-gray-500'}"
248
+ >
249
+ {line.type === 'addition' ? '+' : line.type === 'deletion' ? '-' : ''}
250
+ </div>
251
+
252
+ <!-- Content -->
253
+ <div
254
+ class="content flex-1 px-2 py-1 font-mono text-sm leading-relaxed whitespace-pre-wrap {line.type ===
255
+ 'hunk'
256
+ ? 'text-gray-600 dark:text-gray-400 font-medium'
257
+ : line.type === 'header'
258
+ ? 'text-gray-500 dark:text-gray-400'
259
+ : 'text-gray-900 dark:text-gray-100'}"
260
+ >
261
+ {#if language === 'yaml' && (line.type === 'context' || line.type === 'addition' || line.type === 'deletion')}
262
+ {@html highlightYaml(line.content)}
263
+ {:else}
264
+ {line.content}
265
+ {/if}
266
+ </div>
267
+ </div>
268
+ {/each}
269
+ </div>
270
+ </div>
271
+
272
+ <style>
273
+ .diff-viewer {
274
+ font-family: 'Monaco', 'Menlo', 'Consolas', monospace;
275
+ }
276
+
277
+ .diff-line:hover {
278
+ background-color: rgba(59, 130, 246, 0.05);
279
+ }
280
+
281
+ .diff-line.bg-green-50:hover {
282
+ background-color: rgba(34, 197, 94, 0.1);
283
+ }
284
+
285
+ .diff-line.bg-red-50:hover {
286
+ background-color: rgba(239, 68, 68, 0.1);
287
+ }
288
+
289
+ :global(.dark) .diff-line:hover {
290
+ background-color: rgba(59, 130, 246, 0.1);
291
+ }
292
+ </style>
@@ -0,0 +1,107 @@
1
+ <!-- SPDX-License-Identifier: Apache-2.0 -->
2
+ <!-- SPDX-FileCopyrightText: 2023-Present The Lula Authors -->
3
+
4
+ <script lang="ts">
5
+ import type { GitCommit } from '$lib/types';
6
+ import { DiffViewer, YamlDiffViewer } from '.';
7
+
8
+ interface Props {
9
+ commit: GitCommit & { type?: string; fileType?: string; source?: 'control' | 'mapping' };
10
+ showConnector?: boolean;
11
+ }
12
+
13
+ let { commit, showConnector = false }: Props = $props();
14
+
15
+ function formatDate(dateString: string): string {
16
+ return new Date(dateString).toLocaleDateString('en-US', {
17
+ year: 'numeric',
18
+ month: 'short',
19
+ day: 'numeric',
20
+ hour: '2-digit',
21
+ minute: '2-digit'
22
+ });
23
+ }
24
+ </script>
25
+
26
+ <div class="relative">
27
+ <!-- Connector line -->
28
+ {#if showConnector}
29
+ <div class="absolute left-4 top-12 bottom-0 w-0.5 bg-gray-200 dark:bg-gray-800"></div>
30
+ {/if}
31
+
32
+ <!-- Timeline item -->
33
+ <div class="relative">
34
+ <!-- Icon/dot -->
35
+ <div
36
+ class="absolute left-0 mt-1.5 w-8 h-8 rounded-full border-2 border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-900 flex items-center justify-center"
37
+ >
38
+ {#if commit.isPending}
39
+ <div class="w-3 h-3 rounded-full bg-amber-400 animate-pulse"></div>
40
+ {:else if commit.source === 'mapping' || commit.type === 'mapping'}
41
+ <div class="w-3 h-3 rounded-full bg-green-500"></div>
42
+ {:else}
43
+ <div class="w-3 h-3 rounded-full bg-blue-500"></div>
44
+ {/if}
45
+ </div>
46
+
47
+ <!-- Content card -->
48
+ <div
49
+ class="ml-12 bg-gradient-to-br from-gray-50 to-gray-100 dark:from-gray-800 dark:to-gray-900 border border-gray-200 dark:border-gray-700 rounded-xl shadow-sm hover:shadow-md transition-all duration-200"
50
+ >
51
+ <!-- Header -->
52
+ <div
53
+ class="px-6 py-4 border-b border-gray-100 dark:border-gray-700 bg-gray-50 dark:bg-gray-800/50 rounded-t-xl"
54
+ >
55
+ <div class="flex items-center justify-between">
56
+ <div class="flex items-center space-x-3">
57
+ <h4 class="text-sm font-semibold text-gray-900 dark:text-gray-100">
58
+ {commit.fileType ||
59
+ (commit.source === 'mapping' || commit.type === 'mapping'
60
+ ? 'Mappings'
61
+ : 'Control File')}
62
+ </h4>
63
+ {#if commit.isPending}
64
+ <span
65
+ class="inline-flex items-center px-2 py-1 rounded-full text-xs font-medium bg-amber-100 dark:bg-amber-900/30 text-amber-700 dark:text-amber-300"
66
+ >
67
+ Pending
68
+ </span>
69
+ {:else}
70
+ <span
71
+ class="inline-flex items-center px-2 py-1 rounded-full text-xs font-medium bg-gray-100 dark:bg-gray-800 text-gray-600 dark:text-gray-400"
72
+ >
73
+ {commit.shortHash}
74
+ </span>
75
+ {/if}
76
+ </div>
77
+ <p class="text-xs text-gray-500 dark:text-gray-400">
78
+ {formatDate(commit.date)}
79
+ </p>
80
+ </div>
81
+
82
+ <p class="text-xs text-gray-600 dark:text-gray-400 mt-1">
83
+ {commit.author}
84
+ </p>
85
+ </div>
86
+
87
+ <!-- Content -->
88
+ <div class="px-6 py-4">
89
+ <pre
90
+ class="text-sm text-gray-700 dark:text-gray-300 leading-relaxed whitespace-pre-wrap font-sans">{commit.message}</pre>
91
+ </div>
92
+
93
+ <!-- Always show diff content -->
94
+ <div class="p-2">
95
+ {#if commit.diff && !commit.yamlDiff?.hasChanges}
96
+ <div class="border-t border-gray-200 dark:border-gray-700">
97
+ <DiffViewer diff={commit.diff} />
98
+ </div>
99
+ {:else if commit.yamlDiff?.hasChanges}
100
+ <div class="border-t border-gray-200 dark:border-gray-700">
101
+ <YamlDiffViewer yamlDiff={commit.yamlDiff} />
102
+ </div>
103
+ {/if}
104
+ </div>
105
+ </div>
106
+ </div>
107
+ </div>