@0xtorch/csv 0.0.1
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/.DS_Store +0 -0
- package/_cjs/formatCsvRows.js +67 -0
- package/_cjs/formatCsvRows.js.map +1 -0
- package/_cjs/index.js +12 -0
- package/_cjs/index.js.map +1 -0
- package/_cjs/package.json +1 -0
- package/_cjs/parseCsvFileToAccountActions.js +26 -0
- package/_cjs/parseCsvFileToAccountActions.js.map +1 -0
- package/_cjs/parseCsvFileToText.js +15 -0
- package/_cjs/parseCsvFileToText.js.map +1 -0
- package/_cjs/parseCsvRowToNormalAction/asset.js +62 -0
- package/_cjs/parseCsvRowToNormalAction/asset.js.map +1 -0
- package/_cjs/parseCsvRowToNormalAction/condition.js +32 -0
- package/_cjs/parseCsvRowToNormalAction/condition.js.map +1 -0
- package/_cjs/parseCsvRowToNormalAction/index.js +6 -0
- package/_cjs/parseCsvRowToNormalAction/index.js.map +1 -0
- package/_cjs/parseCsvRowToNormalAction/nft.js +15 -0
- package/_cjs/parseCsvRowToNormalAction/nft.js.map +1 -0
- package/_cjs/parseCsvRowToNormalAction/parseCsvRowToNormalAction.js +83 -0
- package/_cjs/parseCsvRowToNormalAction/parseCsvRowToNormalAction.js.map +1 -0
- package/_cjs/parseCsvRowToNormalAction/text.js +31 -0
- package/_cjs/parseCsvRowToNormalAction/text.js.map +1 -0
- package/_cjs/parseCsvRowToNormalAction/timestamp.js +12 -0
- package/_cjs/parseCsvRowToNormalAction/timestamp.js.map +1 -0
- package/_cjs/parseCsvRowToNormalAction/transfer.js +29 -0
- package/_cjs/parseCsvRowToNormalAction/transfer.js.map +1 -0
- package/_cjs/parseCsvRowsToAccountActions.js +49 -0
- package/_cjs/parseCsvRowsToAccountActions.js.map +1 -0
- package/_cjs/parseCsvText.js +15 -0
- package/_cjs/parseCsvText.js.map +1 -0
- package/_cjs/schemas/formatter.js +15 -0
- package/_cjs/schemas/formatter.js.map +1 -0
- package/_cjs/schemas/formatterTypes.js +37 -0
- package/_cjs/schemas/formatterTypes.js.map +1 -0
- package/_cjs/schemas/index.js +6 -0
- package/_cjs/schemas/index.js.map +1 -0
- package/_cjs/schemas/parser.js +80 -0
- package/_cjs/schemas/parser.js.map +1 -0
- package/_cjs/schemas/schemas.js +14 -0
- package/_cjs/schemas/schemas.js.map +1 -0
- package/_cjs/types.js +3 -0
- package/_cjs/types.js.map +1 -0
- package/_esm/formatCsvRows.js +67 -0
- package/_esm/formatCsvRows.js.map +1 -0
- package/_esm/index.js +5 -0
- package/_esm/index.js.map +1 -0
- package/_esm/package.json +1 -0
- package/_esm/parseCsvFileToAccountActions.js +22 -0
- package/_esm/parseCsvFileToAccountActions.js.map +1 -0
- package/_esm/parseCsvFileToText.js +11 -0
- package/_esm/parseCsvFileToText.js.map +1 -0
- package/_esm/parseCsvRowToNormalAction/asset.js +58 -0
- package/_esm/parseCsvRowToNormalAction/asset.js.map +1 -0
- package/_esm/parseCsvRowToNormalAction/condition.js +28 -0
- package/_esm/parseCsvRowToNormalAction/condition.js.map +1 -0
- package/_esm/parseCsvRowToNormalAction/index.js +2 -0
- package/_esm/parseCsvRowToNormalAction/index.js.map +1 -0
- package/_esm/parseCsvRowToNormalAction/nft.js +11 -0
- package/_esm/parseCsvRowToNormalAction/nft.js.map +1 -0
- package/_esm/parseCsvRowToNormalAction/parseCsvRowToNormalAction.js +81 -0
- package/_esm/parseCsvRowToNormalAction/parseCsvRowToNormalAction.js.map +1 -0
- package/_esm/parseCsvRowToNormalAction/text.js +27 -0
- package/_esm/parseCsvRowToNormalAction/text.js.map +1 -0
- package/_esm/parseCsvRowToNormalAction/timestamp.js +8 -0
- package/_esm/parseCsvRowToNormalAction/timestamp.js.map +1 -0
- package/_esm/parseCsvRowToNormalAction/transfer.js +25 -0
- package/_esm/parseCsvRowToNormalAction/transfer.js.map +1 -0
- package/_esm/parseCsvRowsToAccountActions.js +47 -0
- package/_esm/parseCsvRowsToAccountActions.js.map +1 -0
- package/_esm/parseCsvText.js +11 -0
- package/_esm/parseCsvText.js.map +1 -0
- package/_esm/schemas/formatter.js +12 -0
- package/_esm/schemas/formatter.js.map +1 -0
- package/_esm/schemas/formatterTypes.js +35 -0
- package/_esm/schemas/formatterTypes.js.map +1 -0
- package/_esm/schemas/index.js +2 -0
- package/_esm/schemas/index.js.map +1 -0
- package/_esm/schemas/parser.js +100 -0
- package/_esm/schemas/parser.js.map +1 -0
- package/_esm/schemas/schemas.js +11 -0
- package/_esm/schemas/schemas.js.map +1 -0
- package/_esm/types.js +2 -0
- package/_esm/types.js.map +1 -0
- package/_types/formatCsvRows.d.ts +11 -0
- package/_types/formatCsvRows.d.ts.map +1 -0
- package/_types/index.d.ts +6 -0
- package/_types/index.d.ts.map +1 -0
- package/_types/parseCsvFileToAccountActions.d.ts +12 -0
- package/_types/parseCsvFileToAccountActions.d.ts.map +1 -0
- package/_types/parseCsvFileToText.d.ts +2 -0
- package/_types/parseCsvFileToText.d.ts.map +1 -0
- package/_types/parseCsvRowToNormalAction/asset.d.ts +17 -0
- package/_types/parseCsvRowToNormalAction/asset.d.ts.map +1 -0
- package/_types/parseCsvRowToNormalAction/condition.d.ts +10 -0
- package/_types/parseCsvRowToNormalAction/condition.d.ts.map +1 -0
- package/_types/parseCsvRowToNormalAction/index.d.ts +2 -0
- package/_types/parseCsvRowToNormalAction/index.d.ts.map +1 -0
- package/_types/parseCsvRowToNormalAction/nft.d.ts +12 -0
- package/_types/parseCsvRowToNormalAction/nft.d.ts.map +1 -0
- package/_types/parseCsvRowToNormalAction/parseCsvRowToNormalAction.d.ts +20 -0
- package/_types/parseCsvRowToNormalAction/parseCsvRowToNormalAction.d.ts.map +1 -0
- package/_types/parseCsvRowToNormalAction/text.d.ts +11 -0
- package/_types/parseCsvRowToNormalAction/text.d.ts.map +1 -0
- package/_types/parseCsvRowToNormalAction/timestamp.d.ts +8 -0
- package/_types/parseCsvRowToNormalAction/timestamp.d.ts.map +1 -0
- package/_types/parseCsvRowToNormalAction/transfer.d.ts +18 -0
- package/_types/parseCsvRowToNormalAction/transfer.d.ts.map +1 -0
- package/_types/parseCsvRowsToAccountActions.d.ts +16 -0
- package/_types/parseCsvRowsToAccountActions.d.ts.map +1 -0
- package/_types/parseCsvText.d.ts +4 -0
- package/_types/parseCsvText.d.ts.map +1 -0
- package/_types/schemas/formatter.d.ts +4 -0
- package/_types/schemas/formatter.d.ts.map +1 -0
- package/_types/schemas/formatterTypes.d.ts +10 -0
- package/_types/schemas/formatterTypes.d.ts.map +1 -0
- package/_types/schemas/index.d.ts +2 -0
- package/_types/schemas/index.d.ts.map +1 -0
- package/_types/schemas/parser.d.ts +1505 -0
- package/_types/schemas/parser.d.ts.map +1 -0
- package/_types/schemas/schemas.d.ts +806 -0
- package/_types/schemas/schemas.d.ts.map +1 -0
- package/_types/types.d.ts +13 -0
- package/_types/types.d.ts.map +1 -0
- package/formatCsvRows.ts +97 -0
- package/index.ts +5 -0
- package/package.json +50 -0
- package/parseCsvFileToAccountActions.ts +40 -0
- package/parseCsvFileToText.ts +11 -0
- package/parseCsvRowToNormalAction/asset.ts +92 -0
- package/parseCsvRowToNormalAction/condition.ts +39 -0
- package/parseCsvRowToNormalAction/index.ts +1 -0
- package/parseCsvRowToNormalAction/nft.ts +27 -0
- package/parseCsvRowToNormalAction/parseCsvRowToNormalAction.ts +146 -0
- package/parseCsvRowToNormalAction/text.ts +37 -0
- package/parseCsvRowToNormalAction/timestamp.ts +19 -0
- package/parseCsvRowToNormalAction/transfer.ts +55 -0
- package/parseCsvRowsToAccountActions.ts +67 -0
- package/parseCsvText.ts +14 -0
- package/schemas/formatter.ts +13 -0
- package/schemas/formatterTypes.ts +44 -0
- package/schemas/index.ts +1 -0
- package/schemas/parser.ts +110 -0
- package/schemas/schemas.ts +11 -0
- package/tests/assets.ts +28 -0
- package/tests/coincheck-standard.csv +17 -0
- package/tests/coincheck.ts +137 -0
- package/types.ts +17 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schemas.d.ts","sourceRoot":"","sources":["../../schemas/schemas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAIvB,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAM1B,CAAA"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { z } from 'zod';
|
|
2
|
+
import type { csvFormatSchema } from './schemas';
|
|
3
|
+
import type { formatterSchema } from './schemas/formatter';
|
|
4
|
+
import type { formatterValueSchema } from './schemas/formatterTypes';
|
|
5
|
+
import type { parserSchema } from './schemas/parser';
|
|
6
|
+
export type CsvFormat = z.infer<typeof csvFormatSchema>;
|
|
7
|
+
export type Formatter = z.infer<typeof formatterSchema>;
|
|
8
|
+
export type FormatterValue = z.infer<typeof formatterValueSchema>;
|
|
9
|
+
export type FormattedRow = {
|
|
10
|
+
[column: string]: FormatterValue;
|
|
11
|
+
};
|
|
12
|
+
export type Parser = z.infer<typeof parserSchema>;
|
|
13
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAC5B,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,WAAW,CAAA;AAChD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAA;AAC1D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAA;AACpE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAEpD,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAA;AAEvD,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAA;AAEvD,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAA;AAEjE,MAAM,MAAM,YAAY,GAAG;IACzB,CAAC,MAAM,EAAE,MAAM,GAAG,cAAc,CAAA;CACjC,CAAA;AAED,MAAM,MAAM,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAA"}
|
package/formatCsvRows.ts
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import {
|
|
2
|
+
bigDecimalNegativeTextSchema,
|
|
3
|
+
bigDecimalPositiveTextSchema,
|
|
4
|
+
bigDecimalTextSchema,
|
|
5
|
+
blankTextSchema,
|
|
6
|
+
datetimeJpTextSchema,
|
|
7
|
+
iso8601TextSchema,
|
|
8
|
+
stringTextSchema,
|
|
9
|
+
} from './schemas/formatterTypes'
|
|
10
|
+
import type { FormattedRow, Formatter, FormatterValue } from './types'
|
|
11
|
+
|
|
12
|
+
type RawRow = {
|
|
13
|
+
[column: string]: string
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
type FormatCsvRowsParameters = {
|
|
17
|
+
readonly rows: readonly RawRow[]
|
|
18
|
+
readonly formatter: Formatter
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export const formatCsvRows = ({
|
|
22
|
+
rows,
|
|
23
|
+
formatter,
|
|
24
|
+
}: FormatCsvRowsParameters): readonly FormattedRow[] =>
|
|
25
|
+
rows.map((row) => formatCsvRow(row, formatter))
|
|
26
|
+
|
|
27
|
+
const formatCsvRow = (row: RawRow, formatter: Formatter): FormattedRow =>
|
|
28
|
+
Object.fromEntries(
|
|
29
|
+
Object.entries(formatter).map(
|
|
30
|
+
([column, schemaTypes]): [string, FormatterValue] => {
|
|
31
|
+
// column に一致する column が無かったらエラー
|
|
32
|
+
if (!(column in row)) {
|
|
33
|
+
throw new Error(`The column '${column}' does not exist in the CSV`)
|
|
34
|
+
}
|
|
35
|
+
const value = row[column]
|
|
36
|
+
// schema types を順番に調査
|
|
37
|
+
for (const schemaType of schemaTypes) {
|
|
38
|
+
switch (schemaType) {
|
|
39
|
+
case 'blank': {
|
|
40
|
+
const parsed = blankTextSchema.safeParse(value)
|
|
41
|
+
if (!parsed.success) {
|
|
42
|
+
break
|
|
43
|
+
}
|
|
44
|
+
return [column, parsed.data]
|
|
45
|
+
}
|
|
46
|
+
case 'string': {
|
|
47
|
+
const parsed = stringTextSchema.safeParse(value)
|
|
48
|
+
if (!parsed.success) {
|
|
49
|
+
break
|
|
50
|
+
}
|
|
51
|
+
return [column, parsed.data]
|
|
52
|
+
}
|
|
53
|
+
case 'big-decimal': {
|
|
54
|
+
const parsed = bigDecimalTextSchema.safeParse(value)
|
|
55
|
+
if (!parsed.success) {
|
|
56
|
+
break
|
|
57
|
+
}
|
|
58
|
+
return [column, parsed.data]
|
|
59
|
+
}
|
|
60
|
+
case 'big-decimal-negative': {
|
|
61
|
+
const parsed = bigDecimalNegativeTextSchema.safeParse(value)
|
|
62
|
+
if (!parsed.success) {
|
|
63
|
+
break
|
|
64
|
+
}
|
|
65
|
+
return [column, parsed.data]
|
|
66
|
+
}
|
|
67
|
+
case 'big-decimal-positive': {
|
|
68
|
+
const parsed = bigDecimalPositiveTextSchema.safeParse(value)
|
|
69
|
+
if (!parsed.success) {
|
|
70
|
+
break
|
|
71
|
+
}
|
|
72
|
+
return [column, parsed.data]
|
|
73
|
+
}
|
|
74
|
+
case 'iso8601': {
|
|
75
|
+
const parsed = iso8601TextSchema.safeParse(value)
|
|
76
|
+
if (!parsed.success) {
|
|
77
|
+
break
|
|
78
|
+
}
|
|
79
|
+
return [column, parsed.data]
|
|
80
|
+
}
|
|
81
|
+
case 'datetime-jp': {
|
|
82
|
+
const parsed = datetimeJpTextSchema.safeParse(value)
|
|
83
|
+
if (!parsed.success) {
|
|
84
|
+
break
|
|
85
|
+
}
|
|
86
|
+
return [column, parsed.data]
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
// schema に一致したら値を返す
|
|
91
|
+
// 一致する schema type が無かったらエラー
|
|
92
|
+
throw new Error(
|
|
93
|
+
`The column "${column}"'s value "${value}" does not match schema: [${schemaTypes.join(',')}]`,
|
|
94
|
+
)
|
|
95
|
+
},
|
|
96
|
+
),
|
|
97
|
+
)
|
package/index.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { parseCsvFileToAccountActions } from './parseCsvFileToAccountActions'
|
|
2
|
+
export { parseCsvFileToText } from './parseCsvFileToText'
|
|
3
|
+
export { parseCsvText } from './parseCsvText'
|
|
4
|
+
export { csvFormatSchema } from './schemas'
|
|
5
|
+
export type { CsvFormat } from './types'
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@0xtorch/csv",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Cryptorch CSV extension",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"cryptorch",
|
|
7
|
+
"csv"
|
|
8
|
+
],
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "git@github.com:0xtorch/csv.git"
|
|
12
|
+
},
|
|
13
|
+
"license": "MIT",
|
|
14
|
+
"author": "0xnekoya <nekoya.bc@gmail.com>",
|
|
15
|
+
"sideEffects": false,
|
|
16
|
+
"exports": {
|
|
17
|
+
".": {
|
|
18
|
+
"types": "./_types/index.d.ts",
|
|
19
|
+
"import": "./_esm/index.js",
|
|
20
|
+
"default": "./_cjs/index.js"
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"main": "./_cjs/index.js",
|
|
24
|
+
"module": "./_esm/index.js",
|
|
25
|
+
"types": "./_types/index.d.ts",
|
|
26
|
+
"typings": "./_types/index.d.ts",
|
|
27
|
+
"files": [
|
|
28
|
+
"*",
|
|
29
|
+
"!**/*.tsbuildinfo",
|
|
30
|
+
"!**/*.test.ts",
|
|
31
|
+
"!**/*.test.ts.snap",
|
|
32
|
+
"!**/*.test-d.ts",
|
|
33
|
+
"!**/*.bench.ts",
|
|
34
|
+
"!tsconfig.build.json"
|
|
35
|
+
],
|
|
36
|
+
"dependencies": {
|
|
37
|
+
"@0xtorch/big-decimal": "^0.0.10",
|
|
38
|
+
"@0xtorch/core": "^0.0.18",
|
|
39
|
+
"encoding-japanese": "^2.1.0",
|
|
40
|
+
"papaparse": "^5.4.1",
|
|
41
|
+
"zod": "^3.22.4"
|
|
42
|
+
},
|
|
43
|
+
"peerDependencies": {
|
|
44
|
+
"typescript": "^5.0.0"
|
|
45
|
+
},
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"@types/encoding-japanese": "^2.0.5",
|
|
48
|
+
"@types/papaparse": "^5.3.14"
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { AccountAction, CryptoCurrency, FiatCurrency } from '@0xtorch/core'
|
|
2
|
+
import { formatCsvRows } from './formatCsvRows'
|
|
3
|
+
import { parseCsvFileToText } from './parseCsvFileToText'
|
|
4
|
+
import { parseCsvRowsToAccountActions } from './parseCsvRowsToAccountActions'
|
|
5
|
+
import { parseCsvText } from './parseCsvText'
|
|
6
|
+
import type { CsvFormat } from './types'
|
|
7
|
+
|
|
8
|
+
type ParseCsvFileToAccountActionsParameters = {
|
|
9
|
+
readonly file: File
|
|
10
|
+
readonly format: CsvFormat
|
|
11
|
+
readonly accountId: string
|
|
12
|
+
readonly cryptoCurrencies: readonly CryptoCurrency[]
|
|
13
|
+
readonly fiatCurrencies: readonly FiatCurrency[]
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export const parseCsvFileToAccountActions = async ({
|
|
17
|
+
file,
|
|
18
|
+
format: { service, formatter, parsers, symbolAssetMap },
|
|
19
|
+
accountId,
|
|
20
|
+
cryptoCurrencies,
|
|
21
|
+
fiatCurrencies,
|
|
22
|
+
}: ParseCsvFileToAccountActionsParameters): Promise<
|
|
23
|
+
readonly AccountAction[]
|
|
24
|
+
> => {
|
|
25
|
+
const text = await parseCsvFileToText(file)
|
|
26
|
+
const rows = formatCsvRows({
|
|
27
|
+
rows: parseCsvText(text),
|
|
28
|
+
formatter,
|
|
29
|
+
})
|
|
30
|
+
const actions = parseCsvRowsToAccountActions({
|
|
31
|
+
rows,
|
|
32
|
+
service,
|
|
33
|
+
parsers,
|
|
34
|
+
symbolAssetMap,
|
|
35
|
+
accountId,
|
|
36
|
+
cryptoCurrencies,
|
|
37
|
+
fiatCurrencies,
|
|
38
|
+
})
|
|
39
|
+
return actions
|
|
40
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { convert } from 'encoding-japanese'
|
|
2
|
+
|
|
3
|
+
export const parseCsvFileToText = async (file: File): Promise<string> => {
|
|
4
|
+
const buffers = await file.arrayBuffer()
|
|
5
|
+
const codes = new Uint8Array(buffers)
|
|
6
|
+
const unicodeString = convert(codes, {
|
|
7
|
+
to: 'UNICODE',
|
|
8
|
+
type: 'string',
|
|
9
|
+
})
|
|
10
|
+
return unicodeString
|
|
11
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import type { CryptoCurrency, FiatCurrency, Nft } from '@0xtorch/core'
|
|
2
|
+
import type { z } from 'zod'
|
|
3
|
+
import type { assetComponentSchema } from '../schemas/parser'
|
|
4
|
+
import type { FormattedRow } from '../types'
|
|
5
|
+
import { createNftByNftComponent } from './nft'
|
|
6
|
+
|
|
7
|
+
type CreateAssetByComponentParameters = {
|
|
8
|
+
readonly row: FormattedRow
|
|
9
|
+
readonly service: string
|
|
10
|
+
readonly symbolAssetMap: { [symbol: string]: string } | undefined
|
|
11
|
+
readonly component: z.infer<typeof assetComponentSchema>
|
|
12
|
+
readonly cryptoCurrencies: readonly CryptoCurrency[]
|
|
13
|
+
readonly fiatCurrencies: readonly FiatCurrency[]
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export const createAssetByComponent = ({
|
|
17
|
+
row,
|
|
18
|
+
service,
|
|
19
|
+
symbolAssetMap,
|
|
20
|
+
component,
|
|
21
|
+
cryptoCurrencies,
|
|
22
|
+
fiatCurrencies,
|
|
23
|
+
}: CreateAssetByComponentParameters): CryptoCurrency | FiatCurrency | Nft => {
|
|
24
|
+
switch (component.type) {
|
|
25
|
+
case 'custom': {
|
|
26
|
+
switch (component.assetType) {
|
|
27
|
+
case 'CryptoCurrency': {
|
|
28
|
+
const asset = cryptoCurrencies.find(
|
|
29
|
+
(cryptoCurrency) => cryptoCurrency.id === component.assetId,
|
|
30
|
+
)
|
|
31
|
+
if (asset === undefined) {
|
|
32
|
+
throw new Error(`asset not found: ${component.assetId}`)
|
|
33
|
+
}
|
|
34
|
+
return asset
|
|
35
|
+
}
|
|
36
|
+
case 'FiatCurrency': {
|
|
37
|
+
const asset = fiatCurrencies.find(
|
|
38
|
+
(fiatCurrency) => fiatCurrency.id === component.assetId,
|
|
39
|
+
)
|
|
40
|
+
if (asset === undefined) {
|
|
41
|
+
throw new Error(`asset not found: ${component.assetId}`)
|
|
42
|
+
}
|
|
43
|
+
return asset
|
|
44
|
+
}
|
|
45
|
+
case 'Nft': {
|
|
46
|
+
return {
|
|
47
|
+
type: 'Nft',
|
|
48
|
+
id: component.assetId,
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
throw new Error('Not reachable')
|
|
53
|
+
}
|
|
54
|
+
case 'column': {
|
|
55
|
+
const symbol = row[component.column]
|
|
56
|
+
if (typeof symbol !== 'string') {
|
|
57
|
+
throw new TypeError(
|
|
58
|
+
`symbol needs to be string but got ${typeof symbol}`,
|
|
59
|
+
)
|
|
60
|
+
}
|
|
61
|
+
if (symbolAssetMap !== undefined && symbol in symbolAssetMap) {
|
|
62
|
+
const assetId = symbolAssetMap[symbol]
|
|
63
|
+
const asset = cryptoCurrencies.find(
|
|
64
|
+
(cryptoCurrency) => cryptoCurrency.id === assetId,
|
|
65
|
+
)
|
|
66
|
+
if (asset !== undefined) {
|
|
67
|
+
return asset
|
|
68
|
+
}
|
|
69
|
+
throw new Error(`asset not found: ${assetId}`)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const upperSymbol = symbol.toUpperCase()
|
|
73
|
+
const fiat = fiatCurrencies.find(
|
|
74
|
+
(fiatCurrency) => fiatCurrency.symbol.toUpperCase() === upperSymbol,
|
|
75
|
+
)
|
|
76
|
+
if (fiat !== undefined) {
|
|
77
|
+
return fiat
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const crypto = cryptoCurrencies.find(
|
|
81
|
+
(cryptoCurrency) => cryptoCurrency.symbol.toUpperCase() === upperSymbol,
|
|
82
|
+
)
|
|
83
|
+
if (crypto !== undefined) {
|
|
84
|
+
return crypto
|
|
85
|
+
}
|
|
86
|
+
throw new Error(`asset not found: ${symbol}`)
|
|
87
|
+
}
|
|
88
|
+
case 'nft': {
|
|
89
|
+
return createNftByNftComponent({ row, service, component })
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { z } from 'zod'
|
|
2
|
+
import type { conditionComponentSchema } from '../schemas/parser'
|
|
3
|
+
import type { FormattedRow } from '../types'
|
|
4
|
+
|
|
5
|
+
type MatchConditionParameters = {
|
|
6
|
+
readonly row: FormattedRow
|
|
7
|
+
readonly component: z.infer<typeof conditionComponentSchema>
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const matchCondition = ({
|
|
11
|
+
row,
|
|
12
|
+
component,
|
|
13
|
+
}: MatchConditionParameters): boolean => {
|
|
14
|
+
const { column, pattern } = component
|
|
15
|
+
const value = row[column]
|
|
16
|
+
if (typeof pattern === 'string' || typeof pattern === 'number') {
|
|
17
|
+
return value === pattern
|
|
18
|
+
}
|
|
19
|
+
switch (pattern.type) {
|
|
20
|
+
case 'defined': {
|
|
21
|
+
return value !== undefined
|
|
22
|
+
}
|
|
23
|
+
case 'undefined': {
|
|
24
|
+
return value === undefined
|
|
25
|
+
}
|
|
26
|
+
case 'in': {
|
|
27
|
+
if (value === undefined || typeof value === 'object') {
|
|
28
|
+
return false
|
|
29
|
+
}
|
|
30
|
+
return pattern.values.includes(value)
|
|
31
|
+
}
|
|
32
|
+
case 'not-in': {
|
|
33
|
+
if (value === undefined || typeof value === 'object') {
|
|
34
|
+
return false
|
|
35
|
+
}
|
|
36
|
+
return !pattern.values.includes(value)
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { parseCsvRowToNormalAction } from './parseCsvRowToNormalAction'
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { Nft } from '@0xtorch/core'
|
|
2
|
+
import type { z } from 'zod'
|
|
3
|
+
import type { nftComponentSchema } from '../schemas/parser'
|
|
4
|
+
import type { FormattedRow } from '../types'
|
|
5
|
+
import { createTextByComponent } from './text'
|
|
6
|
+
|
|
7
|
+
type CreateNftByNftComponentParameters = {
|
|
8
|
+
readonly row: FormattedRow
|
|
9
|
+
readonly service: string
|
|
10
|
+
readonly component: z.infer<typeof nftComponentSchema>
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const createNftByNftComponent = ({
|
|
14
|
+
row,
|
|
15
|
+
service,
|
|
16
|
+
component,
|
|
17
|
+
}: CreateNftByNftComponentParameters): Nft => {
|
|
18
|
+
const id = component.id
|
|
19
|
+
.map((idComponent) =>
|
|
20
|
+
createTextByComponent({ row, service, component: idComponent }),
|
|
21
|
+
)
|
|
22
|
+
.join('')
|
|
23
|
+
return {
|
|
24
|
+
type: 'Nft',
|
|
25
|
+
id,
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
BaseNormalAction,
|
|
3
|
+
CryptoCurrency,
|
|
4
|
+
FiatCurrency,
|
|
5
|
+
NormalAction,
|
|
6
|
+
} from '@0xtorch/core'
|
|
7
|
+
import { parseBaseNormalActionToNormalAction } from '@0xtorch/core'
|
|
8
|
+
import type { FormattedRow, Parser } from '../types'
|
|
9
|
+
import { matchCondition } from './condition'
|
|
10
|
+
import { createNftByNftComponent } from './nft'
|
|
11
|
+
import { createTextByComponent } from './text'
|
|
12
|
+
import { createTimestampByRow } from './timestamp'
|
|
13
|
+
import { createTransferByComponent } from './transfer'
|
|
14
|
+
|
|
15
|
+
type ParseCsvRowToNormalActionParameters = {
|
|
16
|
+
readonly row: FormattedRow
|
|
17
|
+
readonly service: string
|
|
18
|
+
readonly parsers: readonly Parser[]
|
|
19
|
+
readonly symbolAssetMap: { [symbol: string]: string } | undefined
|
|
20
|
+
readonly accountId: string
|
|
21
|
+
readonly cryptoCurrencies: readonly CryptoCurrency[]
|
|
22
|
+
readonly fiatCurrencies: readonly FiatCurrency[]
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
type ParseCsvRowToNormalActionReturnTypes =
|
|
26
|
+
| {
|
|
27
|
+
readonly action: NormalAction
|
|
28
|
+
readonly source: string
|
|
29
|
+
}
|
|
30
|
+
| undefined
|
|
31
|
+
|
|
32
|
+
export const parseCsvRowToNormalAction = ({
|
|
33
|
+
row,
|
|
34
|
+
service,
|
|
35
|
+
parsers,
|
|
36
|
+
symbolAssetMap,
|
|
37
|
+
accountId,
|
|
38
|
+
cryptoCurrencies,
|
|
39
|
+
fiatCurrencies,
|
|
40
|
+
}: ParseCsvRowToNormalActionParameters): ParseCsvRowToNormalActionReturnTypes => {
|
|
41
|
+
for (const parser of parsers) {
|
|
42
|
+
try {
|
|
43
|
+
const action = parseCsvRowToNormalActionByParser({
|
|
44
|
+
row,
|
|
45
|
+
service,
|
|
46
|
+
parser,
|
|
47
|
+
symbolAssetMap,
|
|
48
|
+
accountId,
|
|
49
|
+
cryptoCurrencies,
|
|
50
|
+
fiatCurrencies,
|
|
51
|
+
})
|
|
52
|
+
if (action !== undefined) {
|
|
53
|
+
return action
|
|
54
|
+
}
|
|
55
|
+
} catch (error) {
|
|
56
|
+
// TODO 意図しないエラーは別途記録できるようにしたい
|
|
57
|
+
console.debug(error)
|
|
58
|
+
continue
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return undefined
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
type ParseCsvRowToNormalActionByParserParameters = {
|
|
65
|
+
readonly row: FormattedRow
|
|
66
|
+
readonly service: string
|
|
67
|
+
readonly parser: Parser
|
|
68
|
+
readonly symbolAssetMap: { [symbol: string]: string } | undefined
|
|
69
|
+
readonly accountId: string
|
|
70
|
+
readonly cryptoCurrencies: readonly CryptoCurrency[]
|
|
71
|
+
readonly fiatCurrencies: readonly FiatCurrency[]
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const parseCsvRowToNormalActionByParser = ({
|
|
75
|
+
row,
|
|
76
|
+
service,
|
|
77
|
+
parser,
|
|
78
|
+
symbolAssetMap,
|
|
79
|
+
accountId,
|
|
80
|
+
cryptoCurrencies,
|
|
81
|
+
fiatCurrencies,
|
|
82
|
+
}: ParseCsvRowToNormalActionByParserParameters): ParseCsvRowToNormalActionReturnTypes => {
|
|
83
|
+
// 合致しない condition がある場合は undefined を返す
|
|
84
|
+
for (const condition of parser.conditions) {
|
|
85
|
+
if (!matchCondition({ row, component: condition })) {
|
|
86
|
+
return undefined
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const baseAction: BaseNormalAction = {
|
|
91
|
+
action: parser.action,
|
|
92
|
+
evidence: 'system-rule',
|
|
93
|
+
timestamp: createTimestampByRow({ row, column: parser.timestamp }),
|
|
94
|
+
comment:
|
|
95
|
+
parser.comment === undefined
|
|
96
|
+
? undefined
|
|
97
|
+
: parser.comment
|
|
98
|
+
.map((component) =>
|
|
99
|
+
createTextByComponent({ row, service, component }),
|
|
100
|
+
)
|
|
101
|
+
.join(''),
|
|
102
|
+
app: undefined,
|
|
103
|
+
transfers: parser.transfers.map((component) =>
|
|
104
|
+
createTransferByComponent({
|
|
105
|
+
row,
|
|
106
|
+
service,
|
|
107
|
+
symbolAssetMap,
|
|
108
|
+
component,
|
|
109
|
+
accountId,
|
|
110
|
+
cryptoCurrencies,
|
|
111
|
+
fiatCurrencies,
|
|
112
|
+
}),
|
|
113
|
+
),
|
|
114
|
+
crossId:
|
|
115
|
+
parser.crossId === undefined
|
|
116
|
+
? undefined
|
|
117
|
+
: parser.crossId
|
|
118
|
+
.map((component) =>
|
|
119
|
+
createTextByComponent({ row, service, component }),
|
|
120
|
+
)
|
|
121
|
+
.join(''),
|
|
122
|
+
crossType: parser.crossType,
|
|
123
|
+
loanId:
|
|
124
|
+
parser.loanId === undefined
|
|
125
|
+
? undefined
|
|
126
|
+
: parser.loanId
|
|
127
|
+
.map((component) =>
|
|
128
|
+
createTextByComponent({ row, service, component }),
|
|
129
|
+
)
|
|
130
|
+
.join(''),
|
|
131
|
+
target:
|
|
132
|
+
parser.target === undefined
|
|
133
|
+
? undefined
|
|
134
|
+
: createNftByNftComponent({ row, service, component: parser.target }),
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const action = parseBaseNormalActionToNormalAction(baseAction)
|
|
138
|
+
const source = parser.source
|
|
139
|
+
.map((component) => createTextByComponent({ row, service, component }))
|
|
140
|
+
.join('')
|
|
141
|
+
|
|
142
|
+
return {
|
|
143
|
+
action,
|
|
144
|
+
source,
|
|
145
|
+
}
|
|
146
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { toStringBigDecimal } from '@0xtorch/big-decimal'
|
|
2
|
+
import type { z } from 'zod'
|
|
3
|
+
import type { textComponentSchema } from '../schemas/parser'
|
|
4
|
+
import type { FormattedRow } from '../types'
|
|
5
|
+
|
|
6
|
+
type CreateTextByComponentParameters = {
|
|
7
|
+
readonly row: FormattedRow
|
|
8
|
+
readonly service: string
|
|
9
|
+
readonly component: z.infer<typeof textComponentSchema>
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const createTextByComponent = ({
|
|
13
|
+
row,
|
|
14
|
+
service,
|
|
15
|
+
component,
|
|
16
|
+
}: CreateTextByComponentParameters): string => {
|
|
17
|
+
if (typeof component === 'string') {
|
|
18
|
+
return component
|
|
19
|
+
}
|
|
20
|
+
switch (component.type) {
|
|
21
|
+
case 'service': {
|
|
22
|
+
return service
|
|
23
|
+
}
|
|
24
|
+
case 'column': {
|
|
25
|
+
const value = row[component.column]
|
|
26
|
+
if (value === undefined) {
|
|
27
|
+
return ''
|
|
28
|
+
} else if (typeof value === 'string') {
|
|
29
|
+
return value
|
|
30
|
+
} else if (typeof value === 'number') {
|
|
31
|
+
return value.toString()
|
|
32
|
+
} else {
|
|
33
|
+
return toStringBigDecimal(value)
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { FormattedRow } from '../types'
|
|
2
|
+
|
|
3
|
+
type CreateTimestampByRowParameters = {
|
|
4
|
+
readonly row: FormattedRow
|
|
5
|
+
readonly column: string
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export const createTimestampByRow = ({
|
|
9
|
+
row,
|
|
10
|
+
column,
|
|
11
|
+
}: CreateTimestampByRowParameters): number => {
|
|
12
|
+
const timestamp = row[column]
|
|
13
|
+
if (typeof timestamp !== 'number') {
|
|
14
|
+
throw new TypeError(
|
|
15
|
+
`timestamp needs to be number but got ${typeof timestamp}`,
|
|
16
|
+
)
|
|
17
|
+
}
|
|
18
|
+
return timestamp
|
|
19
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { absoluteValue } from '@0xtorch/big-decimal'
|
|
2
|
+
import type { CryptoCurrency, FiatCurrency, Transfer } from '@0xtorch/core'
|
|
3
|
+
import type { z } from 'zod'
|
|
4
|
+
import type { transferComponentSchema } from '../schemas/parser'
|
|
5
|
+
import type { FormattedRow } from '../types'
|
|
6
|
+
import { createAssetByComponent } from './asset'
|
|
7
|
+
|
|
8
|
+
type CreateTransferByComponentParameters = {
|
|
9
|
+
readonly row: FormattedRow
|
|
10
|
+
readonly service: string
|
|
11
|
+
readonly symbolAssetMap: { [symbol: string]: string } | undefined
|
|
12
|
+
readonly component: z.infer<typeof transferComponentSchema>
|
|
13
|
+
readonly accountId: string
|
|
14
|
+
readonly cryptoCurrencies: readonly CryptoCurrency[]
|
|
15
|
+
readonly fiatCurrencies: readonly FiatCurrency[]
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export const createTransferByComponent = ({
|
|
19
|
+
row,
|
|
20
|
+
service,
|
|
21
|
+
symbolAssetMap,
|
|
22
|
+
component,
|
|
23
|
+
accountId,
|
|
24
|
+
cryptoCurrencies,
|
|
25
|
+
fiatCurrencies,
|
|
26
|
+
}: CreateTransferByComponentParameters): Transfer => {
|
|
27
|
+
const {
|
|
28
|
+
direction,
|
|
29
|
+
asset: assetComponent,
|
|
30
|
+
amount: amountComponent,
|
|
31
|
+
} = component
|
|
32
|
+
|
|
33
|
+
const amount = row[amountComponent]
|
|
34
|
+
if (typeof amount !== 'object') {
|
|
35
|
+
throw new TypeError(
|
|
36
|
+
`amount needs to be BigDecimal but got ${typeof amount}`,
|
|
37
|
+
)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return {
|
|
41
|
+
from: direction === 'in' ? undefined : accountId,
|
|
42
|
+
to: direction === 'in' ? accountId : undefined,
|
|
43
|
+
asset: createAssetByComponent({
|
|
44
|
+
row,
|
|
45
|
+
service,
|
|
46
|
+
symbolAssetMap,
|
|
47
|
+
component: assetComponent,
|
|
48
|
+
cryptoCurrencies,
|
|
49
|
+
fiatCurrencies,
|
|
50
|
+
}),
|
|
51
|
+
amount: absoluteValue(amount),
|
|
52
|
+
price: undefined,
|
|
53
|
+
direction,
|
|
54
|
+
}
|
|
55
|
+
}
|