ronantakizawa/codereview-bench huggingface dataset:
Repository: element-plus/element-plus
File: packages/components/select/__tests__/select.test.ts (TypeScript)

Code before:
          } else {
            options.value = [{ value: '1', label: 'Option 1' }]
          }
        })
        return { value, options, remoteMethod }
      },
    })
    const select = wrapper.findComponent(Select)
    const input = wrapper.find('input')
    const vm = select.vm as any

    await input.trigger('click')
    vm.states.query = 'empty'
    await vm.remoteMethod('empty')
    vi.runAllTimers()
    await nextTick()
    await nextTick()
    expect(vm.states.options.size).toBe(0)
    expect(vm.states.query).toBe('empty')
    expect(vm.dropdownMenuVisible).toBe(true)
    expect(vm.expanded).toBe(true)
    const emptyText = document.querySelector('.custom-empty')
    expect(emptyText).not.toBeNull()
    expect(emptyText?.textContent).toBe('NO DATA')
    const popper = document.querySelector('.el-select__popper') as HTMLElement
    expect(popper.style.display).not.toBe('none')

    vi.useRealTimers()
  })
})


Review comment (refactor):
This test file is quite large, so I’d like to simplify it as much as possible. Some of these assertions seem redundant; maybe it’s sufficient to assert only `options.size`, `dropdownMenuVisible`, and `custom-empty`.


Code after:
            options.value = []
          } else {
            options.value = [{ value: '1', label: 'Option 1' }]
          }
        }
        return { value, options, remoteMethod }
      },
    })

    const select = wrapper.findComponent(Select)
    const input = wrapper.find('input')
    const vm = select.vm as any

    await input.trigger('click')
    expect(vm.states.options.size).toBe(0)
    expect(vm.dropdownMenuVisible).toBe(true)
    expect(document.querySelector('.custom-empty')).not.toBeNull()

    await input.setValue('a')
    vi.runAllTimers()
    await nextTick()
    expect(vm.states.options.size).toBe(1)
    expect(vm.dropdownMenuVisible).toBe(true)
    expect(document.querySelector('.custom-empty')).toBeNull()

    await input.setValue('empty')
    vi.runAllTimers()
    await nextTick()
    expect(vm.states.options.size).toBe(0)
    expect(vm.dropdownMenuVisible).toBe(true)
    expect(document.querySelector('.custom-empty')).not.toBeNull()

    vi.useRealTimers()
  })
})
Repository: element-plus/element-plus
File: packages/components/avatar/src/avatar.vue (Vue)

Code before:
</template>

<script lang="ts" setup>
import { computed, inject, ref, watch } from 'vue'
import { ElIcon } from '@element-plus/components/icon'
import { useNamespace } from '@element-plus/hooks'
import { addUnit, isNumber, isString } from '@element-plus/utils'
import { avatarEmits, avatarProps } from './avatar'
import { avatarGroupContextKey } from './constants'

import type { CSSProperties } from 'vue'

defineOptions({
  name: 'ElAvatar',
})

const props = defineProps(avatarProps)
const emit = defineEmits(avatarEmits)

const avatarGroupContext = inject(avatarGroupContextKey, undefined)

const ns = useNamespace('avatar')

const hasLoadError = ref(false)

const size = computed(() => props.size || avatarGroupContext?.size || '')
const shape = computed(
  () => props.shape || avatarGroupContext?.shape || 'circle'
)

const avatarClass = computed(() => {
  const { icon } = props
  const classList = [ns.b()]
  if (isString(size.value)) classList.push(ns.m(size.value))
  if (icon) classList.push(ns.m('icon'))
  if (shape.value) classList.push(ns.m(shape.value))
  return classList
})

const sizeStyle = computed(() => {
  return isNumber(size.value)
    ? (ns.cssVarBlock({
        size: addUnit(size.value)!,
      }) as CSSProperties)
    : undefined
})

const fitStyle = computed<CSSProperties>(() => ({
  objectFit: props.fit,
}))


Review comment (suggestion):
It would be better to use `??` here — we should respect `0`, right?

ref #22808

```suggestion
const size = computed(() => props.size ?? avatarGroupContext?.size ?? '')
```

Code after:
</template>

