angular-data-mapper 1.0.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 (64) hide show
  1. package/.claude/settings.local.json +10 -0
  2. package/LICENSE +190 -0
  3. package/PUBLISHING.md +75 -0
  4. package/README.md +214 -0
  5. package/angular.json +121 -0
  6. package/package.json +67 -0
  7. package/projects/demo-app/public/favicon.ico +0 -0
  8. package/projects/demo-app/src/app/app.config.ts +12 -0
  9. package/projects/demo-app/src/app/app.html +36 -0
  10. package/projects/demo-app/src/app/app.routes.ts +62 -0
  11. package/projects/demo-app/src/app/app.scss +65 -0
  12. package/projects/demo-app/src/app/app.ts +11 -0
  13. package/projects/demo-app/src/app/layout/app-layout.component.ts +294 -0
  14. package/projects/demo-app/src/app/pages/mapper-page/mapper-page.component.html +87 -0
  15. package/projects/demo-app/src/app/pages/mapper-page/mapper-page.component.scss +202 -0
  16. package/projects/demo-app/src/app/pages/mapper-page/mapper-page.component.ts +192 -0
  17. package/projects/demo-app/src/app/pages/mappings-page/add-mapping-dialog.component.ts +163 -0
  18. package/projects/demo-app/src/app/pages/mappings-page/mappings-page.component.ts +306 -0
  19. package/projects/demo-app/src/app/pages/schema-creator-page/schema-creator-page.component.ts +88 -0
  20. package/projects/demo-app/src/app/pages/schema-editor-page/schema-editor-page.component.html +108 -0
  21. package/projects/demo-app/src/app/pages/schema-editor-page/schema-editor-page.component.scss +317 -0
  22. package/projects/demo-app/src/app/pages/schema-editor-page/schema-editor-page.component.ts +129 -0
  23. package/projects/demo-app/src/app/services/app-state.service.ts +233 -0
  24. package/projects/demo-app/src/app/services/sample-data.service.ts +228 -0
  25. package/projects/demo-app/src/index.html +15 -0
  26. package/projects/demo-app/src/main.ts +6 -0
  27. package/projects/demo-app/src/styles.scss +54 -0
  28. package/projects/demo-app/tsconfig.app.json +13 -0
  29. package/projects/ngx-data-mapper/ng-package.json +7 -0
  30. package/projects/ngx-data-mapper/package.json +40 -0
  31. package/projects/ngx-data-mapper/src/lib/components/array-filter-modal/array-filter-modal.component.html +183 -0
  32. package/projects/ngx-data-mapper/src/lib/components/array-filter-modal/array-filter-modal.component.scss +352 -0
  33. package/projects/ngx-data-mapper/src/lib/components/array-filter-modal/array-filter-modal.component.ts +277 -0
  34. package/projects/ngx-data-mapper/src/lib/components/array-selector-modal/array-selector-modal.component.html +174 -0
  35. package/projects/ngx-data-mapper/src/lib/components/array-selector-modal/array-selector-modal.component.scss +357 -0
  36. package/projects/ngx-data-mapper/src/lib/components/array-selector-modal/array-selector-modal.component.ts +258 -0
  37. package/projects/ngx-data-mapper/src/lib/components/condition-builder/condition-builder.component.html +139 -0
  38. package/projects/ngx-data-mapper/src/lib/components/condition-builder/condition-builder.component.scss +213 -0
  39. package/projects/ngx-data-mapper/src/lib/components/condition-builder/condition-builder.component.ts +261 -0
  40. package/projects/ngx-data-mapper/src/lib/components/data-mapper/data-mapper.component.html +199 -0
  41. package/projects/ngx-data-mapper/src/lib/components/data-mapper/data-mapper.component.scss +321 -0
  42. package/projects/ngx-data-mapper/src/lib/components/data-mapper/data-mapper.component.ts +618 -0
  43. package/projects/ngx-data-mapper/src/lib/components/default-value-popover/default-value-popover.component.html +67 -0
  44. package/projects/ngx-data-mapper/src/lib/components/default-value-popover/default-value-popover.component.scss +97 -0
  45. package/projects/ngx-data-mapper/src/lib/components/default-value-popover/default-value-popover.component.ts +105 -0
  46. package/projects/ngx-data-mapper/src/lib/components/schema-editor/schema-editor.component.html +552 -0
  47. package/projects/ngx-data-mapper/src/lib/components/schema-editor/schema-editor.component.scss +824 -0
  48. package/projects/ngx-data-mapper/src/lib/components/schema-editor/schema-editor.component.ts +730 -0
  49. package/projects/ngx-data-mapper/src/lib/components/schema-tree/schema-tree.component.html +82 -0
  50. package/projects/ngx-data-mapper/src/lib/components/schema-tree/schema-tree.component.scss +352 -0
  51. package/projects/ngx-data-mapper/src/lib/components/schema-tree/schema-tree.component.ts +225 -0
  52. package/projects/ngx-data-mapper/src/lib/components/transformation-popover/transformation-popover.component.html +346 -0
  53. package/projects/ngx-data-mapper/src/lib/components/transformation-popover/transformation-popover.component.scss +511 -0
  54. package/projects/ngx-data-mapper/src/lib/components/transformation-popover/transformation-popover.component.ts +368 -0
  55. package/projects/ngx-data-mapper/src/lib/models/json-schema.model.ts +164 -0
  56. package/projects/ngx-data-mapper/src/lib/models/schema.model.ts +173 -0
  57. package/projects/ngx-data-mapper/src/lib/services/mapping.service.ts +615 -0
  58. package/projects/ngx-data-mapper/src/lib/services/schema-parser.service.ts +270 -0
  59. package/projects/ngx-data-mapper/src/lib/services/svg-connector.service.ts +135 -0
  60. package/projects/ngx-data-mapper/src/lib/services/transformation.service.ts +453 -0
  61. package/projects/ngx-data-mapper/src/public-api.ts +22 -0
  62. package/projects/ngx-data-mapper/tsconfig.lib.json +13 -0
  63. package/projects/ngx-data-mapper/tsconfig.lib.prod.json +9 -0
  64. package/tsconfig.json +28 -0
