@haus-tech/product-import-export-plugin 2.2.0-dev.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.
- package/dist/api/plugin.controller.d.ts +8 -0
- package/dist/api/plugin.controller.js +49 -0
- package/dist/api/product-export.controller.d.ts +14 -0
- package/dist/api/product-export.controller.js +117 -0
- package/dist/api/product-import.controller.d.ts +11 -0
- package/dist/api/product-import.controller.js +62 -0
- package/dist/constants.d.ts +2 -0
- package/dist/constants.js +5 -0
- package/dist/helpers/generate-asset-hash.d.ts +2 -0
- package/dist/helpers/generate-asset-hash.js +15 -0
- package/dist/helpers/normalize-string.d.ts +1 -0
- package/dist/helpers/normalize-string.js +16 -0
- package/dist/helpers/remove-update-at-fields.d.ts +5 -0
- package/dist/helpers/remove-update-at-fields.js +19 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +17 -0
- package/dist/product-import-export.plugin.d.ts +13 -0
- package/dist/product-import-export.plugin.js +153 -0
- package/dist/providers/import-providers/asset-importer.d.ts +27 -0
- package/dist/providers/import-providers/asset-importer.js +127 -0
- package/dist/providers/import-providers/import-parser.d.ts +137 -0
- package/dist/providers/import-providers/import-parser.js +600 -0
- package/dist/providers/import-providers/product-importer.d.ts +47 -0
- package/dist/providers/import-providers/product-importer.js +729 -0
- package/dist/services/extended-fast-importer.service.d.ts +41 -0
- package/dist/services/extended-fast-importer.service.js +418 -0
- package/dist/services/product-export.service.d.ts +23 -0
- package/dist/services/product-export.service.js +340 -0
- package/dist/services/product-import.service.d.ts +21 -0
- package/dist/services/product-import.service.js +83 -0
- package/dist/types.d.ts +40 -0
- package/dist/types.js +2 -0
- package/dist/ui/components/export-dialog.component.d.ts +43 -0
- package/dist/ui/components/export-dialog.component.html +78 -0
- package/dist/ui/components/export-dialog.component.js +108 -0
- package/dist/ui/components/export-dialog.component.ts +142 -0
- package/dist/ui/components/product-import.component.d.ts +55 -0
- package/dist/ui/components/product-import.component.html +76 -0
- package/dist/ui/components/product-import.component.js +398 -0
- package/dist/ui/components/product-import.component.ts +528 -0
- package/dist/ui/product-export.service.d.ts +14 -0
- package/dist/ui/product-export.service.js +107 -0
- package/dist/ui/product-export.service.ts +107 -0
- package/dist/ui/providers.d.ts +2 -0
- package/dist/ui/providers.js +49 -0
- package/dist/ui/providers.ts +57 -0
- package/dist/ui/routes.d.ts +29 -0
- package/dist/ui/routes.js +12 -0
- package/dist/ui/routes.ts +11 -0
- package/dist/ui/translations/en.json +44 -0
- package/dist/ui/translations/sv.json +44 -0
- package/package.json +30 -0
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { Injectable } from '@angular/core'
|
|
2
|
+
import {
|
|
3
|
+
DataService,
|
|
4
|
+
LocalStorageService,
|
|
5
|
+
NotificationService,
|
|
6
|
+
getServerLocation,
|
|
7
|
+
} from '@vendure/admin-ui/core'
|
|
8
|
+
import { Product } from '@vendure/core'
|
|
9
|
+
|
|
10
|
+
@Injectable()
|
|
11
|
+
export class ProductExportService {
|
|
12
|
+
serverPath: string
|
|
13
|
+
constructor(
|
|
14
|
+
protected dataService: DataService,
|
|
15
|
+
private notificationService: NotificationService,
|
|
16
|
+
private localStorageService: LocalStorageService,
|
|
17
|
+
) {
|
|
18
|
+
this.serverPath = getServerLocation()
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async getCustomFields(productIds: string[]) {
|
|
22
|
+
return fetch(`${this.serverPath}/product-export/custom-fields`, {
|
|
23
|
+
method: 'POST',
|
|
24
|
+
headers: {
|
|
25
|
+
'Content-Type': 'application/json',
|
|
26
|
+
...this.getHeaders(),
|
|
27
|
+
},
|
|
28
|
+
body: JSON.stringify(productIds),
|
|
29
|
+
})
|
|
30
|
+
.then((res) => res.json())
|
|
31
|
+
.then((data: { name: string; type: string }[]) => {
|
|
32
|
+
return data.map((field) => field.name)
|
|
33
|
+
})
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async getConfig() {
|
|
37
|
+
return fetch(`${this.serverPath}/product-import-export/config`, {
|
|
38
|
+
method: 'GET',
|
|
39
|
+
headers: {
|
|
40
|
+
'Content-Type': 'application/json',
|
|
41
|
+
...this.getHeaders(),
|
|
42
|
+
},
|
|
43
|
+
})
|
|
44
|
+
.then((res) => res.json())
|
|
45
|
+
.then((data) => data)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
async exportProducts(
|
|
49
|
+
selection: Product[],
|
|
50
|
+
fileName?: string,
|
|
51
|
+
customFields?: string[],
|
|
52
|
+
exportAssetsAs?: 'url' | 'json',
|
|
53
|
+
selectedExportFields?: string[],
|
|
54
|
+
) {
|
|
55
|
+
this.notificationService.info(`Exporting ${selection.length} products to ${fileName}.csv`)
|
|
56
|
+
const productIds = selection.map((product) => product.id)
|
|
57
|
+
try {
|
|
58
|
+
const res = await fetch(
|
|
59
|
+
`${this.serverPath}/product-export/export?fileName=${fileName}&customFields=${customFields}&exportAssetsAs=${exportAssetsAs}&selectedExportFields=${selectedExportFields}`,
|
|
60
|
+
{
|
|
61
|
+
method: 'POST',
|
|
62
|
+
headers: {
|
|
63
|
+
'Content-Type': 'application/json',
|
|
64
|
+
...this.getHeaders(),
|
|
65
|
+
},
|
|
66
|
+
body: JSON.stringify(productIds),
|
|
67
|
+
},
|
|
68
|
+
)
|
|
69
|
+
if (!res.ok) {
|
|
70
|
+
const json = await res.json()
|
|
71
|
+
throw Error(json?.message)
|
|
72
|
+
}
|
|
73
|
+
const header = res.headers.get('Content-Disposition')
|
|
74
|
+
const parts = header!.split(';')
|
|
75
|
+
const filename = parts[1].split('=')[1]
|
|
76
|
+
const blob = await res.blob()
|
|
77
|
+
await this.downloadBlob(blob, filename)
|
|
78
|
+
} catch (err: any) {
|
|
79
|
+
console.error(err)
|
|
80
|
+
this.notificationService.error(err.message)
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
private getHeaders(): Record<string, string> {
|
|
85
|
+
const headers: Record<string, string> = {}
|
|
86
|
+
const channelToken = this.localStorageService.get('activeChannelToken')
|
|
87
|
+
if (channelToken) {
|
|
88
|
+
headers['vendure-token'] = channelToken
|
|
89
|
+
}
|
|
90
|
+
const authToken = this.localStorageService.get('authToken')
|
|
91
|
+
if (authToken) {
|
|
92
|
+
headers.authorization = `Bearer ${authToken}`
|
|
93
|
+
}
|
|
94
|
+
return headers
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
private async downloadBlob(blob: Blob, fileName: string): Promise<void> {
|
|
98
|
+
const blobUrl = window.URL.createObjectURL(blob)
|
|
99
|
+
const a = document.createElement('a')
|
|
100
|
+
document.body.appendChild(a)
|
|
101
|
+
a.setAttribute('hidden', 'true')
|
|
102
|
+
a.href = blobUrl
|
|
103
|
+
a.download = fileName
|
|
104
|
+
a.setAttribute('target', '_blank')
|
|
105
|
+
a.click()
|
|
106
|
+
}
|
|
107
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const core_1 = require("@vendure/admin-ui/core");
|
|
4
|
+
const product_import_component_1 = require("./components/product-import.component");
|
|
5
|
+
const export_dialog_component_1 = require("./components/export-dialog.component");
|
|
6
|
+
const core_2 = require("@vendure/admin-ui/core");
|
|
7
|
+
const product_export_service_1 = require("./product-export.service");
|
|
8
|
+
const ngx_translate_extract_marker_1 = require("@biesbjerg/ngx-translate-extract-marker");
|
|
9
|
+
exports.default = [
|
|
10
|
+
(0, core_1.registerPageTab)({
|
|
11
|
+
location: 'product-list',
|
|
12
|
+
tab: (0, ngx_translate_extract_marker_1.marker)('product-import.import-products'),
|
|
13
|
+
route: 'import',
|
|
14
|
+
tabIcon: 'import',
|
|
15
|
+
component: product_import_component_1.ProductImportComponent,
|
|
16
|
+
}),
|
|
17
|
+
(0, core_2.registerBulkAction)({
|
|
18
|
+
location: 'product-list',
|
|
19
|
+
label: (0, ngx_translate_extract_marker_1.marker)('product-export.action'),
|
|
20
|
+
icon: 'export',
|
|
21
|
+
onClick: ({ injector, selection }) => {
|
|
22
|
+
const modalService = injector.get(core_2.ModalService);
|
|
23
|
+
const productExportService = injector.get(product_export_service_1.ProductExportService);
|
|
24
|
+
const productIds = selection.map((product) => product.id);
|
|
25
|
+
const promises = [
|
|
26
|
+
productExportService.getCustomFields(productIds),
|
|
27
|
+
productExportService.getConfig(),
|
|
28
|
+
];
|
|
29
|
+
Promise.all(promises).then(([customFields, config]) => {
|
|
30
|
+
modalService
|
|
31
|
+
.fromComponent(export_dialog_component_1.ExportDialogComponent, {
|
|
32
|
+
size: 'md',
|
|
33
|
+
locals: {
|
|
34
|
+
selection,
|
|
35
|
+
customFields,
|
|
36
|
+
config: config.exportOptions,
|
|
37
|
+
},
|
|
38
|
+
closable: true,
|
|
39
|
+
})
|
|
40
|
+
.subscribe((response) => {
|
|
41
|
+
if (response?.result) {
|
|
42
|
+
productExportService.exportProducts(selection, response.fileName, response.selectedFields, response.exportAssetsAs, response.selectedExportFields);
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
},
|
|
47
|
+
}),
|
|
48
|
+
product_export_service_1.ProductExportService,
|
|
49
|
+
];
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { registerPageTab } from '@vendure/admin-ui/core'
|
|
2
|
+
import { ProductImportComponent } from './components/product-import.component'
|
|
3
|
+
import { ExportDialogComponent } from './components/export-dialog.component'
|
|
4
|
+
import { ModalService, registerBulkAction } from '@vendure/admin-ui/core'
|
|
5
|
+
import { ProductExportService } from './product-export.service'
|
|
6
|
+
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'
|
|
7
|
+
|
|
8
|
+
export default [
|
|
9
|
+
registerPageTab({
|
|
10
|
+
location: 'product-list',
|
|
11
|
+
tab: _('product-import.import-products'),
|
|
12
|
+
route: 'import',
|
|
13
|
+
tabIcon: 'import',
|
|
14
|
+
component: ProductImportComponent,
|
|
15
|
+
}),
|
|
16
|
+
registerBulkAction({
|
|
17
|
+
location: 'product-list',
|
|
18
|
+
label: _('product-export.action'),
|
|
19
|
+
icon: 'export',
|
|
20
|
+
onClick: ({ injector, selection }) => {
|
|
21
|
+
const modalService = injector.get(ModalService)
|
|
22
|
+
const productExportService = injector.get(ProductExportService)
|
|
23
|
+
|
|
24
|
+
const productIds = selection.map((product) => product.id)
|
|
25
|
+
|
|
26
|
+
const promises = [
|
|
27
|
+
productExportService.getCustomFields(productIds),
|
|
28
|
+
productExportService.getConfig(),
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
Promise.all(promises).then(([customFields, config]) => {
|
|
32
|
+
modalService
|
|
33
|
+
.fromComponent(ExportDialogComponent, {
|
|
34
|
+
size: 'md',
|
|
35
|
+
locals: {
|
|
36
|
+
selection,
|
|
37
|
+
customFields,
|
|
38
|
+
config: config.exportOptions,
|
|
39
|
+
},
|
|
40
|
+
closable: true,
|
|
41
|
+
})
|
|
42
|
+
.subscribe((response) => {
|
|
43
|
+
if (response?.result) {
|
|
44
|
+
productExportService.exportProducts(
|
|
45
|
+
selection,
|
|
46
|
+
response.fileName,
|
|
47
|
+
response.selectedFields,
|
|
48
|
+
response.exportAssetsAs,
|
|
49
|
+
response.selectedExportFields,
|
|
50
|
+
)
|
|
51
|
+
}
|
|
52
|
+
})
|
|
53
|
+
})
|
|
54
|
+
},
|
|
55
|
+
}),
|
|
56
|
+
ProductExportService,
|
|
57
|
+
]
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
declare const _default: {
|
|
2
|
+
resolve: {
|
|
3
|
+
detail?: import("@angular/router").ResolveFn<{
|
|
4
|
+
entity: import("rxjs").Observable<any>;
|
|
5
|
+
result?: any;
|
|
6
|
+
}> | undefined;
|
|
7
|
+
};
|
|
8
|
+
data: {
|
|
9
|
+
breadcrumb: import("rxjs").BehaviorSubject<import("@vendure/admin-ui/core").BreadcrumbValue> | ((data: any) => any);
|
|
10
|
+
};
|
|
11
|
+
component: typeof import("@vendure/admin-ui/core").AngularRouteComponent;
|
|
12
|
+
title?: string | import("@angular/core").Type<import("@angular/router").Resolve<string>> | import("@angular/router").ResolveFn<string> | undefined;
|
|
13
|
+
path: string;
|
|
14
|
+
pathMatch?: "prefix" | "full" | undefined;
|
|
15
|
+
matcher?: import("@angular/router").UrlMatcher | undefined;
|
|
16
|
+
loadComponent?: (() => import("@angular/core").Type<unknown> | import("rxjs").Observable<import("@angular/core").Type<unknown> | import("@angular/router").DefaultExport<import("@angular/core").Type<unknown>>> | Promise<import("@angular/core").Type<unknown> | import("@angular/router").DefaultExport<import("@angular/core").Type<unknown>>>) | undefined;
|
|
17
|
+
redirectTo?: string | undefined;
|
|
18
|
+
outlet?: string | undefined;
|
|
19
|
+
canActivate?: any[] | undefined;
|
|
20
|
+
canMatch?: any[] | undefined;
|
|
21
|
+
canActivateChild?: any[] | undefined;
|
|
22
|
+
canDeactivate?: any[] | undefined;
|
|
23
|
+
canLoad?: any[] | undefined;
|
|
24
|
+
children?: import("@angular/router").Routes | undefined;
|
|
25
|
+
loadChildren?: import("@angular/router").LoadChildrenCallback | undefined;
|
|
26
|
+
runGuardsAndResolvers?: import("@angular/router").RunGuardsAndResolvers | undefined;
|
|
27
|
+
providers: (import("@angular/core").Provider | import("@angular/core").EnvironmentProviders)[];
|
|
28
|
+
}[];
|
|
29
|
+
export default _default;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const core_1 = require("@vendure/admin-ui/core");
|
|
4
|
+
const product_import_component_1 = require("./components/product-import.component");
|
|
5
|
+
exports.default = [
|
|
6
|
+
(0, core_1.registerRouteComponent)({
|
|
7
|
+
component: product_import_component_1.ProductImportComponent,
|
|
8
|
+
path: '',
|
|
9
|
+
title: 'Import Products',
|
|
10
|
+
breadcrumb: 'Import Products',
|
|
11
|
+
}),
|
|
12
|
+
];
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { registerRouteComponent } from '@vendure/admin-ui/core'
|
|
2
|
+
import { ProductImportComponent } from './components/product-import.component'
|
|
3
|
+
|
|
4
|
+
export default [
|
|
5
|
+
registerRouteComponent({
|
|
6
|
+
component: ProductImportComponent,
|
|
7
|
+
path: '',
|
|
8
|
+
title: 'Import Products',
|
|
9
|
+
breadcrumb: 'Import Products',
|
|
10
|
+
}),
|
|
11
|
+
]
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"product-import": {
|
|
3
|
+
"import-products": "Import products",
|
|
4
|
+
"card": {
|
|
5
|
+
"title": "Import products from CSV",
|
|
6
|
+
"description": "Choose a CSV file to import products from",
|
|
7
|
+
"button-select": "Select file",
|
|
8
|
+
"button-upload": "Upload file",
|
|
9
|
+
"update-product-slugs": "Update product slugs based on name"
|
|
10
|
+
},
|
|
11
|
+
"notifications": {
|
|
12
|
+
"invalid-file-type": "Invalid file type. Please upload a CSV file.",
|
|
13
|
+
"invalid-file-structure": "Invalid file structure. Please upload a correct CSV file.",
|
|
14
|
+
"upload-success": "The file was uploaded and has been added to the import queue.",
|
|
15
|
+
"upload-error": "An error occurred while uploading the file.",
|
|
16
|
+
"no-file-selected": "No file selected.",
|
|
17
|
+
"mismatched-values": "Some fields are missing language specifications. Please fill in all languages: ",
|
|
18
|
+
"missing-base-columns": "Some columns are missing: ",
|
|
19
|
+
"missing-column": "Column is missing: ",
|
|
20
|
+
"no-lines-in-file": "The file is empty.",
|
|
21
|
+
"file-read-error": "An error occurred while reading the file.",
|
|
22
|
+
"invalid-json": "Invalid JSON structure. Please upload a correct JSON file.",
|
|
23
|
+
"missing-languages": "Your CSV file contains languages that are not available in the system. Please add the languages to the system or remove the languages that are not used and try again.",
|
|
24
|
+
"mismatched-option-values": "Some product variants are missing product options. Please fill in all options: ",
|
|
25
|
+
"missing-main-language-name": "Main language is missing for name. Please add the main language and try again.",
|
|
26
|
+
"missing-translation-values": "Some fields are missing translations for the main language that exist in other languages. These will not be imported: "
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
"product-export": {
|
|
30
|
+
"action": "Export products to CSV",
|
|
31
|
+
"dialog": {
|
|
32
|
+
"title": "Export products to CSV",
|
|
33
|
+
"label": "File name (optional)",
|
|
34
|
+
"export": "Export",
|
|
35
|
+
"cancel": "Cancel",
|
|
36
|
+
"customFieldsLabel": "Custom fields to include in the export",
|
|
37
|
+
"exportAssetsAs": "Export assets as: ",
|
|
38
|
+
"exportAssetsAsOptions": {
|
|
39
|
+
"url": "URL",
|
|
40
|
+
"json": "JSON"
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"product-import": {
|
|
3
|
+
"import-products": "Importera produkter",
|
|
4
|
+
"card": {
|
|
5
|
+
"title": "Importera produkter från CSV",
|
|
6
|
+
"description": "Välj en CSV-fil att importera produkter från",
|
|
7
|
+
"button-select": "Välj fil",
|
|
8
|
+
"button-upload": "Ladda upp fil",
|
|
9
|
+
"update-product-slugs": "Uppdatera produkt-sluggar utifrån namn"
|
|
10
|
+
},
|
|
11
|
+
"notifications": {
|
|
12
|
+
"invalid-file-type": "Felaktig filtyp. Vänligen ladda upp en CSV-fil.",
|
|
13
|
+
"invalid-file-structure": "Felaktig filstruktur. Vänligen ladda upp en korrekt CSV-fil.",
|
|
14
|
+
"upload-success": "Filen laddades upp och har lagts till i kön för import.",
|
|
15
|
+
"upload-error": "Ett fel uppstod vid uppladdning av filen.",
|
|
16
|
+
"no-file-selected": "Ingen fil vald.",
|
|
17
|
+
"mismatched-values": "Det saknas språkspecifikationer för vissa fält. Vänligen fyll i alla språk: ",
|
|
18
|
+
"missing-base-columns": "Vissa kolumner saknas: ",
|
|
19
|
+
"missing-column": "Kolumnen saknas: ",
|
|
20
|
+
"no-lines-in-file": "Filen är tom.",
|
|
21
|
+
"file-read-error": "Ett fel uppstod vid läsning av filen.",
|
|
22
|
+
"invalid-json": "Felaktig JSON-struktur. Vänligen ladda upp en korrekt JSON-fil.",
|
|
23
|
+
"missing-languages": "Din CSV-fil innehåller språk som inte är tillgängliga i den här kanalen. Vänligen lägg till språken i kanalen eller ta bort de språk som inte används och försök igen.",
|
|
24
|
+
"mismatched-option-values": "Antalet produktalternativ för vissa produktvarianter är felaktigt: ",
|
|
25
|
+
"missing-main-language-name": "Huvudspråket saknas för namn. Vänligen lägg till huvudspråket och försök igen.",
|
|
26
|
+
"missing-translation-values": "Det saknas översättningar för vissa fält för huvudspråket som existerar i andra språk. Dessa kommer inte importeras: "
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
"product-export": {
|
|
30
|
+
"action": "Exportera produkter till CSV",
|
|
31
|
+
"dialog": {
|
|
32
|
+
"title": "Exportera produkter till CSV",
|
|
33
|
+
"label": "Filnamn (valfritt)",
|
|
34
|
+
"export": "Exportera",
|
|
35
|
+
"cancel": "Avbryt",
|
|
36
|
+
"customFieldsLabel": "Anpassade fält som ska inkluderas i exporten",
|
|
37
|
+
"exportAssetsAs": "Exportera filer som: ",
|
|
38
|
+
"exportAssetsAsOptions": {
|
|
39
|
+
"url": "URL",
|
|
40
|
+
"json": "JSON"
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@haus-tech/product-import-export-plugin",
|
|
3
|
+
"version": "2.2.0-dev.0",
|
|
4
|
+
"description": "A Vendure plugin for importing and exporting products using a CSV file",
|
|
5
|
+
"author": "Haus Tech",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/WeAreHausTech/haus-tech-vendure-plugins.git"
|
|
9
|
+
},
|
|
10
|
+
"license": "MIT",
|
|
11
|
+
"engines": {
|
|
12
|
+
"node": ">=20.0.0"
|
|
13
|
+
},
|
|
14
|
+
"main": "dist/index.js",
|
|
15
|
+
"types": "dist/index.d.ts",
|
|
16
|
+
"files": [
|
|
17
|
+
"dist",
|
|
18
|
+
"README.md"
|
|
19
|
+
],
|
|
20
|
+
"scripts": {
|
|
21
|
+
"start": "yarn ts-node test/dev-server.ts",
|
|
22
|
+
"build": "yarn run -T rimraf dist && yarn run -T tsc && yarn run -T copyfiles -u 1 'src/ui/**/*' dist/",
|
|
23
|
+
"test": "jest --preset=\"ts-jest\"",
|
|
24
|
+
"prepublishOnly": "yarn && yarn build"
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"csv-parse": "^5.5.6",
|
|
28
|
+
"csv-stringify": "^6.5.1"
|
|
29
|
+
}
|
|
30
|
+
}
|