@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.
Files changed (147) hide show
  1. package/.DS_Store +0 -0
  2. package/_cjs/formatCsvRows.js +67 -0
  3. package/_cjs/formatCsvRows.js.map +1 -0
  4. package/_cjs/index.js +12 -0
  5. package/_cjs/index.js.map +1 -0
  6. package/_cjs/package.json +1 -0
  7. package/_cjs/parseCsvFileToAccountActions.js +26 -0
  8. package/_cjs/parseCsvFileToAccountActions.js.map +1 -0
  9. package/_cjs/parseCsvFileToText.js +15 -0
  10. package/_cjs/parseCsvFileToText.js.map +1 -0
  11. package/_cjs/parseCsvRowToNormalAction/asset.js +62 -0
  12. package/_cjs/parseCsvRowToNormalAction/asset.js.map +1 -0
  13. package/_cjs/parseCsvRowToNormalAction/condition.js +32 -0
  14. package/_cjs/parseCsvRowToNormalAction/condition.js.map +1 -0
  15. package/_cjs/parseCsvRowToNormalAction/index.js +6 -0
  16. package/_cjs/parseCsvRowToNormalAction/index.js.map +1 -0
  17. package/_cjs/parseCsvRowToNormalAction/nft.js +15 -0
  18. package/_cjs/parseCsvRowToNormalAction/nft.js.map +1 -0
  19. package/_cjs/parseCsvRowToNormalAction/parseCsvRowToNormalAction.js +83 -0
  20. package/_cjs/parseCsvRowToNormalAction/parseCsvRowToNormalAction.js.map +1 -0
  21. package/_cjs/parseCsvRowToNormalAction/text.js +31 -0
  22. package/_cjs/parseCsvRowToNormalAction/text.js.map +1 -0
  23. package/_cjs/parseCsvRowToNormalAction/timestamp.js +12 -0
  24. package/_cjs/parseCsvRowToNormalAction/timestamp.js.map +1 -0
  25. package/_cjs/parseCsvRowToNormalAction/transfer.js +29 -0
  26. package/_cjs/parseCsvRowToNormalAction/transfer.js.map +1 -0
  27. package/_cjs/parseCsvRowsToAccountActions.js +49 -0
  28. package/_cjs/parseCsvRowsToAccountActions.js.map +1 -0
  29. package/_cjs/parseCsvText.js +15 -0
  30. package/_cjs/parseCsvText.js.map +1 -0
  31. package/_cjs/schemas/formatter.js +15 -0
  32. package/_cjs/schemas/formatter.js.map +1 -0
  33. package/_cjs/schemas/formatterTypes.js +37 -0
  34. package/_cjs/schemas/formatterTypes.js.map +1 -0
  35. package/_cjs/schemas/index.js +6 -0
  36. package/_cjs/schemas/index.js.map +1 -0
  37. package/_cjs/schemas/parser.js +80 -0
  38. package/_cjs/schemas/parser.js.map +1 -0
  39. package/_cjs/schemas/schemas.js +14 -0
  40. package/_cjs/schemas/schemas.js.map +1 -0
  41. package/_cjs/types.js +3 -0
  42. package/_cjs/types.js.map +1 -0
  43. package/_esm/formatCsvRows.js +67 -0
  44. package/_esm/formatCsvRows.js.map +1 -0
  45. package/_esm/index.js +5 -0
  46. package/_esm/index.js.map +1 -0
  47. package/_esm/package.json +1 -0
  48. package/_esm/parseCsvFileToAccountActions.js +22 -0
  49. package/_esm/parseCsvFileToAccountActions.js.map +1 -0
  50. package/_esm/parseCsvFileToText.js +11 -0
  51. package/_esm/parseCsvFileToText.js.map +1 -0
  52. package/_esm/parseCsvRowToNormalAction/asset.js +58 -0
  53. package/_esm/parseCsvRowToNormalAction/asset.js.map +1 -0
  54. package/_esm/parseCsvRowToNormalAction/condition.js +28 -0
  55. package/_esm/parseCsvRowToNormalAction/condition.js.map +1 -0
  56. package/_esm/parseCsvRowToNormalAction/index.js +2 -0
  57. package/_esm/parseCsvRowToNormalAction/index.js.map +1 -0
  58. package/_esm/parseCsvRowToNormalAction/nft.js +11 -0
  59. package/_esm/parseCsvRowToNormalAction/nft.js.map +1 -0
  60. package/_esm/parseCsvRowToNormalAction/parseCsvRowToNormalAction.js +81 -0
  61. package/_esm/parseCsvRowToNormalAction/parseCsvRowToNormalAction.js.map +1 -0
  62. package/_esm/parseCsvRowToNormalAction/text.js +27 -0
  63. package/_esm/parseCsvRowToNormalAction/text.js.map +1 -0
  64. package/_esm/parseCsvRowToNormalAction/timestamp.js +8 -0
  65. package/_esm/parseCsvRowToNormalAction/timestamp.js.map +1 -0
  66. package/_esm/parseCsvRowToNormalAction/transfer.js +25 -0
  67. package/_esm/parseCsvRowToNormalAction/transfer.js.map +1 -0
  68. package/_esm/parseCsvRowsToAccountActions.js +47 -0
  69. package/_esm/parseCsvRowsToAccountActions.js.map +1 -0
  70. package/_esm/parseCsvText.js +11 -0
  71. package/_esm/parseCsvText.js.map +1 -0
  72. package/_esm/schemas/formatter.js +12 -0
  73. package/_esm/schemas/formatter.js.map +1 -0
  74. package/_esm/schemas/formatterTypes.js +35 -0
  75. package/_esm/schemas/formatterTypes.js.map +1 -0
  76. package/_esm/schemas/index.js +2 -0
  77. package/_esm/schemas/index.js.map +1 -0
  78. package/_esm/schemas/parser.js +100 -0
  79. package/_esm/schemas/parser.js.map +1 -0
  80. package/_esm/schemas/schemas.js +11 -0
  81. package/_esm/schemas/schemas.js.map +1 -0
  82. package/_esm/types.js +2 -0
  83. package/_esm/types.js.map +1 -0
  84. package/_types/formatCsvRows.d.ts +11 -0
  85. package/_types/formatCsvRows.d.ts.map +1 -0
  86. package/_types/index.d.ts +6 -0
  87. package/_types/index.d.ts.map +1 -0
  88. package/_types/parseCsvFileToAccountActions.d.ts +12 -0
  89. package/_types/parseCsvFileToAccountActions.d.ts.map +1 -0
  90. package/_types/parseCsvFileToText.d.ts +2 -0
  91. package/_types/parseCsvFileToText.d.ts.map +1 -0
  92. package/_types/parseCsvRowToNormalAction/asset.d.ts +17 -0
  93. package/_types/parseCsvRowToNormalAction/asset.d.ts.map +1 -0
  94. package/_types/parseCsvRowToNormalAction/condition.d.ts +10 -0
  95. package/_types/parseCsvRowToNormalAction/condition.d.ts.map +1 -0
  96. package/_types/parseCsvRowToNormalAction/index.d.ts +2 -0
  97. package/_types/parseCsvRowToNormalAction/index.d.ts.map +1 -0
  98. package/_types/parseCsvRowToNormalAction/nft.d.ts +12 -0
  99. package/_types/parseCsvRowToNormalAction/nft.d.ts.map +1 -0
  100. package/_types/parseCsvRowToNormalAction/parseCsvRowToNormalAction.d.ts +20 -0
  101. package/_types/parseCsvRowToNormalAction/parseCsvRowToNormalAction.d.ts.map +1 -0
  102. package/_types/parseCsvRowToNormalAction/text.d.ts +11 -0
  103. package/_types/parseCsvRowToNormalAction/text.d.ts.map +1 -0
  104. package/_types/parseCsvRowToNormalAction/timestamp.d.ts +8 -0
  105. package/_types/parseCsvRowToNormalAction/timestamp.d.ts.map +1 -0
  106. package/_types/parseCsvRowToNormalAction/transfer.d.ts +18 -0
  107. package/_types/parseCsvRowToNormalAction/transfer.d.ts.map +1 -0
  108. package/_types/parseCsvRowsToAccountActions.d.ts +16 -0
  109. package/_types/parseCsvRowsToAccountActions.d.ts.map +1 -0
  110. package/_types/parseCsvText.d.ts +4 -0
  111. package/_types/parseCsvText.d.ts.map +1 -0
  112. package/_types/schemas/formatter.d.ts +4 -0
  113. package/_types/schemas/formatter.d.ts.map +1 -0
  114. package/_types/schemas/formatterTypes.d.ts +10 -0
  115. package/_types/schemas/formatterTypes.d.ts.map +1 -0
  116. package/_types/schemas/index.d.ts +2 -0
  117. package/_types/schemas/index.d.ts.map +1 -0
  118. package/_types/schemas/parser.d.ts +1505 -0
  119. package/_types/schemas/parser.d.ts.map +1 -0
  120. package/_types/schemas/schemas.d.ts +806 -0
  121. package/_types/schemas/schemas.d.ts.map +1 -0
  122. package/_types/types.d.ts +13 -0
  123. package/_types/types.d.ts.map +1 -0
  124. package/formatCsvRows.ts +97 -0
  125. package/index.ts +5 -0
  126. package/package.json +50 -0
  127. package/parseCsvFileToAccountActions.ts +40 -0
  128. package/parseCsvFileToText.ts +11 -0
  129. package/parseCsvRowToNormalAction/asset.ts +92 -0
  130. package/parseCsvRowToNormalAction/condition.ts +39 -0
  131. package/parseCsvRowToNormalAction/index.ts +1 -0
  132. package/parseCsvRowToNormalAction/nft.ts +27 -0
  133. package/parseCsvRowToNormalAction/parseCsvRowToNormalAction.ts +146 -0
  134. package/parseCsvRowToNormalAction/text.ts +37 -0
  135. package/parseCsvRowToNormalAction/timestamp.ts +19 -0
  136. package/parseCsvRowToNormalAction/transfer.ts +55 -0
  137. package/parseCsvRowsToAccountActions.ts +67 -0
  138. package/parseCsvText.ts +14 -0
  139. package/schemas/formatter.ts +13 -0
  140. package/schemas/formatterTypes.ts +44 -0
  141. package/schemas/index.ts +1 -0
  142. package/schemas/parser.ts +110 -0
  143. package/schemas/schemas.ts +11 -0
  144. package/tests/assets.ts +28 -0
  145. package/tests/coincheck-standard.csv +17 -0
  146. package/tests/coincheck.ts +137 -0
  147. 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"}
@@ -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
+ }