<script lang="ts" setup>
import { computed, inject, ref, watch } from 'vue'
import { ElIcon } from '@element-plus/components/icon'
import { useNamespace } from '@element-plus/hooks'
import { addUnit, isNumber, isString } from '@element-plus/utils'
import { avatarEmits, avatarProps } from './avatar'
import { avatarGroupContextKey } from './constants'

import type { CSSProperties } from 'vue'

defineOptions({
  name: 'ElAvatar',
})

const props = defineProps(avatarProps)
const emit = defineEmits(avatarEmits)

const avatarGroupContext = inject(avatarGroupContextKey, undefined)

const ns = useNamespace('avatar')

const hasLoadError = ref(false)

const size = computed(() => props.size ?? avatarGroupContext?.size)
const shape = computed(
  () => props.shape ?? avatarGroupContext?.shape ?? 'circle'
)

const avatarClass = computed(() => {
  const { icon } = props
  const classList = [ns.b()]
  if (isString(size.value)) classList.push(ns.m(size.value))
  if (icon) classList.push(ns.m('icon'))
  if (shape.value) classList.push(ns.m(shape.value))
  return classList
})

const sizeStyle = computed(() => {
  return isNumber(size.value)
    ? (ns.cssVarBlock({
        size: addUnit(size.value)!,
      }) as CSSProperties)
    : undefined
})

const fitStyle = computed<CSSProperties>(() => ({
  objectFit: props.fit,
}))
Repository: element-plus/element-plus
File: packages/components/avatar/src/avatar-group.tsx (TypeScript)

Code before:
        const hiddenAvatars = avatars.slice(
          props.maxCollapseAvatars,
          avatars.length
        )

        visibleAvatars.push(
          <ElTooltip
            popperClass={props.popperClass}
            popperStyle={props.popperStyle}
            placement={props.placement}
            effect={props.effect}
            disabled={!props.collapseAvatarsTooltip}
          >
            {{
              default: () => (
                <ElAvatar
                  size={props.size}
                  shape={props.shape}
                  class={props.collapseClass}
                  style={props.collapseStyle}
                >
                  + {hiddenAvatars.length}
                </ElAvatar>
              ),
              content: () => (
                <div class={ns.e('collapse-avatars')}>{hiddenAvatars}</div>
              ),
            }}
          </ElTooltip>
        )
      }

      return <div class={ns.b()}>{visibleAvatars}</div>
    }
  },
})


Review comment (suggestion):
It is due to the tooltip; we can modify the hiddenAvatars rendering logic.

```tsx
{hiddenAvatars.map((node, idx) =>
  isVNode(node) ? cloneVNode(node, { key: node.key ?? idx }) : node
)}
```

Code after:
      let visibleAvatars = avatars

      const showCollapseAvatar =
        props.collapseAvatars && avatars.length > props.maxCollapseAvatars

      if (showCollapseAvatar) {
        visibleAvatars = avatars.slice(0, props.maxCollapseAvatars)
        const hiddenAvatars = avatars.slice(props.maxCollapseAvatars)

        visibleAvatars.push(
          <ElTooltip
            popperClass={props.popperClass}
            popperStyle={props.popperStyle}
            placement={props.placement}
            effect={props.effect}
            disabled={!props.collapseAvatarsTooltip}
          >
            {{
              default: () => (
                <ElAvatar
                  size={props.size}
                  shape={props.shape}
                  class={props.collapseClass}
                  style={props.collapseStyle}
                >
                  + {hiddenAvatars.length}
                </ElAvatar>
              ),
              content: () => (
                <div class={ns.e('collapse-avatars')}>
                  {hiddenAvatars.map((node, idx) =>
                    isVNode(node)
                      ? cloneVNode(node, { key: node.key ?? idx })
                      : node
                  )}
                </div>
              ),
            }}
          </ElTooltip>
        )
      }

      return <div class={ns.b()}>{visibleAvatars}</div>
    }
  },
})
Repository: element-plus/element-plus
File: packages/components/input/src/input.ts (TypeScript)

Code before:
 */
export type InputPropsPublic = ExtractPublicPropTypes<typeof inputProps>

/**
 * @deprecated Removed after 3.0.0
 */
