chore(medusa-core-utils): Migrate to TS (#2670)

This commit is contained in:
Adrien de Peretti
2022-12-05 10:21:04 +01:00
committed by GitHub
parent 1dc816039c
commit 1b21af87ab
23 changed files with 254 additions and 233 deletions
+6
View File
@@ -0,0 +1,6 @@
---
"medusa-core-utils": patch
"@medusajs/medusa": patch
---
chore(medusa-core-utils): Migrate to TS
-9
View File
@@ -1,9 +0,0 @@
{
"plugins": ["@babel/plugin-proposal-class-properties"],
"presets": ["@babel/preset-env", "@babel/preset-typescript"],
"env": {
"test": {
"plugins": ["@babel/plugin-transform-runtime"]
}
}
}
+13
View File
@@ -0,0 +1,13 @@
module.exports = {
globals: {
"ts-jest": {
tsConfig: "tsconfig.spec.json",
isolatedModules: false,
},
},
transform: {
"^.+\\.[jt]s?$": "ts-jest",
},
testEnvironment: `node`,
moduleFileExtensions: [`js`, `jsx`, `ts`, `tsx`, `json`],
}
+2 -9
View File
@@ -12,23 +12,16 @@
"test": "jest",
"build": "tsc --build",
"prepare": "cross-env NODE_ENV=production yarn run build",
"watch": "babel -w src --out-dir dist/ --ignore **/__tests__"
"watch": "tsc --watch"
},
"author": "Sebastian Rindom",
"license": "MIT",
"devDependencies": {
"@babel/cli": "^7.13.0",
"@babel/core": "^7.13.8",
"@babel/plugin-proposal-class-properties": "^7.13.0",
"@babel/plugin-transform-classes": "^7.9.5",
"@babel/plugin-transform-runtime": "^7.7.6",
"@babel/preset-env": "^7.13.9",
"@babel/preset-typescript": "^7.16.0",
"@babel/runtime": "^7.13.9",
"class-transformer": "^0.5.1",
"class-validator": "^0.13.1",
"cross-env": "^5.2.1",
"jest": "^25.5.2",
"ts-jest": "^25.5.1",
"typescript": "^4.4.4"
},
"dependencies": {
@@ -1,17 +0,0 @@
import _ from "lodash"
function compareObjectsByProp(object1, object2, prop) {
if (Array.isArray(object1[prop])) {
object2[prop] = object2[prop].map(({ _id, ...rest }) => rest)
return (
_.differenceWith(object1[prop], object2[prop], _.isEqual).length === 0
)
} else if (typeof object1[prop] === "object") {
delete object2[prop]._id
return _.isEqual(object1[prop], object2[prop])
} else {
return object1[prop] === object2[prop]
}
}
export default compareObjectsByProp
@@ -1,6 +1,6 @@
import zeroDecimalCurrencies from "./zero-decimal-currencies"
const computerizeAmount = (amount, currency) => {
const computerizeAmount = (amount: number, currency: string): number => {
let divisor = 100
if (zeroDecimalCurrencies.includes(currency.toLowerCase())) {
@@ -1,4 +1,11 @@
export const countries = [
type Country = {
alpha2: string
name: string
alpha3: string
numeric: string
}
export const countries: Country[] = [
{ alpha2: "AF", name: "Afghanistan", alpha3: "AFG", numeric: "004" },
{ alpha2: "AL", name: "Albania", alpha3: "ALB", numeric: "008" },
{ alpha2: "DZ", name: "Algeria", alpha3: "DZA", numeric: "012" },
@@ -402,27 +409,17 @@ export const countries = [
{ alpha2: "AX", name: "Åland Islands", alpha3: "ALA", numeric: "248" },
]
export function isoCountryLookup(country) {
export function isoCountryLookup(country: string): string {
const normalizedCountry = country.toUpperCase()
let isoRecord = countries.find(record => {
return record.name === normalizedCountry
let isoRecord = countries.find((record) => {
return (
record.name.toUpperCase() === normalizedCountry ||
record.alpha2.toUpperCase() === normalizedCountry ||
record.alpha3.toUpperCase() === normalizedCountry
)
})
// Try alpha2 instead
if (!isoRecord) {
isoRecord = countries.find(record => {
return record.alpha2 === normalizedCountry
})
}
// Try alpha3
if (!isoRecord) {
isoRecord = countries.find(record => {
return record.alpha3 === normalizedCountry
})
}
if (!isoRecord) {
throw new Error("Invalid country name")
}
@@ -1,12 +1,12 @@
import Module from "module"
import path from "path"
const fallback = filename => {
const fallback = (filename: string) => {
const mod = new Module(filename)
mod.filename = filename
mod.paths = Module._nodeModulePaths(path.dirname(filename))
mod._compile(`module.exports = require;`, filename)
mod.paths = (Module as any)._nodeModulePaths(path.dirname(filename))
;(mod as any)._compile(`module.exports = require;`, filename)
return mod.exports
}
@@ -1,4 +1,4 @@
import path from "path"
import { join } from "path"
/**
* Attempts to resolve the config file in a given root directory.
@@ -6,8 +6,11 @@ import path from "path"
* @param {string} configName - the name of the config file.
* @return {object} an object containing the config module and its path as well as an error property if the config couldn't be loaded.
*/
function getConfigFile(rootDir, configName) {
const configPath = path.join(rootDir, configName)
function getConfigFile<TConfig = unknown>(
rootDir: string,
configName: string
): { configModule: TConfig; configFilePath: string } | { error: any } {
const configPath = join(rootDir, configName)
let configFilePath = ``
let configModule
@@ -1,6 +1,6 @@
import path from "path"
export const getMedusaVersion = () => {
export const getMedusaVersion = (): string => {
try {
return require(path.join(
process.cwd(),
@@ -1,6 +1,6 @@
import zeroDecimalCurrencies from "./zero-decimal-currencies"
const humanizeAmount = (amount, currency) => {
const humanizeAmount = (amount: number, currency: string): number => {
let divisor = 100
if (zeroDecimalCurrencies.includes(currency.toLowerCase())) {
@@ -1,4 +1,3 @@
export { default as compareObjectsByProp } from "./compare-objects"
export { countries, isoCountryLookup } from "./countries"
export { default as createRequireFromPath } from "./create-require-from-path"
export { default as MedusaError } from "./errors"
@@ -1,22 +0,0 @@
/**
* Takes an object and a list of fields to tranform in that object. If the field
* exists on the object and its value is a string it will append `_id` to the
* field name. This is used when allowing API calls to hold either ID or object
* values in the payload. The method returns a new object with the
* transformation.
* @param {Object} obj - the object to transform
* @param {Array<String>} fields - the fields to apply transformation to
* @returns {Object} the transformed object
*/
export const transformIdableFields = (obj, fields) => {
const ret = { ...obj }
for (const key of fields) {
if (key in obj && typeof ret[key] === "string") {
ret[`${key}_id`] = ret[key]
delete ret[key]
}
}
return ret
}
@@ -0,0 +1,50 @@
type ComputePropertyNames<
T,
TKey extends keyof T & string,
TFields extends (keyof T | string)[] = (keyof T | string)[]
> = TKey extends TFields[number]
? T[TKey] extends string
? `${TKey}_id`
: TKey
: TKey
/**
* Takes an object and a list of fields to tranform in that object. If the field
* exists on the object and its value is a string it will append `_id` to the
* field name. This is used when allowing API calls to hold either ID or object
* values in the payload. The method returns a new object with the
* transformation.
* @param obj - the object to transform
* @param fields - the fields to apply transformation to
* @returns the transformed object
*
* @example
* ```ts
* const obj = { test: "test", toto: 1, tata: Symbol("tata") }
* const out = transformIdableFields(obj, ["test"]) // out: { test_id: string, toto: number, tata: symbol }
* ```
*/
export const transformIdableFields = <
T = Record<string, unknown>,
TFields extends (keyof T | string)[] = (keyof T | string)[],
TOutput = {
[P in ComputePropertyNames<T, keyof T & string, TFields>]: P extends keyof T
? T[P]
: string
}
>(
obj: T,
fields: TFields
): TOutput => {
const ret = { ...obj }
for (let key of fields) {
key = key as string
if (key in obj && typeof obj[key] === "string") {
ret[`${key.toString()}_id`] = obj[key]
delete ret[key]
}
}
return ret as unknown as TOutput
}
-129
View File
@@ -1,129 +0,0 @@
import Joi from "joi"
Joi.objectId = require("joi-objectid")(Joi)
// if address is a string, we assume that it is an id
Joi.address = () => {
return Joi.alternatives().try(
Joi.string(),
Joi.object().keys({
first_name: Joi.string().required(),
last_name: Joi.string().required(),
company: Joi.string().optional(),
address_1: Joi.string().required(),
address_2: Joi.string()
.allow(null, "")
.optional(),
city: Joi.string().required(),
country_code: Joi.string().required(),
province: Joi.string()
.allow(null, "")
.optional(),
postal_code: Joi.string().required(),
phone: Joi.string().optional(),
metadata: Joi.object()
.allow(null, {})
.optional(),
})
)
}
Joi.dateFilter = () => {
return Joi.object({
lt: Joi.alternatives(Joi.date().timestamp("unix"), Joi.date()),
gt: Joi.alternatives(Joi.date().timestamp("unix"), Joi.date()),
gte: Joi.alternatives(Joi.date().timestamp("unix"), Joi.date()),
lte: Joi.alternatives(Joi.date().timestamp("unix"), Joi.date()),
})
}
Joi.orderFilter = () => {
return Joi.object().keys({
id: Joi.string(),
q: Joi.string(),
status: Joi.array()
.items(
Joi.string().valid(
"pending",
"completed",
"archived",
"canceled",
"requires_action"
)
)
.single(),
fulfillment_status: Joi.array()
.items(
Joi.string().valid(
"not_fulfilled",
"fulfilled",
"partially_fulfilled",
"shipped",
"partially_shipped",
"canceled",
"returned",
"partially_returned",
"requires_action"
)
)
.single(),
payment_status: Joi.array()
.items(
Joi.string().valid(
"captured",
"awaiting",
"not_paid",
"refunded",
"partially_refunded",
"canceled",
"requires_action"
)
)
.single(),
display_id: Joi.string(),
cart_id: Joi.string(),
offset: Joi.string(),
limit: Joi.string(),
expand: Joi.string(),
fields: Joi.string(),
customer_id: Joi.string(),
email: Joi.string(),
region_id: Joi.string(),
currency_code: Joi.string(),
tax_rate: Joi.string(),
canceled_at: Joi.dateFilter(),
created_at: Joi.dateFilter(),
updated_at: Joi.dateFilter(),
})
}
Joi.productFilter = () => {
return Joi.object().keys({
id: Joi.string(),
q: Joi.string().allow(null, ""),
status: Joi.array()
.items(Joi.string().valid("proposed", "draft", "published", "rejected"))
.single(),
collection_id: Joi.array()
.items(Joi.string())
.single(),
tags: Joi.array()
.items(Joi.string())
.single(),
title: Joi.string(),
description: Joi.string(),
handle: Joi.string(),
is_giftcard: Joi.string(),
type: Joi.string(),
offset: Joi.string(),
limit: Joi.string(),
expand: Joi.string(),
fields: Joi.string(),
order: Joi.string().optional(),
created_at: Joi.dateFilter(),
updated_at: Joi.dateFilter(),
deleted_at: Joi.dateFilter(),
})
}
export default Joi
+128
View File
@@ -0,0 +1,128 @@
import { default as Joi } from "joi"
const dateFilter = () => {
return Joi.object({
lt: Joi.alternatives(Joi.date().timestamp("unix"), Joi.date()),
gt: Joi.alternatives(Joi.date().timestamp("unix"), Joi.date()),
gte: Joi.alternatives(Joi.date().timestamp("unix"), Joi.date()),
lte: Joi.alternatives(Joi.date().timestamp("unix"), Joi.date()),
})
}
Object.assign(Joi, {
objectId: require("joi-objectid")(Joi),
address: () => {
return Joi.alternatives().try(
Joi.string(),
Joi.object().keys({
first_name: Joi.string().required(),
last_name: Joi.string().required(),
company: Joi.string().optional(),
address_1: Joi.string().required(),
address_2: Joi.string().allow(null, "").optional(),
city: Joi.string().required(),
country_code: Joi.string().required(),
province: Joi.string().allow(null, "").optional(),
postal_code: Joi.string().required(),
phone: Joi.string().optional(),
metadata: Joi.object().allow(null, {}).optional(),
})
)
},
dateFilter,
orderFilter: () => {
return Joi.object().keys({
id: Joi.string(),
q: Joi.string(),
status: Joi.array()
.items(
Joi.string().valid(
"pending",
"completed",
"archived",
"canceled",
"requires_action"
)
)
.single(),
fulfillment_status: Joi.array()
.items(
Joi.string().valid(
"not_fulfilled",
"fulfilled",
"partially_fulfilled",
"shipped",
"partially_shipped",
"canceled",
"returned",
"partially_returned",
"requires_action"
)
)
.single(),
payment_status: Joi.array()
.items(
Joi.string().valid(
"captured",
"awaiting",
"not_paid",
"refunded",
"partially_refunded",
"canceled",
"requires_action"
)
)
.single(),
display_id: Joi.string(),
cart_id: Joi.string(),
offset: Joi.string(),
limit: Joi.string(),
expand: Joi.string(),
fields: Joi.string(),
customer_id: Joi.string(),
email: Joi.string(),
region_id: Joi.string(),
currency_code: Joi.string(),
tax_rate: Joi.string(),
canceled_at: dateFilter(),
created_at: dateFilter(),
updated_at: dateFilter(),
})
},
productFilter: () => {
return Joi.object().keys({
id: Joi.string(),
q: Joi.string().allow(null, ""),
status: Joi.array()
.items(Joi.string().valid("proposed", "draft", "published", "rejected"))
.single(),
collection_id: Joi.array().items(Joi.string()).single(),
tags: Joi.array().items(Joi.string()).single(),
title: Joi.string(),
description: Joi.string(),
handle: Joi.string(),
is_giftcard: Joi.string(),
type: Joi.string(),
offset: Joi.string(),
limit: Joi.string(),
expand: Joi.string(),
fields: Joi.string(),
order: Joi.string().optional(),
created_at: dateFilter(),
updated_at: dateFilter(),
deleted_at: dateFilter(),
})
},
})
declare module "joi" {
interface Root {
objectId: Joi.StringSchema
address: <T>() => Joi.AlternativesSchema
dateFilter: <T>() => Joi.ObjectSchema<T>
orderFilter: <T>() => Joi.ObjectSchema<T>
productFilter: <T>() => Joi.ObjectSchema<T>
}
}
export default Joi
@@ -0,0 +1,10 @@
{
"extends": "./tsconfig.json",
"include": [
"./src/**/*",
"index.d.ts",
"./src/**/__tests__",
"./src/**/__mocks__"
],
"exclude": ["node_modules"]
}
@@ -1,23 +1,23 @@
import { EntityManager } from "typeorm"
import { MedusaError, computerizeAmount } from "medusa-core-utils"
import { computerizeAmount, MedusaError } from "medusa-core-utils"
import { AbstractBatchJobStrategy, IFileService } from "../../../interfaces"
import CsvParser from "../../../services/csv-parser"
import {
BatchJobService,
ProductVariantService,
PriceListService,
ProductVariantService,
RegionService,
} from "../../../services"
import { CreateBatchJobInput } from "../../../types/batch-job"
import {
InjectedProps,
OperationType,
PriceListImportOperation,
PriceListImportOperationPrice,
ParsedPriceListImportPrice,
PriceListImportBatchJob,
PriceListImportCsvSchema,
PriceListImportOperation,
PriceListImportOperationPrice,
TBuiltPriceListImportLine,
TParsedPriceListImportRowData,
} from "./types"
@@ -204,7 +204,10 @@ class PriceListImportStrategy extends AbstractBatchJobStrategy {
record.currency_code = price.currency_code
}
record.amount = computerizeAmount(record.amount, record.currency_code)
record.amount = computerizeAmount(
record.amount as number,
record.currency_code
)
operationalPrices.push(record as PriceListImportOperationPrice)
}
@@ -218,7 +218,10 @@ class ProductImportStrategy extends AbstractBatchJobStrategy {
record.currency_code = price.currency_code
}
record.amount = computerizeAmount(record.amount, record.currency_code)
record.amount = computerizeAmount(
Number(record.amount),
record.currency_code as string
)
prices.push(record)
}
+6 -13
View File
@@ -216,7 +216,7 @@ __metadata:
languageName: node
linkType: hard
"@babel/cli@npm:^7.12.1, @babel/cli@npm:^7.13.0, @babel/cli@npm:^7.14.3, @babel/cli@npm:^7.15.4, @babel/cli@npm:^7.16.0, @babel/cli@npm:^7.7.5":
"@babel/cli@npm:^7.12.1, @babel/cli@npm:^7.14.3, @babel/cli@npm:^7.15.4, @babel/cli@npm:^7.16.0, @babel/cli@npm:^7.7.5":
version: 7.18.6
resolution: "@babel/cli@npm:7.18.6"
dependencies:
@@ -292,7 +292,7 @@ __metadata:
languageName: node
linkType: hard
"@babel/core@npm:^7.1.0, @babel/core@npm:^7.12.10, @babel/core@npm:^7.12.3, @babel/core@npm:^7.12.7, @babel/core@npm:^7.13.8, @babel/core@npm:^7.14.0, @babel/core@npm:^7.14.3, @babel/core@npm:^7.15.5, @babel/core@npm:^7.16.0, @babel/core@npm:^7.18.6, @babel/core@npm:^7.7.2, @babel/core@npm:^7.7.5, @babel/core@npm:^7.8.0":
"@babel/core@npm:^7.1.0, @babel/core@npm:^7.12.10, @babel/core@npm:^7.12.3, @babel/core@npm:^7.12.7, @babel/core@npm:^7.14.0, @babel/core@npm:^7.14.3, @babel/core@npm:^7.15.5, @babel/core@npm:^7.16.0, @babel/core@npm:^7.18.6, @babel/core@npm:^7.7.2, @babel/core@npm:^7.7.5, @babel/core@npm:^7.8.0":
version: 7.18.6
resolution: "@babel/core@npm:7.18.6"
dependencies:
@@ -709,7 +709,7 @@ __metadata:
languageName: node
linkType: hard
"@babel/plugin-proposal-class-properties@npm:^7.0.0, @babel/plugin-proposal-class-properties@npm:^7.10.4, @babel/plugin-proposal-class-properties@npm:^7.12.1, @babel/plugin-proposal-class-properties@npm:^7.13.0, @babel/plugin-proposal-class-properties@npm:^7.14.0, @babel/plugin-proposal-class-properties@npm:^7.14.5, @babel/plugin-proposal-class-properties@npm:^7.16.0, @babel/plugin-proposal-class-properties@npm:^7.18.6, @babel/plugin-proposal-class-properties@npm:^7.7.4":
"@babel/plugin-proposal-class-properties@npm:^7.0.0, @babel/plugin-proposal-class-properties@npm:^7.10.4, @babel/plugin-proposal-class-properties@npm:^7.12.1, @babel/plugin-proposal-class-properties@npm:^7.14.0, @babel/plugin-proposal-class-properties@npm:^7.14.5, @babel/plugin-proposal-class-properties@npm:^7.16.0, @babel/plugin-proposal-class-properties@npm:^7.18.6, @babel/plugin-proposal-class-properties@npm:^7.7.4":
version: 7.18.6
resolution: "@babel/plugin-proposal-class-properties@npm:7.18.6"
dependencies:
@@ -1668,7 +1668,7 @@ __metadata:
languageName: node
linkType: hard
"@babel/preset-env@npm:^7.11.5, @babel/preset-env@npm:^7.12.11, @babel/preset-env@npm:^7.12.7, @babel/preset-env@npm:^7.13.9, @babel/preset-env@npm:^7.15.4, @babel/preset-env@npm:^7.15.6, @babel/preset-env@npm:^7.16.4, @babel/preset-env@npm:^7.18.6, @babel/preset-env@npm:^7.7.5":
"@babel/preset-env@npm:^7.11.5, @babel/preset-env@npm:^7.12.11, @babel/preset-env@npm:^7.12.7, @babel/preset-env@npm:^7.15.4, @babel/preset-env@npm:^7.15.6, @babel/preset-env@npm:^7.16.4, @babel/preset-env@npm:^7.18.6, @babel/preset-env@npm:^7.7.5":
version: 7.18.6
resolution: "@babel/preset-env@npm:7.18.6"
dependencies:
@@ -1835,7 +1835,7 @@ __metadata:
languageName: node
linkType: hard
"@babel/runtime@npm:^7.0.0, @babel/runtime@npm:^7.1.2, @babel/runtime@npm:^7.10.0, @babel/runtime@npm:^7.10.2, @babel/runtime@npm:^7.10.4, @babel/runtime@npm:^7.11.2, @babel/runtime@npm:^7.12.13, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.13.9, @babel/runtime@npm:^7.15.4, @babel/runtime@npm:^7.16.3, @babel/runtime@npm:^7.17.8, @babel/runtime@npm:^7.18.0, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.3.1, @babel/runtime@npm:^7.5.0, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.6.2, @babel/runtime@npm:^7.7.2, @babel/runtime@npm:^7.7.6, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.9.2, @babel/runtime@npm:^7.9.6":
"@babel/runtime@npm:^7.0.0, @babel/runtime@npm:^7.1.2, @babel/runtime@npm:^7.10.0, @babel/runtime@npm:^7.10.2, @babel/runtime@npm:^7.10.4, @babel/runtime@npm:^7.11.2, @babel/runtime@npm:^7.12.13, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.15.4, @babel/runtime@npm:^7.16.3, @babel/runtime@npm:^7.17.8, @babel/runtime@npm:^7.18.0, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.3.1, @babel/runtime@npm:^7.5.0, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.6.2, @babel/runtime@npm:^7.7.2, @babel/runtime@npm:^7.7.6, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.9.2, @babel/runtime@npm:^7.9.6":
version: 7.18.6
resolution: "@babel/runtime@npm:7.18.6"
dependencies:
@@ -23568,20 +23568,13 @@ __metadata:
version: 0.0.0-use.local
resolution: "medusa-core-utils@workspace:packages/medusa-core-utils"
dependencies:
"@babel/cli": ^7.13.0
"@babel/core": ^7.13.8
"@babel/plugin-proposal-class-properties": ^7.13.0
"@babel/plugin-transform-classes": ^7.9.5
"@babel/plugin-transform-runtime": ^7.7.6
"@babel/preset-env": ^7.13.9
"@babel/preset-typescript": ^7.16.0
"@babel/runtime": ^7.13.9
class-transformer: ^0.5.1
class-validator: ^0.13.1
cross-env: ^5.2.1
jest: ^25.5.2
joi: ^17.3.0
joi-objectid: ^3.0.1
ts-jest: ^25.5.1
typescript: ^4.4.4
languageName: unknown
linkType: soft