ms-data-grid 0.0.45 → 0.0.47

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 (61) hide show
  1. package/ng-package.json +18 -0
  2. package/package.json +38 -45
  3. package/src/lib/css/bootstrap.css +12043 -0
  4. package/src/lib/data-grid/animations.ts +228 -0
  5. package/src/lib/data-grid/data-grid.component.html +5353 -0
  6. package/src/lib/data-grid/data-grid.component.scss +2005 -0
  7. package/src/lib/data-grid/data-grid.component.spec.ts +28 -0
  8. package/src/lib/data-grid/data-grid.component.ts +5368 -0
  9. package/src/lib/data-grid/statuses.ts +49 -0
  10. package/src/lib/data-grid.module.ts +19 -0
  11. package/src/lib/data-grid.service.spec.ts +16 -0
  12. package/src/lib/data-grid.service.ts +9 -0
  13. package/src/lib/directives/draggable-header.directive.spec.ts +11 -0
  14. package/src/lib/directives/draggable-header.directive.ts +172 -0
  15. package/src/lib/pipes/filter.pipe.spec.ts +11 -0
  16. package/src/lib/pipes/filter.pipe.ts +22 -0
  17. package/src/lib/services/cell-selection.service.spec.ts +16 -0
  18. package/src/lib/services/cell-selection.service.ts +205 -0
  19. package/src/lib/services/common.service.spec.ts +16 -0
  20. package/src/lib/services/common.service.ts +278 -0
  21. package/src/lib/services/copy-service.service.spec.ts +16 -0
  22. package/src/lib/services/copy-service.service.ts +252 -0
  23. package/src/lib/services/drag-drp.service.spec.ts +16 -0
  24. package/src/lib/services/drag-drp.service.ts +58 -0
  25. package/src/lib/services/export.service.spec.ts +16 -0
  26. package/src/lib/services/export.service.ts +189 -0
  27. package/src/lib/services/split-columns.service.spec.ts +16 -0
  28. package/src/lib/services/split-columns.service.ts +148 -0
  29. package/src/lib/services/swap-columns.service.spec.ts +16 -0
  30. package/src/lib/services/swap-columns.service.ts +162 -0
  31. package/src/public-api.ts +6 -0
  32. package/src/typings.d.ts +4 -0
  33. package/tsconfig.lib.json +19 -0
  34. package/tsconfig.lib.prod.json +10 -0
  35. package/tsconfig.spec.json +14 -0
  36. package/esm2022/lib/data-grid/data-grid.component.mjs +0 -3786
  37. package/esm2022/lib/data-grid/statuses.mjs +0 -44
  38. package/esm2022/lib/data-grid.module.mjs +0 -25
  39. package/esm2022/lib/data-grid.service.mjs +0 -14
  40. package/esm2022/lib/directives/draggable-header.directive.mjs +0 -145
  41. package/esm2022/lib/pipes/filter.pipe.mjs +0 -28
  42. package/esm2022/lib/services/common.service.mjs +0 -210
  43. package/esm2022/lib/services/copy-service.service.mjs +0 -222
  44. package/esm2022/lib/services/split-columns.service.mjs +0 -143
  45. package/esm2022/lib/services/swap-columns.service.mjs +0 -118
  46. package/esm2022/ms-data-grid.mjs +0 -5
  47. package/esm2022/public-api.mjs +0 -8
  48. package/fesm2022/ms-data-grid.mjs +0 -4720
  49. package/fesm2022/ms-data-grid.mjs.map +0 -1
  50. package/index.d.ts +0 -5
  51. package/lib/data-grid/data-grid.component.d.ts +0 -477
  52. package/lib/data-grid/statuses.d.ts +0 -3
  53. package/lib/data-grid.module.d.ts +0 -14
  54. package/lib/data-grid.service.d.ts +0 -6
  55. package/lib/directives/draggable-header.directive.d.ts +0 -31
  56. package/lib/pipes/filter.pipe.d.ts +0 -7
  57. package/lib/services/common.service.d.ts +0 -17
  58. package/lib/services/copy-service.service.d.ts +0 -14
  59. package/lib/services/split-columns.service.d.ts +0 -9
  60. package/lib/services/swap-columns.service.d.ts +0 -19
  61. package/public-api.d.ts +0 -4