export const inputEmits = {
  [UPDATE_MODEL_EVENT]: (value: string) => isString(value),
  input: (value: string) => isString(value),
  change: (value: string, evt?: Event) =>
    isString(value) && (evt instanceof Event || evt === undefined),
  focus: (evt: FocusEvent) => evt instanceof FocusEvent,
  blur: (evt: FocusEvent) => evt instanceof FocusEvent,
  clear: () => true,
  mouseleave: (evt: MouseEvent) => evt instanceof MouseEvent,
  mouseenter: (evt: MouseEvent) => evt instanceof MouseEvent,
  // NOTE: when autofill by browser, the keydown event is instanceof Event, not KeyboardEvent
  // relative bug report https://github.com/element-plus/element-plus/issues/6665
  keydown: (evt: KeyboardEvent | Event) => evt instanceof Event,
  compositionstart: (evt: CompositionEvent) => evt instanceof CompositionEvent,
  compositionupdate: (evt: CompositionEvent) => evt instanceof CompositionEvent,
  compositionend: (evt: CompositionEvent) => evt instanceof CompositionEvent,
}

export interface InputProps<
  M extends InputModelModifiers = InputModelModifiers,
> {
  /**
   * @description native input id
   */
  id?: string
  /**
   * @description input box size
   */
  size?: ComponentSize
  /**
   * @description whether to disable
   */
  disabled?: boolean
  /**
   * @description binding value
   */
  modelValue?: string | number | null | undefined
  /**
   * @description v-model modifiers, reference [Vue modifiers](https://vuejs.org/guide/essentials/forms.html#modifiers)
   */
  modelModifiers?: M
  /**
   * @description same as `maxlength` in native input
   */
  maxlength?: string | number

Review comment (suggestion):
It seems this isn't a public type that will be used everywhere, so perhaps we don't need to declare generics here. 🤔 

Code after:
   * @description whether textarea has an adaptive height
   */
  autosize: {
    type: definePropType<InputAutoSize>([Boolean, Object]),
    default: false,
  },
  /**
   * @description native input autocomplete
   */
  autocomplete: {
    type: definePropType<HTMLInputElement['autocomplete']>(String),
    default: 'off',
  },
  /**
   * @description format content
   */
  formatter: {
    type: Function,
  },
  /**
   * @description parse content
   */
  parser: {
    type: Function,
  },
  /**
   * @description placeholder
   */
  placeholder: {
    type: String,
  },
  /**
   * @description native input form
   */
  form: {
    type: String,
  },
  /**
   * @description native input readonly
   */
  readonly: Boolean,
  /**
   * @description whether to show clear button
   */
  clearable: Boolean,
  /**
   * @description custom clear icon component
   */
  clearIcon: {
    type: iconPropType,
    default: CircleClose,
Repository: element-plus/element-plus
File: packages/components/input-number/src/input-number.vue (Vue)

Code before:
  getEventCode,
  getEventKey,
  isNumber,
  isString,
  isUndefined,
  throwError,
} from '@element-plus/utils'
import { ArrowDown, ArrowUp, Minus, Plus } from '@element-plus/icons-vue'
import {
  CHANGE_EVENT,
  EVENT_CODE,
  INPUT_EVENT,
  UPDATE_MODEL_EVENT,
} from '@element-plus/constants'
import { inputNumberEmits } from './input-number'

import type { InputInstance } from '@element-plus/components/input'
import type { InputNumberProps } from './input-number'

defineOptions({
  name: 'ElInputNumber',
})

const props = withDefaults(defineProps<InputNumberProps>(), {
  disabled: undefined,
  step: 1,
  max: Number.MAX_SAFE_INTEGER,
  min: Number.MIN_SAFE_INTEGER,
  stepStrictly: false,
  readonly: false,
  controls: true,
  controlsPosition: '',
  valueOnClear: null,
  validateEvent: true,
  align: 'center',
  disabledScientific: false,
})
const emit = defineEmits(inputNumberEmits)

const { t } = useLocale()
const ns = useNamespace('input-number')
const input = ref<InputInstance>()

interface Data {
  currentValue: number | null | undefined
  userInput: null | number | string
}
const data = reactive<Data>({
  currentValue: props.modelValue,
  userInput: null,
})

Review comment (suggestion):
```suggestion
  id: '',
  disabled: undefined,
```

Code after:
  getEventCode,
  getEventKey,
  isNumber,
  isString,
  isUndefined,
  throwError,
} from '@element-plus/utils'
import { ArrowDown, ArrowUp, Minus, Plus } from '@element-plus/icons-vue'
import {
  CHANGE_EVENT,
  EVENT_CODE,
  INPUT_EVENT,
  UPDATE_MODEL_EVENT,
} from '@element-plus/constants'
import { inputNumberEmits } from './input-number'