@@ -0,0 +1,346 @@
1
+ <div class="transformation-popover" [ngStyle]="getPopoverStyle()">
2
+ <div class="popover-arrow"></div>
3
+
4
+ <div class="popover-header">
5
+ <span class="popover-title">Transformation</span>
6
+ <button mat-icon-button class="close-btn" (click)="onClose()">
7
+ <mat-icon>close</mat-icon>
8
+ </button>
9
+ </div>
10
+
11
+ <div class="popover-content">
12
+ <!-- Source/Target Info -->
13
+ <div class="mapping-info">
14
+ <div class="info-row">
15
+ <span class="info-label">Source:</span>
16
+ <span class="info-value">{{ getSourceFieldNames() }}</span>
17
+ </div>
18
+ <div class="info-row">
19
+ <span class="info-label">Target:</span>
20
+ <span class="info-value">{{ mapping.targetField.name }}</span>
21
+ </div>
22
+ </div>
23
+
24
+ <!-- Single Step Mode (default, clean UI) -->
25
+ @if (!isMultiStep) {
26
+ <ng-container *ngTemplateOutlet="stepConfig; context: { step: steps[0], index: 0, showHeader: false }"></ng-container>
27
+
28
+ <!-- Preview Section -->
29
+ <div class="preview-section">
30
+ <span class="preview-label">Preview:</span>
31
+ <div class="preview-value">{{ stepPreviews[0] || '(empty)' }}</div>
32
+ </div>
33
+ }
34
+
35
+ <!-- Multi-Step Mode -->
36
+ @if (isMultiStep) {
37
+ <div class="steps-container" cdkDropList (cdkDropListDropped)="onStepDrop($event)">
38
+ @for (step of steps; track $index; let i = $index) {
39
+ <div class="step-card" [class.expanded]="isStepExpanded(i)" cdkDrag>
40
+ <!-- Collapsed View -->
41
+ @if (!isStepExpanded(i)) {
42
+ <div class="step-collapsed" (click)="toggleStep(i)">
43
+ <mat-icon class="drag-handle" cdkDragHandle (click)="$event.stopPropagation()">drag_indicator</mat-icon>
44
+ <div class="step-collapsed-header">
45
+ <div class="step-title-row">
46
+ <span class="step-number">Step {{ i + 1 }}: {{ getStepTypeLabel(step.type) }}</span>
47
+ @if (hasCondition(step)) {
48
+ <span class="condition-badge" matTooltip="{{ getConditionSummary(step) }}">
49
+ <mat-icon>filter_alt</mat-icon>
50
+ if
51
+ </span>
52
+ }
53
+ </div>
54
+ <div class="step-collapsed-actions">
55
+ <button
56
+ mat-icon-button
57
+ class="expand-btn"
58
+ (click)="toggleStep(i); $event.stopPropagation()"
59
+ matTooltip="Edit step"
60
+ >
61
+ <mat-icon>edit</mat-icon>
62
+ </button>
63
+ <button
64
+ mat-icon-button
65
+ class="remove-step-btn"
66
+ (click)="removeStep(i); $event.stopPropagation()"
67
+ matTooltip="Remove step"
68
+ >
69
+ <mat-icon>close</mat-icon>
70
+ </button>
71
+ </div>
72
+ </div>
73
+ <div class="step-collapsed-preview">
74
+ <span class="step-input">"{{ (stepInputs[i] || '') | slice:0:20 }}{{ (stepInputs[i] || '').length > 20 ? '...' : '' }}"</span>
75
+ <mat-icon class="arrow-icon">arrow_forward</mat-icon>
76
+ <span class="step-output">"{{ (stepPreviews[i] || '') | slice:0:20 }}{{ (stepPreviews[i] || '').length > 20 ? '...' : '' }}"</span>
77
+ </div>
78
+ </div>
79
+ }
80
+
81
+ <!-- Expanded View -->
82
+ @if (isStepExpanded(i)) {
83
+ <div class="step-expanded">
84
+ <mat-icon class="drag-handle" cdkDragHandle>drag_indicator</mat-icon>
85
+ <div class="step-header">
86
+ <span class="step-number">Step {{ i + 1 }}</span>
87
+ <div class="step-header-actions">
88
+ <button
89
+ mat-icon-button
90
+ class="collapse-btn"
91
+ (click)="toggleStep(i)"
92
+ matTooltip="Collapse"
93
+ >
94
+ <mat-icon>expand_less</mat-icon>
95
+ </button>
96
+ <button
97
+ mat-icon-button
98
+ class="remove-step-btn"
99
+ (click)="removeStep(i)"
100
+ matTooltip="Remove step"
101
+ >
102
+ <mat-icon>close</mat-icon>
103
+ </button>
104
+ </div>
105
+ </div>
106
+
107
+ <div class="step-content">
108
+ <ng-container *ngTemplateOutlet="stepConfig; context: { step: step, index: i, showHeader: false }"></ng-container>
109
+ </div>
110
+
111
+ <!-- Step Preview -->
112
+ <div class="step-preview">
113
+ <mat-icon class="preview-arrow">arrow_downward</mat-icon>
114
+ <span class="step-preview-value">{{ stepPreviews[i] || '(empty)' }}</span>
115
+ </div>
116
+ </div>
117
+ }
118
+ </div>
119
+ }
120
+ </div>
121
+
122
+ <!-- Final Preview -->
123
+ <div class="preview-section final-preview">
124
+ <span class="preview-label">Final Result:</span>
125
+ <div class="preview-value">{{ finalPreview || '(empty)' }}</div>
126
+ </div>
127
+ }
128
+ </div>
129
+
130
+ <!-- Add Step Button - Always visible -->
131
+ <div class="add-step-section">
132
+ <button mat-stroked-button class="add-step-btn" (click)="addStep()">
133
+ <mat-icon>add</mat-icon>
134
+ @if (isMultiStep) {
135
+ Add Step
136
+ } @else {
137
+ Add Transformation Step
138
+ }
139
+ </button>
140
+ </div>
141
+
142
+ <div class="popover-actions">
143
+ <button mat-button color="warn" (click)="onDelete()" matTooltip="Remove this mapping">
144
+ <mat-icon>delete</mat-icon>
145
+ Delete
146
+ </button>
147
+ <div class="action-spacer"></div>
148
+ <button mat-button (click)="onClose()">Cancel</button>
149
+ <button mat-flat-button color="primary" (click)="onSave()">Apply</button>
150
+ </div>
151
+ </div>
152
+
153
+ <!-- Backdrop -->
154
+ <div class="popover-backdrop" (click)="onClose()"></div>
155
+
156
+ <!-- Step Configuration Template -->
157
+ <ng-template #stepConfig let-step="step" let-index="index" let-showHeader="showHeader">
158
+ <!-- Transformation Type -->
159
+ <mat-form-field appearance="outline" class="full-width">
160
+ <mat-label>Transformation Type</mat-label>
161
+ <mat-select [(ngModel)]="step.type" (selectionChange)="onStepTypeChange(index)">
162
+ @for (t of availableTransformations; track t.type) {
163
+ <mat-option [value]="t.type">{{ t.label }}</mat-option>
164
+ }
165
+ </mat-select>
166
+ </mat-form-field>
167
+
168
+ <!-- Type-specific options -->
169
+ @switch (step.type) {
170
+ @case ('concat') {
171
+ <div class="config-section">
172
+ <mat-form-field appearance="outline" class="full-width">
173
+ <mat-label>Separator</mat-label>
174
+ <input
175
+ matInput
176
+ [(ngModel)]="step.separator"
177
+ (ngModelChange)="onConfigChange()"
178
+ placeholder=" "
179
+ />
180
+ <mat-hint>Join values with this (default: space)</mat-hint>
181
+ </mat-form-field>
182
+ <div class="or-divider">or use template for custom format</div>
183
+ <mat-form-field appearance="outline" class="full-width">
184
+ <mat-label>Template</mat-label>
185
+ <input
186
+ matInput
187
+ [(ngModel)]="step.template"
188
+ (ngModelChange)="onConfigChange()"
189
+ [placeholder]="'{0} - {1}'"
190
+ />
191
+ <mat-hint>Overrides separator if set</mat-hint>
192
+ </mat-form-field>
193
+ </div>
194
+ }
195
+
196
+ @case ('substring') {
197
+ <div class="config-section config-row">
198
+ <mat-form-field appearance="outline">
199
+ <mat-label>Start Index</mat-label>
200
+ <input
201
+ matInput
202
+ type="number"
203
+ [(ngModel)]="step.startIndex"
204
+ (ngModelChange)="onConfigChange()"
205
+ min="0"
206
+ />
207
+ </mat-form-field>
208
+ <mat-form-field appearance="outline">
209
+ <mat-label>End Index</mat-label>
210
+ <input
211
+ matInput
212
+ type="number"
213
+ [(ngModel)]="step.endIndex"
214
+ (ngModelChange)="onConfigChange()"
215
+ />
216
+ </mat-form-field>
217
+ </div>
218
+ }
219
+
220
+ @case ('replace') {
221
+ <div class="config-section">
222
+ <mat-form-field appearance="outline" class="full-width">
223
+ <mat-label>Search For</mat-label>
224
+ <input
225
+ matInput
226
+ [(ngModel)]="step.searchValue"
227
+ (ngModelChange)="onConfigChange()"
228
+ />
229
+ </mat-form-field>
230
+ <mat-form-field appearance="outline" class="full-width">
231
+ <mat-label>Replace With</mat-label>
232
+ <input
233
+ matInput
234
+ [(ngModel)]="step.replaceValue"
235
+ (ngModelChange)="onConfigChange()"
236
+ />
237
+ </mat-form-field>
238
+ </div>
239
+ }
240
+
241
+ @case ('dateFormat') {
242
+ <div class="config-section">
243
+ <mat-form-field appearance="outline" class="full-width">
244
+ <mat-label>Output Format</mat-label>
245
+ <input
246
+ matInput
247
+ [(ngModel)]="step.outputFormat"
248
+ (ngModelChange)="onConfigChange()"
249
+ placeholder="YYYY-MM-DD"
250
+ />
251
+ <mat-hint>YYYY, MM, DD, HH, mm, ss</mat-hint>
252
+ </mat-form-field>
253
+ </div>
254
+ }
255
+
256
+ @case ('numberFormat') {
257
+ <div class="config-section">
258
+ <mat-form-field appearance="outline" class="full-width">
259
+ <mat-label>Decimal Places</mat-label>
260
+ <input
261
+ matInput
262
+ type="number"
263
+ [(ngModel)]="step.decimalPlaces"
264
+ (ngModelChange)="onConfigChange()"
265
+ min="0"
266
+ />
267
+ </mat-form-field>
268
+ <div class="config-row">
269
+ <mat-form-field appearance="outline">
270
+ <mat-label>Prefix</mat-label>
271
+ <input
272
+ matInput
273
+ [(ngModel)]="step.prefix"
274
+ (ngModelChange)="onConfigChange()"
275
+ placeholder="$"
276
+ />
277
+ </mat-form-field>
278
+ <mat-form-field appearance="outline">
279
+ <mat-label>Suffix</mat-label>
280
+ <input
281
+ matInput
282
+ [(ngModel)]="step.suffix"
283
+ (ngModelChange)="onConfigChange()"
284
+ />
285
+ </mat-form-field>
286
+ </div>
287
+ </div>
288
+ }
289
+
290
+ @case ('mask') {
291
+ <div class="config-section">
292
+ <mat-form-field appearance="outline" class="full-width">
293
+ <mat-label>Pattern</mat-label>
294
+ <input
295
+ matInput
296
+ [(ngModel)]="step.pattern"
297
+ (ngModelChange)="onConfigChange()"
298
+ placeholder="(###) ###-####"
299
+ />
300
+ <mat-hint># = character from input</mat-hint>
301
+ </mat-form-field>
302
+ </div>
303
+ }
304
+
305
+ @case ('template') {
306
+ <div class="config-section">
307
+ <mat-form-field appearance="outline" class="full-width">
308
+ <mat-label>Template Expression</mat-label>
309
+ <textarea
310
+ matInput
311
+ [(ngModel)]="step.template"
312
+ (ngModelChange)="onConfigChange()"
313
+ rows="3"
314
+ [placeholder]="'Hello {0}, your ID is {1}'"
315
+ ></textarea>
316
+ @if (index === 0) {
317
+ <mat-hint>Use {{ '{' }}0{{ '}' }}, {{ '{' }}1{{ '}' }}, etc. for source fields</mat-hint>
318
+ } @else {
319
+ <mat-hint>Use {{ '{' }}0{{ '}' }} for the value from previous step</mat-hint>
320
+ }
321
+ </mat-form-field>
322
+ </div>
323
+ }
324
+ }
325
+
326
+ <!-- Condition Section -->
327
+ <div class="condition-section">
328
+ <mat-checkbox
329
+ [checked]="hasCondition(step)"
330
+ (change)="toggleCondition(step, $event.checked)"
331
+ class="condition-checkbox"
332
+ >
333
+ Apply conditionally
334
+ </mat-checkbox>
335
+
336
+ @if (hasCondition(step)) {
337
+ <div class="condition-content">
338
+ <condition-builder
339
+ [condition]="step.condition?.root || null"
340
+ [compact]="true"
341
+ (conditionChange)="onConditionChange(step, $event)"
342
+ ></condition-builder>
343
+ </div>
344
+ }
345
+ </div>
346
+ </ng-template>