Skip to content

Commit

Permalink
chore: improve types
Browse files Browse the repository at this point in the history
test: convert tests to ts
  • Loading branch information
pimlie committed Apr 4, 2021
1 parent 8e2fed1 commit 9d62122
Show file tree
Hide file tree
Showing 14 changed files with 139 additions and 110 deletions.
11 changes: 4 additions & 7 deletions jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,6 @@ module.exports = {

forceExit: false,

// https://github.com/facebook/jest/pull/6747 fix warning here
// But its performance overhead is pretty bad (30+%).
// detectOpenHandles: true

setupFilesAfterEnv: ['./test/utils/setup'],

coverageDirectory: './coverage',
Expand All @@ -31,16 +27,17 @@ module.exports = {
],

transform: {
'^.+\\.[tj]s$': 'babel-jest',
'.*\\.(vue)$': 'vue-jest'
'^.+\\.jsx?$': 'babel-jest',
'^.+\\.tsx?$': 'ts-jest',
'^.+\\.vue$': 'vue-jest'
},

moduleFileExtensions: [
'ts',
'js',
'json'
],

globals: {
__DEV__: true,
__BROWSER__: true,
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
"@rollup/plugin-commonjs": "^17.1.0",
"@rollup/plugin-node-resolve": "^11.2.0",
"@rollup/plugin-replace": "^2.4.1",
"@types/jest": "^26.0.22",
"@types/webpack": "^4.41.26",
"@types/webpack-env": "^1.16.0",
"@typescript-eslint/eslint-plugin": "^4.15.2",
Expand Down Expand Up @@ -100,7 +101,7 @@
"selenium-webdriver": "^4.0.0-beta.1",
"standard-version": "^9.1.1",
"tib": "^0.7.5",
"ts-jest": "^26.5.2",
"ts-jest": "^26.5.4",
"ts-loader": "^8.0.17",
"typescript": "^4.2.2",
"vite": "^2.0.4",
Expand Down
6 changes: 3 additions & 3 deletions src/manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,12 @@ export const createMetaManager = (config?: MetaConfig, resolver?: MetaResolver):

export class MetaManager {
config: MetaConfig
target: MergedObjectBuilder
target: MergedObjectBuilder<MetaSource>
resolver?: MetaResolverSetup

ssrCleanedUp: boolean = false

constructor (config: MetaConfig, target: MergedObjectBuilder, resolver: MetaResolver | ResolveMethod) {
constructor (config: MetaConfig, target: MergedObjectBuilder<MetaSource>, resolver: MetaResolver | ResolveMethod) {
this.config = config
this.target = target

Expand All @@ -83,7 +83,7 @@ export class MetaManager {
return resolver.resolve(options, contexts, active, key, pathSegments)
}

const mergedObject = createMergedObject(resolve, active)
const mergedObject = createMergedObject<MetaSource>(resolve, active)

// TODO: validate resolver
const manager = new MetaManager(config, mergedObject, resolver)
Expand Down
8 changes: 4 additions & 4 deletions src/object-merge/constants.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// https://github.com/microsoft/TypeScript/issues/1863
export const IS_PROXY = Symbol('kIsProxy') as unknown as string
export const PROXY_SOURCES = Symbol('kProxySources') as unknown as string
export const PROXY_TARGET = Symbol('kProxyTarget') as unknown as string
export const RESOLVE_CONTEXT = Symbol('kResolveContext') as unknown as string
export const IS_PROXY = Symbol('kIsProxy')
export const PROXY_SOURCES = Symbol('kProxySources')
export const PROXY_TARGET = Symbol('kProxyTarget')
export const RESOLVE_CONTEXT = Symbol('kResolveContext')
57 changes: 29 additions & 28 deletions src/object-merge/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import { PROXY_TARGET } from './constants'
import { IS_PROXY, PROXY_SOURCES, PROXY_TARGET, RESOLVE_CONTEXT } from './constants'
import { createProxy } from './proxy'
import { recompute } from './recompute'

export type MergeSource = {
[key: string]: any
export interface ResolveContext {}

export type MergeSource<T extends Object> = { [K in keyof T]: T[K] } & {
[IS_PROXY]: boolean
[PROXY_SOURCES]: MergeSource<T>[]
[PROXY_TARGET]: MergeSource<T>
[RESOLVE_CONTEXT]: ResolveContext
}

// eslint-disable-next-line no-use-before-define
Expand All @@ -15,49 +20,45 @@ export type MergedObject = {

export type PathSegments = Array<string>

export type ResolveContext = {}

export type ResolveMethod<T = ResolveContext> = (
options: Array<any>,
contexts: Array<T>,
active: MergedObjectValue,
key: string | number | symbol,
pathSegments: PathSegments,
) => MergedObjectValue
export interface ResolveMethod<T = any, U = ResolveContext> {
(
options: Array<T>,
contexts: Array<U>,
active: MergedObjectValue,
key: string | number | symbol,
pathSegments: PathSegments,
): MergedObjectValue
}

export type MergeContext = {
export type MergeContext<T> = {
resolve: ResolveMethod
active: MergedObject
sources: Array<MergeSource>
sources: MergeSource<T>[]
}

export type MergedObjectBuilder = {
context: MergeContext
export type MergedObjectBuilder<T> = {
context: MergeContext<T>
compute: () => void
addSource: (source: MergeSource, resolveContext: ResolveContext | undefined, recompute?: Boolean) => any
delSource: (sourceOrProxy: MergeSource, recompute?: boolean) => boolean
addSource: (source: T, resolveContext?: ResolveContext, recompute?: Boolean) => any
delSource: (sourceOrProxy: T | MergeSource<T>, recompute?: boolean) => boolean
}

export const createMergedObject = (resolve: ResolveMethod, active: MergedObject = {}): MergedObjectBuilder => {
const sources: Array<MergeSource> = []

if (!active) {
active = {}
}
export const createMergedObject = <T extends Object>(resolve: ResolveMethod<T>, active: T): MergedObjectBuilder<T> => {
const sources: MergeSource<T>[] = []

const context: MergeContext = {
const context: MergeContext<T> = {
active,
resolve,
sources
}

const compute: () => void = () => recompute(context)
const compute: () => void = () => recompute<T>(context)

return {
context,
compute,
addSource: (source, resolveContext, recompute = false) => {
const proxy = createProxy(context, source, resolveContext || {})
const proxy = createProxy<T>(context, source, resolveContext || {})

if (recompute) {
compute()
Expand All @@ -66,7 +67,7 @@ export const createMergedObject = (resolve: ResolveMethod, active: MergedObject
return proxy
},
delSource: (sourceOrProxy, recompute = true) => {
const index = sources.findIndex(src => src === sourceOrProxy || src[PROXY_TARGET] === sourceOrProxy)
const index = sources.findIndex(source => source === sourceOrProxy || source[PROXY_TARGET] === sourceOrProxy)

if (index > -1) {
sources.splice(index, 1)
Expand Down
21 changes: 11 additions & 10 deletions src/object-merge/proxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import { IS_PROXY, PROXY_SOURCES, PROXY_TARGET, RESOLVE_CONTEXT } from './consta
import { recompute } from './recompute'
import type { MergeContext, MergeSource, MergedObjectValue, PathSegments, ResolveContext } from '.'

export const createProxy = (context: MergeContext, target: MergeSource, resolveContext: ResolveContext, pathSegments: PathSegments = []) => {
const handler = createHandler(context, resolveContext, pathSegments)
const proxy = markRaw(new Proxy(target, handler))
export const createProxy = <T extends Record<string, any>>(context: MergeContext<T>, target: T, resolveContext: ResolveContext, pathSegments: PathSegments = []): MergeSource<T> => {
const handler = createHandler<T>(context, resolveContext, pathSegments)
const proxy = markRaw(new Proxy(target, handler)) as MergeSource<T>

if (!pathSegments.length && context.sources) {
context.sources.push(proxy)
Expand All @@ -16,7 +16,7 @@ export const createProxy = (context: MergeContext, target: MergeSource, resolveC
return proxy
}

export const createHandler: (context: MergeContext, resolveContext: ResolveContext, pathSegments: PathSegments) => ProxyHandler<any> = (context, resolveContext, pathSegments = []) => ({
export const createHandler = <T>(context: MergeContext<T>, resolveContext: ResolveContext, pathSegments: PathSegments = []): ProxyHandler<MergeSource<T>> => ({
get: (target, key, receiver) => {
if (key === IS_PROXY) {
return true
Expand All @@ -40,11 +40,11 @@ export const createHandler: (context: MergeContext, resolveContext: ResolveConte
return value
}

if (!value[IS_PROXY]) {
if (!(value as MergeSource<T>)[IS_PROXY]) {
const keyPath: PathSegments = [...pathSegments, (key as string)]

value = createProxy(context, value, resolveContext, keyPath)
target[key] = value
value = createProxy<typeof value>(context, value, resolveContext, keyPath)
Reflect.set(target, key, value)
}

return value
Expand Down Expand Up @@ -87,8 +87,8 @@ export const createHandler: (context: MergeContext, resolveContext: ResolveConte
return success
}

let keyContexts: Array<ResolveContext> = []
let keySources
let keyContexts: ResolveContext[] = []
let keySources: MergeSource<T>[]

if (isArrayItem) {
keySources = proxies
Expand Down Expand Up @@ -138,6 +138,7 @@ export const createHandler: (context: MergeContext, resolveContext: ResolveConte

let index = 0
for (const segment of pathSegments) {
// @ts-ignore
proxies = proxies.map(proxy => proxy[segment])

if (isArrayItem && index === pathSegments.length - 1) {
Expand All @@ -152,7 +153,7 @@ export const createHandler: (context: MergeContext, resolveContext: ResolveConte
// Check if the key still exists in one of the sourceProxies,
// if so resolve the new value, if not remove the key
if (proxies.some(proxy => (key in proxy))) {
let keyContexts: Array<ResolveContext> = []
let keyContexts: ResolveContext[] = []
let keySources

if (isArrayItem) {
Expand Down
7 changes: 5 additions & 2 deletions src/object-merge/recompute.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { clone, pluck } from '../utils'
import { RESOLVE_CONTEXT } from './constants'
import type { MergeContext, MergeSource, MergedObject, PathSegments, ResolveContext } from '.'

export const allKeys = (source?: MergeSource, ...sources: Array<MergeSource>): Array<string> => {
export const allKeys = <T>(source?: MergeSource<T>, ...sources: MergeSource<T>[]): string[] => {
const keys = source ? Object.keys(source) : []

if (sources) {
Expand All @@ -25,7 +25,7 @@ export const allKeys = (source?: MergeSource, ...sources: Array<MergeSource>): A
return keys
}

export const recompute = (context: MergeContext, sources?: Array<MergeSource>, target?: MergedObject, path: PathSegments = []): void => {
export const recompute = <T>(context: MergeContext<T>, sources?: MergeSource<T>[], target?: MergedObject, path: PathSegments = []): void => {
if (!path.length) {
if (!target) {
target = context.active
Expand All @@ -52,6 +52,7 @@ export const recompute = (context: MergeContext, sources?: Array<MergeSource>, t

for (const key of keys) {
// This assumes consistent types usages for keys across sources
// @ts-ignore
if (isPlainObject(sources[0][key])) {
if (!target[key]) {
target[key] = {}
Expand All @@ -60,6 +61,7 @@ export const recompute = (context: MergeContext, sources?: Array<MergeSource>, t
const keySources = []
for (const source of sources) {
if (key in source) {
// @ts-ignore
keySources.push(source[key])
}
}
Expand All @@ -69,6 +71,7 @@ export const recompute = (context: MergeContext, sources?: Array<MergeSource>, t
}

// Ensure the target is an array if source is an array and target is empty
// @ts-ignore
if (!target[key] && isArray(sources[0][key])) {
target[key] = []
}
Expand Down
2 changes: 1 addition & 1 deletion src/resolvers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ export interface ResolveOptionPredicament<T, U> {
(currentValue: T | undefined, context: U): T
}

export const resolveOption = <T, U = ResolveContext>(predicament: ResolveOptionPredicament<T, U>, initialValue?: T): ResolveMethod<U> => (options, contexts) => {
export const resolveOption = <T, U = ResolveContext>(predicament: ResolveOptionPredicament<T, U>, initialValue?: T): ResolveMethod<any, U> => (options, contexts) => {
let resolvedIndex = -1

contexts.reduce((acc, context, index) => {
Expand Down
4 changes: 2 additions & 2 deletions src/utils/collection.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@

export const pluck = (collection: Array<any>, key: string, callback?: (row: any) => void) => {
const plucked: Array<any> = []
export const pluck = <T extends Record<string, any>>(collection: T[], key: string, callback?: (row: T) => void) => {
const plucked: T[] = []

for (const row of collection) {
if (key in row) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { MergeContext } from 'src/object-merge'
import { createProxy } from '../../src/object-merge/proxy'

describe('proxy', () => {
let context
let context: MergeContext<any>

beforeEach(() => {
context = {
sources: [],
Expand All @@ -18,7 +20,7 @@ describe('proxy', () => {
}
}

const proxy = createProxy(context, target)
const proxy = createProxy(context, target, {})

expect(proxy.str).toBe('test')
expect(proxy.obj.str).toBe('test')
Expand All @@ -27,7 +29,7 @@ describe('proxy', () => {
test('string (set, update, delete)', () => {
const target = {}

const proxy = createProxy(context, target)
const proxy = createProxy(context, target, {})

proxy.str = 'test'

Expand All @@ -45,7 +47,7 @@ describe('proxy', () => {
test('array (set, update, delete)', () => {
const target = {}

const proxy = createProxy(context, target)
const proxy = createProxy(context, target, {})

proxy.arr = [0, 1]

Expand All @@ -68,7 +70,7 @@ describe('proxy', () => {
test('proxy (set object)', () => {
const target = {}

const proxy = createProxy(context, target)
const proxy = createProxy(context, target, {})

proxy.obj = { str: 'test' }

Expand All @@ -79,7 +81,7 @@ describe('proxy', () => {
test('proxy (remove)', () => {
const target = {}

const proxy = createProxy(context, target)
const proxy = createProxy(context, target, {})

proxy.obj = { str: 'test' }

Expand All @@ -93,7 +95,7 @@ describe('proxy', () => {
test('proxy (remove child)', () => {
const target = {}

const proxy = createProxy(context, target)
const proxy = createProxy(context, target, {})

proxy.obj = { str: 'test' }

Expand Down
Loading

0 comments on commit 9d62122

Please sign in to comment.