import type { InputInstance } from '@element-plus/components/input'
import type { InputNumberProps } from './input-number'

defineOptions({
  name: 'ElInputNumber',
})

const props = withDefaults(defineProps<InputNumberProps>(), {
  id: undefined,
  disabled: undefined,
  step: 1,
  max: Number.MAX_SAFE_INTEGER,
  min: Number.MIN_SAFE_INTEGER,
  stepStrictly: false,
  readonly: false,
  controls: true,
  controlsPosition: '',
  valueOnClear: null,
  validateEvent: true,
  inputmode: undefined,
  align: 'center',
})
const emit = defineEmits(inputNumberEmits)

const { t } = useLocale()
const ns = useNamespace('input-number')
const input = ref<InputInstance>()

interface Data {
  currentValue: number | null | undefined
  userInput: null | number | string
}
const data = reactive<Data>({
  currentValue: props.modelValue,
  userInput: null,
Repository: element-plus/element-plus
File: packages/components/input-number/src/input-number.vue (Vue)

Code before:
  debugWarn,
  getEventCode,
  getEventKey,
  isNumber,
  isString,
  isUndefined,
  throwError,
} from '@element-plus/utils'
import { ArrowDown, ArrowUp, Minus, Plus } from '@element-plus/icons-vue'
import {
  CHANGE_EVENT,
  EVENT_CODE,
  INPUT_EVENT,
  UPDATE_MODEL_EVENT,
} from '@element-plus/constants'
import { inputNumberEmits } from './input-number'

import type { InputInstance } from '@element-plus/components/input'
import type { InputNumberProps } from './input-number'

defineOptions({
  name: 'ElInputNumber',
})

const props = withDefaults(defineProps<InputNumberProps>(), {
  id: '',
  disabled: undefined,
  step: 1,
  max: Number.MAX_SAFE_INTEGER,
  min: Number.MIN_SAFE_INTEGER,
  stepStrictly: false,
  readonly: false,
  controls: true,
  controlsPosition: '',
  valueOnClear: null,
  validateEvent: true,
  align: 'center',
})
const emit = defineEmits(inputNumberEmits)

const { t } = useLocale()
const ns = useNamespace('input-number')
const input = ref<InputInstance>()

interface Data {
  currentValue: number | null | undefined
  userInput: null | number | string
}
const data = reactive<Data>({
  currentValue: props.modelValue,
  userInput: null,

Review comment (suggestion):
```suggestion
  id: undefined,
```

Sorry I didn't notice

Code after:
  debugWarn,
  getEventCode,
  getEventKey,
  isNumber,
  isString,
  isUndefined,
  throwError,
} from '@element-plus/utils'
import { ArrowDown, ArrowUp, Minus, Plus } from '@element-plus/icons-vue'
import {
  CHANGE_EVENT,
  EVENT_CODE,
  INPUT_EVENT,
  UPDATE_MODEL_EVENT,
} from '@element-plus/constants'
import { inputNumberEmits } from './input-number'

import type { InputInstance } from '@element-plus/components/input'
import type { InputNumberProps } from './input-number'

defineOptions({
  name: 'ElInputNumber',
})

const props = withDefaults(defineProps<InputNumberProps>(), {
  id: undefined,
  disabled: undefined,
  step: 1,
  max: Number.MAX_SAFE_INTEGER,
  min: Number.MIN_SAFE_INTEGER,
  stepStrictly: false,
  readonly: false,
  controls: true,
  controlsPosition: '',
  valueOnClear: null,
  validateEvent: true,
  inputmode: undefined,
  align: 'center',
})
const emit = defineEmits(inputNumberEmits)

const { t } = useLocale()
const ns = useNamespace('input-number')
const input = ref<InputInstance>()

interface Data {
  currentValue: number | null | undefined
  userInput: null | number | string
}
const data = reactive<Data>({
  currentValue: props.modelValue,
Repository: element-plus/element-plus
File: packages/components/avatar/src/avatar.vue (Vue)

Code before:
  <span :class="avatarClass" :style="sizeStyle">
    <img
      v-if="(src || srcSet) && !hasLoadError"
      :src="src"
      :alt="alt"
      :srcset="srcSet"
      :style="fitStyle"
      @error="handleError"
    />
    <el-icon v-else-if="icon">
      <component :is="icon" />
    </el-icon>
    <slot v-else />
  </span>
</template>

<script lang="ts" setup>
import { computed, inject, ref, watch } from 'vue'
import { ElIcon } from '@element-plus/components/icon'
import { useNamespace } from '@element-plus/hooks'
import { addUnit, isNumber, isString } from '@element-plus/utils'
import { avatarEmits } from './avatar'
import { avatarGroupContextKey } from './constants'

import type { AvatarProps } from './avatar'
import type { CSSProperties } from 'vue'

defineOptions({
  name: 'ElAvatar',
})

const props = withDefaults(defineProps<AvatarProps>(), {
  src: '',
  fit: 'cover',
})
const emit = defineEmits(avatarEmits)

const avatarGroupContext = inject(avatarGroupContextKey, undefined)

const ns = useNamespace('avatar')

const hasLoadError = ref(false)

const size = computed(() => props.size ?? avatarGroupContext?.size)
const shape = computed(
  () => props.shape ?? avatarGroupContext?.shape ?? 'circle'
)

const avatarClass = computed(() => {
  const { icon } = props
  const classList = [ns.b()]

Review comment (suggestion):
```suggestion
import type { CSSProperties } from 'vue'
import type { AvatarProps } from './avatar'
```

Code after:
  <span :class="avatarClass" :style="sizeStyle">
    <img
      v-if="(src || srcSet) && !hasLoadError"
      :src="src"
      :alt="alt"
      :srcset="srcSet"
      :style="fitStyle"
      @error="handleError"
    />
    <el-icon v-else-if="icon">
      <component :is="icon" />
    </el-icon>
    <slot v-else />
  </span>
</template>

<script lang="ts" setup>
import { computed, inject, ref, watch } from 'vue'
import { ElIcon } from '@element-plus/components/icon'
import { useNamespace } from '@element-plus/hooks'
import { addUnit, isNumber, isString } from '@element-plus/utils'
import { avatarEmits, avatarProps } from './avatar'
import { avatarGroupContextKey } from './constants'

import type { CSSProperties } from 'vue'

defineOptions({
  name: 'ElAvatar',
})

const props = defineProps(avatarProps)
const emit = defineEmits(avatarEmits)

const avatarGroupContext = inject(avatarGroupContextKey, undefined)

const ns = useNamespace('avatar')

const hasLoadError = ref(false)

const size = computed(() => props.size ?? avatarGroupContext?.size)
const shape = computed(
  () => props.shape ?? avatarGroupContext?.shape ?? 'circle'
)

const avatarClass = computed(() => {
  const { icon } = props
  const classList = [ns.b()]
  if (isString(size.value)) classList.push(ns.m(size.value))
  if (icon) classList.push(ns.m('icon'))
  if (shape.value) classList.push(ns.m(shape.value))
  return classList
Repository: element-plus/element-plus
File: packages/components/link/src/link.ts (TypeScript)

Code before:

import type { Component, ExtractPublicPropTypes, PropType } from 'vue'
import type Link from './link.vue'

export interface LinkProps {
  /**
   * @description type
   */
  type?: 'primary' | 'success' | 'warning' | 'info' | 'danger' | 'default'
  /**
   * @description when underlines should appear
   */
  underline?: boolean | 'always' | 'never' | 'hover'

  /**
   * @description whether the component is disabled
   */
  disabled?: boolean
  /**
   * @description same as native hyperlink's `href`
   */
  href?: string
  /**
   * @description same as native hyperlink's `target`
   */
  target?: '_blank' | '_parent' | '_self' | '_top' | string

  /**
   * @description icon component
   */
  icon?: string | Component
}

/**
 * @deprecated Removed after 3.0.0, Use `LinkProps` instead.
 */
export const linkProps = buildProps({
  /**
   * @description type
   */
  type: {
    type: String,
    values: ['primary', 'success', 'warning', 'info', 'danger', 'default'],
    default: undefined,
  },
  /**
   * @description when underlines should appear
   */
  underline: {
    type: [Boolean, String],
    values: [true, false, 'always', 'never', 'hover'],

Review comment (suggestion):
```suggestion
  target?:
    | '_blank'
    | '_parent'
    | '_self'
    | '_top'
    | (string & NonNullable<unknown>)
```

Code after:

import type { Component, ExtractPublicPropTypes, PropType } from 'vue'
import type Link from './link.vue'

export interface LinkProps {
  /**
   * @description type
   */
  type?: 'primary' | 'success' | 'warning' | 'info' | 'danger' | 'default'
  /**
   * @description when underlines should appear
   */
  underline?: boolean | 'always' | 'never' | 'hover'

  /**
   * @description whether the component is disabled
   */
  disabled?: boolean
  /**
   * @description same as native hyperlink's `href`
   */
  href?: string
  /**
   * @description same as native hyperlink's `target`
   */
  target?:
    | '_blank'
    | '_parent'
    | '_self'
    | '_top'
    | (string & NonNullable<unknown>)

  /**
   * @description icon component
   */
  icon?: string | Component
}

/**
 * @deprecated Removed after 3.0.0, Use `LinkProps` instead.
 */
export const linkProps = buildProps({
  /**
   * @description type
   */
  type: {
    type: String,
    values: ['primary', 'success', 'warning', 'info', 'danger', 'default'],
    default: undefined,
  },
  /**
Repository: element-plus/element-plus
File: packages/components/badge/src/badge.vue (Vue)

Code before:
      </sup>
    </transition>
  </div>
</template>

<script lang="ts" setup>
import { computed } from 'vue'
import { useNamespace } from '@element-plus/hooks'
import { addUnit, isNumber } from '@element-plus/utils'

import type { BadgeProps } from './badge'
import type { StyleValue } from 'vue'

defineOptions({
  name: 'ElBadge',
})

const props = withDefaults(defineProps<BadgeProps>(), {
  value: '',
  max: 99,
  isDot: false,
  hidden: false,
  type: 'danger',
  showZero: true,
  offset: () => [0, 0],
  badgeStyle: false,
})

const ns = useNamespace('badge')

const content = computed<string>(() => {
  if (props.isDot) return ''
  if (isNumber(props.value) && isNumber(props.max)) {
    return props.max < props.value ? `${props.max}+` : `${props.value}`
  }
  return `${props.value}`
})

const style = computed<StyleValue>(() => {
  return [
    {
      backgroundColor: props.color,
      marginRight: addUnit(-props.offset[0]),
      marginTop: addUnit(props.offset[1]),
    },
    props.badgeStyle ?? {},
  ]
})

defineExpose({
  /** @description badge content */

Review comment (suggestion):
```suggestion
  value: '',
  max: 99,
  type: 'danger',
  showZero: true,
  offset: () => [0, 0],
```

The default value for a Boolean type is false, so we can ignore it.

Code after:
      </sup>
    </transition>
  </div>
</template>

<script lang="ts" setup>
import { computed } from 'vue'
import { useNamespace } from '@element-plus/hooks'
import { addUnit, isNumber } from '@element-plus/utils'

import type { StyleValue } from 'vue'
import type { BadgeProps } from './badge'

defineOptions({
  name: 'ElBadge',
})

const props = withDefaults(defineProps<BadgeProps>(), {
  value: '',
  max: 99,
  type: 'danger',
  showZero: true,
  offset: () => [0, 0],
})

const ns = useNamespace('badge')

const content = computed<string>(() => {
  if (props.isDot) return ''
  if (isNumber(props.value) && isNumber(props.max)) {
    return props.max < props.value ? `${props.max}+` : `${props.value}`
  }
  return `${props.value}`
})

const style = computed<StyleValue>(() => {
  return [
    {
      backgroundColor: props.color,
      marginRight: addUnit(-props.offset[0]),
      marginTop: addUnit(props.offset[1]),
    },
    props.badgeStyle ?? {},
  ]
})

defineExpose({
  /** @description badge content */
  content,
})
</script>