@@ -0,0 +1,189 @@
1
+ import { Injectable } from '@angular/core';
2
+ import * as XLSX from 'xlsx-js-style';
3
+ import { saveAs } from 'file-saver';
4
+
5
+ @Injectable({
6
+ providedIn: 'root'
7
+ })
8
+ export class ExportService {
9
+
10
+ constructor() {}
11
+
12
+ /**
13
+ * Exports data to CSV or Excel.
14
+ * @param columns List of column definitions (each having name/key/is_visible)
15
+ * @param data The array of data objects
16
+ * @param fileName Name of the exported file (without extension)
17
+ * @param format 'csv' | 'xlsx'
18
+ */
19
+ exportData(
20
+ columns: any[],
21
+ data: any[],
22
+ fileName: string,
23
+ format: 'csv' | 'xlsx' = 'xlsx',
24
+ rowSelectedIndexes: Set<number> | null = new Set(),
25
+ styleConfig: {
26
+ headerBgColor?: string;
27
+ headerTextColor?: string;
28
+ bodyTextColor?: string;
29
+ fontFamily?: string;
30
+ fontWeight?: 'normal' | 'bold';
31
+ zoomScale?: number;
32
+ headerRowHeight?: number;
33
+ selectedRowBgColor?: string;
34
+ } = {}
35
+ ) {
36
+ const {
37
+ headerBgColor = '#228B22',
38
+ headerTextColor = '#FFFFFF',
39
+ bodyTextColor = '#000000',
40
+ fontFamily = 'Calibri',
41
+ fontWeight = 'normal',
42
+ zoomScale = 120,
43
+ headerRowHeight = 20,
44
+ selectedRowBgColor = '#8AC5FF',
45
+ } = styleConfig;
46
+
47
+ const visibleColumns = columns.filter(
48
+ col => col.is_visible && col.type !== 'image' && col.type !== 'logo'
49
+ );
50
+
51
+ const headers = visibleColumns.map(col => col.header || col.headerName || col.name);
52
+
53
+ const flattenValue = (value: any): any => {
54
+ if (value == null) return '';
55
+ if (Array.isArray(value))
56
+ return value.map(v => (typeof v === 'object' ? flattenValue(v) : v)).join(', ');
57
+ if (typeof value === 'object')
58
+ return Object.entries(value)
59
+ .map(([k, v]) => `${k}: ${flattenValue(v)}`)
60
+ .join(', ');
61
+ return value;
62
+ };
63
+
64
+ const exportData = data.map(row =>
65
+ visibleColumns.reduce((acc: any, col) => {
66
+ const header = col.headerName || col.name || col.header;
67
+ let value = this.getNestedValue(row, col.field);
68
+
69
+ switch (col.type) {
70
+ case 'boolean':
71
+ value = value ? 'Yes' : 'No';
72
+ break;
73
+ case 'date':
74
+ if (value) {
75
+ const date = new Date(value);
76
+ if (!isNaN(date.getTime())) {
77
+ value = date.toLocaleDateString('en-US', {
78
+ day: '2-digit',
79
+ month: 'long',
80
+ year: 'numeric',
81
+ });
82
+ }
83
+ }
84
+ break;
85
+ default:
86
+ value = flattenValue(value);
87
+ }
88
+
89
+ acc[header] = value;
90
+ return acc;
91
+ }, {})
92
+ );
93
+
94
+ const worksheet: XLSX.WorkSheet = XLSX.utils.json_to_sheet(exportData, { header: headers });
95
+
96
+ // ✅ Define a reusable border style
97
+ const borderStyle = {
98
+ top: { style: 'thin', color: { rgb: 'CCCCCC' } },
99
+ bottom: { style: 'thin', color: { rgb: 'CCCCCC' } },
100
+ left: { style: 'thin', color: { rgb: 'CCCCCC' } },
101
+ right: { style: 'thin', color: { rgb: 'CCCCCC' } },
102
+ };
103
+
104
+ // ✅ Apply header styles
105
+ headers.forEach((header, index) => {
106
+ const cellAddress = XLSX.utils.encode_cell({ r: 0, c: index });
107
+ if (!worksheet[cellAddress]) return;
108
+
109
+ worksheet[cellAddress].s = {
110
+ fill: { fgColor: { rgb: headerBgColor.replace('#', '') } },
111
+ font: {
112
+ name: fontFamily,
113
+ sz: 14,
114
+ color: { rgb: headerTextColor.replace('#', '') },
115
+ bold: fontWeight === 'bold',
116
+ },
117
+ alignment: { horizontal: 'center', vertical: 'center' },
118
+ border: borderStyle, // ✅ Added border here
119
+ };
120
+ });
121
+
122
+ // ✅ Apply body styles + highlight selected rows
123
+ for (let r = 1; r <= exportData.length; r++) {
124
+ const isSelected = rowSelectedIndexes?.has(r - 1);
125
+ const rowBgColor = isSelected ? selectedRowBgColor : '#FFFFFF';
126
+
127
+ for (let c = 0; c < headers.length; c++) {
128
+ const col = visibleColumns[c];
129
+ const cellAddress = XLSX.utils.encode_cell({ r, c });
130
+ const cell = worksheet[cellAddress];
131
+ if (!cell) continue;
132
+
133
+ let horizontalAlign = 'left';
134
+ if (['number', 'boolean', 'date'].includes(col.type)) horizontalAlign = 'center';
135
+
136
+ cell.s = {
137
+ fill: { fgColor: { rgb: rowBgColor.replace('#', '') } },
138
+ font: {
139
+ name: fontFamily,
140
+ sz: 14,
141
+ color: { rgb: bodyTextColor.replace('#', '') },
142
+ bold: false,
143
+ },
144
+ alignment: { horizontal: horizontalAlign, vertical: 'center', wrapText: true },
145
+ border: borderStyle, // ✅ Added border here too
146
+ };
147
+ }
148
+ }
149
+
150
+ // ✅ Adjust column widths
151
+ const colWidths = headers.map(header => {
152
+ let maxLength = header.length;
153
+ exportData.forEach(row => {
154
+ const val = row[header];
155
+ if (val != null) {
156
+ const len = val.toString().length;
157
+ if (len > maxLength) maxLength = len;
158
+ }
159
+ });
160
+ return { wch: Math.min(maxLength + 2, 64) };
161
+ });
162
+ worksheet['!cols'] = colWidths;
163
+
164
+ worksheet['!rows'] = [{ hpt: headerRowHeight }];
165
+ worksheet['!zoom'] = zoomScale;
166
+
167
+ const workbook: XLSX.WorkBook = { Sheets: { Data: worksheet }, SheetNames: ['Data'] };
168
+
169
+ if (format === 'csv') {
170
+ const csv = XLSX.utils.sheet_to_csv(worksheet);
171
+ const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' });
172
+ saveAs(blob, `${fileName}.csv`);
173
+ } else {
174
+ const excelBuffer: any = XLSX.write(workbook, { bookType: 'xlsx', type: 'array' });
175
+ const blob = new Blob([excelBuffer], {
176
+ type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8',
177
+ });
178
+ saveAs(blob, `${fileName}.xlsx`);
179
+ }
180
+ }
181
+
182
+
183
+
184
+
185
+ private getNestedValue(obj: any, path: string): any {
186
+ if (!path || typeof obj !== 'object') return obj;
187
+ return path.split('.').reduce((acc, key) => (acc && acc[key] !== undefined ? acc[key] : ''), obj);
188
+ }
189
+ }
@@ -0,0 +1,16 @@
1
+ /* tslint:disable:no-unused-variable */
2
+
3
+ import { TestBed, async, inject } from '@angular/core/testing';
4
+ import { SplitColumnsService } from './split-columns.service';
5
+
6
+ describe('Service: SplitColumns', () => {
7
+ beforeEach(() => {
8
+ TestBed.configureTestingModule({
9
+ providers: [SplitColumnsService]
10
+ });
11
+ });
12
+
13
+ it('should ...', inject([SplitColumnsService], (service: SplitColumnsService) => {
14
+ expect(service).toBeTruthy();
15
+ }));
16
+ });
@@ -0,0 +1,148 @@
1
+ import { Injectable } from '@angular/core';
2
+
3
+ @Injectable({
4
+ providedIn: 'root',
5
+ })
6
+ export class SplitColumnsService {
7
+ prepareColumns(columns: any[], containerWidth: number): any {
8
+ const left: any[] = [];
9
+ const center: any[] = [];
10
+ const right: any[] = [];
11
+
12
+ for (const col of columns) {
13
+ if (col.children?.length) {
14
+ const leftChildren: any[] = [];
15
+ const centerChildren: any[] = [];
16
+ const rightChildren: any[] = [];
17
+
18
+ for (const child of col.children) {
19
+ if (child.is_visible === false) continue;
20
+
21
+ const pinned = child.pinned ?? col.pinned ?? null;
22
+ const childWithPinned = { ...child, pinned };
23
+
24
+ if (pinned === 'left') leftChildren.push(childWithPinned);
25
+ else if (pinned === 'right') rightChildren.push(childWithPinned);
26
+ else centerChildren.push(childWithPinned);
27
+ }
28
+
29
+ if (leftChildren.length) {
30
+ left.push({ header: col.header, children: leftChildren, id: col?.id || col?._id });
31
+ }
32
+ if (centerChildren.length) {
33
+ center.push({
34
+ header: col.header,
35
+ children: centerChildren,
36
+ id: col.id || col._id,
37
+ });
38
+ }
39
+ if (rightChildren.length) {
40
+ right.push({
41
+ header: col.header,
42
+ children: rightChildren,
43
+ id: col.id || col._id,
44
+ });
45
+ }
46
+ } else if (col.is_visible !== false) {
47
+ const pinned = col.pinned ?? null;
48
+ if (pinned === 'left') left.push(col);
49
+ else if (pinned === 'right') right.push(col);
50
+ else center.push(col);
51
+ }
52
+ }
53
+
54
+ return { left, center, right };
55
+ }
56
+
57
+ setColumnsQuery(columns: any[]) {
58
+ for (const col of columns) {
59
+ // if (col.children?.length) {
60
+ // for (const child of col.children) {
61
+ // if (!child?.query?.firt_value && !child?.query?._ids?.length) {
62
+ // child['query'] = {
63
+ // first_condition: 'contain',
64
+ // first_value: null,
65
+ // condition: 'none',
66
+ // second_condition: 'contain',
67
+ // second_value: null,
68
+ // _ids: [],
69
+ // };
70
+ // }
71
+ // }
72
+ // }
73
+ // if (!col?.query?.firt_value && !col?.query?._ids?.length) {
74
+ // col.query = {
75
+ // first_condition: 'contain',
76
+ // first_value: null,
77
+ // condition: 'none',
78
+ // second_condition: 'contain',
79
+ // second_value: null,
80
+ // _ids: [],
81
+ // };
82
+ // }
83
+ }
84
+
85
+ console.log('Updated Columns: ', columns);
86
+
87
+ return columns;
88
+ }
89
+
90
+ assignDefaultWidths(columns: any[], containerWidth: number): any[] {
91
+ const visibleLeafCols = this.getVisibleLeafColumns(columns);
92
+
93
+ if (!visibleLeafCols.length) return columns;
94
+
95
+ let defaultWidth = Math.floor(containerWidth / visibleLeafCols.length);
96
+ if (defaultWidth < 80) defaultWidth = 80;
97
+
98
+ const cloneColumns = (cols: any[]): any[] =>
99
+ cols.map((col) => {
100
+ if (col.children?.length) {
101
+ const newChildren = col.children.map((child: any) => {
102
+ // If visible → dynamic default width
103
+ // If invisible → fixed 150px
104
+ if (!child.width) {
105
+ if (child.is_visible === false) {
106
+ return { ...child, width: 150 };
107
+ } else {
108
+ return { ...child, width: defaultWidth };
109
+ }
110
+ }
111
+ return { ...child };
112
+ });
113
+
114
+ return { ...col, children: newChildren };
115
+ }
116
+
117
+ if (!col.width) {
118
+ if (col.is_visible === false) {
119
+ return { ...col, width: 150 };
120
+ } else {
121
+ return { ...col, width: defaultWidth };
122
+ }
123
+ }
124
+
125
+ return { ...col };
126
+ });
127
+
128
+ return cloneColumns(columns);
129
+ }
130
+
131
+
132
+ private getVisibleLeafColumns(columns: any[]): any[] {
133
+ const result: any[] = [];
134
+
135
+ for (const col of columns) {
136
+ if (col.children?.length) {
137
+ const visibleChildren = col.children.filter(
138
+ (c: any) => c.is_visible !== false
139
+ );
140
+ result.push(...visibleChildren);
141
+ } else if (col.is_visible !== false) {
142
+ result.push(col);
143
+ }
144
+ }
145
+
146
+ return result;
147
+ }
148
+ }
@@ -0,0 +1,16 @@
1
+ /* tslint:disable:no-unused-variable */
2
+
3
+ import { TestBed, async, inject } from '@angular/core/testing';
4
+ import { SwapColumnsService } from './swap-columns.service';
5
+
6
+ describe('Service: SwapColumns', () => {
7
+ beforeEach(() => {
8
+ TestBed.configureTestingModule({
9
+ providers: [SwapColumnsService]
10
+ });
11
+ });
12
+
13
+ it('should ...', inject([SwapColumnsService], (service: SwapColumnsService) => {
14
+ expect(service).toBeTruthy();
15
+ }));
16
+ });
@@ -0,0 +1,162 @@
1
+ import { Injectable } from '@angular/core';
2
+
3
+ @Injectable({
4
+ providedIn: 'root',
5
+ })
6
+ export class SwapColumnsService {
7
+ constructor() {}
8
+
9
+ deepClone(obj: any) {
10
+ return JSON.parse(JSON.stringify(obj));
11
+ }
12
+
13
+ flattenColumnsWithPaths(columns: any[]): { col: any; path: number[] }[] {
14
+ const result: { col: any; path: number[] }[] = [];
15
+
16
+ const recurse = (cols: any[], currentPath: number[] = []) => {
17
+ cols.forEach((col, index) => {
18
+ const path = [...currentPath, index];
19
+ result.push({ col, path });
20
+
21
+ if (Array.isArray(col.children)) {
22
+ recurse(col.children, path);
23
+ }
24
+ });
25
+ };
26
+
27
+ recurse(columns);
28
+ return result;
29
+ }
30
+
31
+ findColumnByIndex(
32
+ columns: any[],
33
+ index: number,
34
+ flat: any[],
35
+ _path: number[][] = [],
36
+ currentPath: number[] = []
37
+ ): { column: any; parent: any[]; path: number[] } | null {
38
+ for (let i = 0; i < columns.length; i++) {
39
+ const col = columns[i];
40
+ const nextPath = [...currentPath, i];
41
+
42
+ if (flat[index] === col) {
43
+ return { column: col, parent: columns, path: nextPath };
44
+ }
45
+
46
+ if (Array.isArray(col?.children)) {
47
+ const result = this.findColumnByIndex(
48
+ col?.children,
49
+ index,
50
+ flat,
51
+ _path,
52
+ nextPath
53
+ );
54
+ if (result) return result;
55
+ }
56
+ }
57
+
58
+ return null;
59
+ }
60
+
61
+ insertAtPath(columns: any[], path: number[], newColumn: any): any[] {
62
+ const cloned = this.deepClone(columns);
63
+ let current = cloned;
64
+
65
+ for (let i = 0; i < path.length - 1; i++) {
66
+ if (!current[path[i]]?.children) {
67
+ current[path[i]]!.children = [];
68
+ }
69
+
70
+ current = current[path[i]]?.children;
71
+ }
72
+
73
+ const insertIndex = path[path.length - 1];
74
+ current.splice(insertIndex, 0, newColumn);
75
+ return cloned;
76
+ }
77
+
78
+ removeAtPath(columns: any[], path: number[]): any[] {
79
+ const cloned = this.deepClone(columns);
80
+ let current = cloned;
81
+
82
+ for (let i = 0; i < path.length - 1; i++) {
83
+ if (!current[path[i]]?.children) {
84
+ return cloned; // Safety: path is invalid
85
+ }
86
+ current = current[path[i]]?.children;
87
+ }
88
+
89
+ const removeIndex = path[path.length - 1];
90
+ if (Array.isArray(current) && current.length > removeIndex) {
91
+ current.splice(removeIndex, 1);
92
+ }
93
+
94
+ return cloned;
95
+ }
96
+
97
+ swapColumnsInTree(
98
+ currentColumn: any,
99
+ columns: any[],
100
+ fromIndex: number,
101
+ toIndex: number
102
+ ): any[] {
103
+ const flat = this.flattenColumnsWithPaths(columns);
104
+
105
+ if (
106
+ fromIndex < 0 ||
107
+ toIndex < 0 ||
108
+ fromIndex >= flat.length ||
109
+ toIndex >= flat.length
110
+ ) {
111
+ return columns; // invalid indices
112
+ }
113
+
114
+ const fromInfo = this.findColumnByIndex(columns, fromIndex, flat);
115
+ const toInfo = this.findColumnByIndex(columns, toIndex, flat);
116
+
117
+ if (!fromInfo || !toInfo) return columns;
118
+
119
+ const fromCol = fromInfo.column;
120
+ const toCol = toInfo.column;
121
+
122
+ let updatedCols = this.removeAtPath(columns, fromInfo.path);
123
+
124
+ // Case 1: Same parent
125
+ if (
126
+ JSON.stringify(fromInfo.path.slice(0, -1)) ===
127
+ JSON.stringify(toInfo.path.slice(0, -1))
128
+ ) {
129
+ return this.insertAtPath(updatedCols, toInfo.path, fromCol);
130
+ }
131
+
132
+ // Case 2: Drop target is a group header
133
+ if (Array.isArray(toCol?.children)) {
134
+ const cloned = this.deepClone(updatedCols);
135
+ let parent = cloned;
136
+
137
+ for (let i = 0; i < toInfo.path.length - 1; i++) {
138
+ parent = parent[toInfo.path[i]].children;
139
+ }
140
+
141
+ const target = parent[toInfo.path[toInfo.path.length - 1]];
142
+ if (!target.children) {
143
+ target.children = [];
144
+ }
145
+
146
+ target.children.push(fromCol);
147
+ return cloned;
148
+ }
149
+
150
+ // Case 3: Drop target is a regular column → wrap both into a group
151
+ const groupHeader = {
152
+ headerName: toCol.headerName || 'Group',
153
+ children: [toCol, fromCol],
154
+ };
155
+
156
+ // Remove target from its original location
157
+ updatedCols = this.removeAtPath(updatedCols, toInfo.path);
158
+
159
+ // Insert group at target index
160
+ return this.insertAtPath(updatedCols, toInfo.path, groupHeader);
161
+ }
162
+ }
@@ -0,0 +1,6 @@
1
+ /*
2
+ * Public API Surface of data-grid
3
+ */
4
+
5
+ export * from './lib/data-grid.module';
6
+ export * from './lib/data-grid/data-grid.component';
@@ -0,0 +1,4 @@
1
+ declare module 'xlsx-style' {
2
+ import * as XLSX from 'xlsx';
3
+ export = XLSX;
4
+ }
@@ -0,0 +1,19 @@
1
+ {
2
+ "extends": "../../tsconfig.json",
3
+ "compilerOptions": {
4
+ "outDir": "../../out-tsc/lib",
5
+ "declaration": true,
6
+ "declarationMap": true,
7
+ "inlineSources": true,
8
+ "types": [],
9
+ "target": "es2019",
10
+ "lib": ["es2019", "dom"]
11
+ },
12
+ "exclude": [
13
+ "**/*.spec.ts"
14
+ ],
15
+ "include": [
16
+ "src/**/*.ts",
17
+ "src/typings.d.ts"
18
+ ]
19
+ }
@@ -0,0 +1,10 @@
1
+ /* To learn more about this file see: https://angular.io/config/tsconfig. */
2
+ {
3
+ "extends": "./tsconfig.lib.json",
4
+ "compilerOptions": {
5
+ "declarationMap": false
6
+ },
7
+ "angularCompilerOptions": {
8
+ "compilationMode": "partial"
9
+ }
10
+ }
@@ -0,0 +1,14 @@
1
+ /* To learn more about this file see: https://angular.io/config/tsconfig. */
2
+ {
3
+ "extends": "../../tsconfig.json",
4
+ "compilerOptions": {
5
+ "outDir": "../../out-tsc/spec",
6
+ "types": [
7
+ "jasmine"
8
+ ]
9
+ },
10
+ "include": [
11
+ "**/*.spec.ts",
12
+ "**/*.d.ts"
13
+ ]
14
+ }