Oh MyUtils

Semver 계산기 - 시맨틱 버전 파싱, 비교 & 테스트 온라인

시맨틱 버전 문자열을 파싱, 비교, 정렬하고 npm 스타일 범위를 테스트하세요. 캐럿, 틸드, 와일드카드, OR 범위를 지원합니다 — 100% 클라이언트 사이드, 서버로 데이터를 전송하지 않습니다.

비교할 유효한 두 버전을 입력하세요

자주 묻는 질문

시맨틱 버저닝(SemVer)이란 무엇인가요?

시맨틱 버저닝은 MAJOR.MINOR.PATCH 세 부분으로 구성된 버전 표준입니다. MAJOR는 하위 호환되지 않는 변경, MINOR는 하위 호환되는 새 기능, PATCH는 하위 호환되는 버그 수정 시 증가합니다. SemVer 2.0.0 사양으로 정의되며 npm, PyPI, Cargo, Go 모듈 등 거의 모든 현대 패키지 생태계에서 사용됩니다.

이 semver 계산기 도구는 어떻게 사용하나요?

필요에 따라 네 가지 탭 중 하나를 선택하세요: (1) 비교 — 두 버전을 입력하여 어느 것이 더 큰지 확인, (2) 범위 체크 — 버전과 npm 스타일 범위를 입력하여 만족 여부 테스트, (3) 정렬 — 여러 버전을 붙여넣어 우선순위로 정렬, (4) 버전 증가 — 버전을 입력하여 다음 major, minor, patch, pre-release 버전 확인. 모든 결과는 입력하는 동안 실시간으로 업데이트됩니다.

버전 데이터는 안전한가요? 서버로 전송되나요?

모든 파싱, 비교, 범위 확인은 브라우저에서 JavaScript를 사용하여 100% 클라이언트 측에서 수행됩니다. 어떤 데이터도 서버로 전송되지 않습니다. npm 레지스트리를 조회하는 도구와 달리 이 도구는 완전히 오프라인으로 작동하므로 내부 또는 독점 버전 문자열에 안전하게 사용할 수 있습니다.

캐럿(^)과 틸드(~) 범위의 차이점은 무엇인가요?

캐럿(^) 범위는 가장 왼쪽의 0이 아닌 숫자를 수정하지 않는 변경을 허용합니다: ^1.2.3은 >=1.2.3 <2.0.0을 의미합니다. 틸드(~) 범위는 패치 수준의 변경만 허용합니다: ~1.2.3은 >=1.2.3 <1.3.0을 의미합니다. 0.x 버전의 경우 캐럿은 더 제한적으로 동작합니다: ^0.2.3은 >=0.2.3 <0.3.0을 의미합니다 (이 경우 틸드와 동일).

SemVer는 프리릴리스 버전을 어떻게 처리하나요?

프리릴리스 버전은 하이픈으로 추가됩니다 (예: 1.0.0-alpha, 1.0.0-beta.1). 관련 정식 버전보다 낮은 우선순위를 가지므로 1.0.0-alpha < 1.0.0입니다. 프리릴리스 식별자는 왼쪽에서 오른쪽으로 비교됩니다: 숫자 식별자는 정수로 비교하고, 영숫자 식별자는 사전순으로 비교하며, 숫자 식별자는 항상 영숫자보다 낮은 우선순위를 가집니다.

빌드 메타데이터란 무엇이며 버전 비교에 영향을 미치나요?

빌드 메타데이터는 더하기 기호로 추가됩니다 (예: 1.0.0+build.123). SemVer 2.0.0 사양에 따라 빌드 메타데이터는 버전 우선순위를 결정할 때 반드시 무시해야 합니다. 즉, 1.0.0+build.1과 1.0.0+build.999는 우선순위가 동일합니다.

범위에 대해 여러 버전을 한 번에 테스트할 수 있나요?

네. 범위 체크 탭에서 일괄 모드를 활성화하면 여러 버전을 한 줄에 하나씩 입력할 수 있습니다. 도구는 각 버전을 범위 표현식에 대해 테스트하고 색상으로 구분된 결과와 함께 목록에서 일치하는 최소 및 최대 버전을 표시합니다.

코드 예제

// Semantic Versioning Parser & Comparator

function parseSemVer(version) {
  const match = version.trim().match(
    /^v?(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-([\w.]+))?(?:\+([\w.]+))?$/
  );
  if (!match) return null;
  return {
    major: parseInt(match[1], 10),
    minor: parseInt(match[2], 10),
    patch: parseInt(match[3], 10),
    prerelease: match[4]
      ? match[4].split('.').map(id => /^\d+$/.test(id) ? parseInt(id, 10) : id)
      : [],
    build: match[5] ? match[5].split('.') : [],
  };
}

function compareSemVer(a, b) {
  for (const key of ['major', 'minor', 'patch']) {
    if (a[key] > b[key]) return 1;
    if (a[key] < b[key]) return -1;
  }
  if (a.prerelease.length > 0 && b.prerelease.length === 0) return -1;
  if (a.prerelease.length === 0 && b.prerelease.length > 0) return 1;
  const len = Math.max(a.prerelease.length, b.prerelease.length);
  for (let i = 0; i < len; i++) {
    if (i >= a.prerelease.length) return -1;
    if (i >= b.prerelease.length) return 1;
    const ai = a.prerelease[i], bi = b.prerelease[i];
    if (ai === bi) continue;
    if (typeof ai === 'number' && typeof bi === 'number') return ai < bi ? -1 : 1;
    if (typeof ai === 'number') return -1;
    if (typeof bi === 'number') return 1;
    return ai < bi ? -1 : 1;
  }
  return 0;
}

function sortVersions(versions, ascending = true) {
  return versions
    .map(v => ({ raw: v, parsed: parseSemVer(v) }))
    .filter(v => v.parsed !== null)
    .sort((a, b) => compareSemVer(a.parsed, b.parsed) * (ascending ? 1 : -1))
    .map(v => v.raw);
}

// Example
const versions = ['2.0.0', '1.0.0-alpha', '1.0.0', '1.2.3', '0.9.0'];
console.log('Sorted:', sortVersions(versions));
// ['0.9.0', '1.0.0-alpha', '1.0.0', '1.2.3', '2.0.0']

관련 도구