# JSON 포매터 — 펼치고, 압축하고, 변환하기

JSON, XML, HTML, CSS, YAML을 정렬하거나 변환합니다. 남의 서버에 붙여 넣는 것은 없습니다.

> JSON, XML, HTML, CSS, YAML을 정렬하고 압축하고, JSON을 YAML이나 XML로 바꾸고 되돌립니다. 파서는 브라우저 안에서 돌아가고 아무것도 업로드되지 않아서, 토큰이나 설정 파일이 내 기기를 떠날 일이 없습니다.

이 페이지는 브라우저 안에서만 동작하는 대화형 도구입니다(https://abox.tools/ko/json-포맷터/). 도구에 넘긴 어떤 것도 업로드되지 않습니다. 아래는 이 페이지가 도구에 대해 글로 설명하는 내용 전부입니다. 도구를 쓰려면 이 주소를 여세요.

## 텍스트와 코드는 **절대 업로드되지 않습니다**. 서버가 아예 없으니까요.

정렬과 변환은 문자열을 두고 하는 산술이고, 여기 이 페이지에서 이루어집니다. 파서는 직접 손으로 쓴 것이고 `src/` 안의 `shared/parse-json.js`, `shared/parse-xml.js`, `css.js`, `shared/parse-yaml.js`에 있으며, 그 밖의 것은 없습니다. 이 도구에는 네트워크 기능이 하나도 없어서 가져올 것도 보낼 것도 없고, 그 사실이 이 사이트의 거의 다른 어디보다 여기서 더 중요합니다. 사람들이 포매터에 붙여 넣는 것은 액세스 토큰이고 세션 쿠키이고 고객 기록이고 공개 전 코드니까요.

- ✗ 업로드 없음
- ✗ 가입 없음
- ✗ 용량 제한 없음
- ✓ 오프라인 동작
- ✓ 오픈 소스

## 업로드하지 않고 JSON을 정렬하거나 변환하는 방법

1. **할 일을 고릅니다.** 탭 두 개에 상자 하나. *정렬*은 JSON, XML, HTML, CSS, YAML을 보기 좋게 펼치거나 납작하게 압축하고, *변환*은 JSON을 YAML이나 XML로 바꾸고 되돌립니다. 방금 정렬한 텍스트가 곧 변환할 텍스트라서 두 번 붙여 넣을 일이 없습니다.
2. **붙여 넣거나, 파일을 놓습니다.** 선택해서 복사할 수 있는 것이면 무엇이든 됩니다. 선택 영역에 놓인 파일은 브라우저가 읽어 상자에 넣습니다. 빼놓을 업로드 단계 자체가 없어요.
3. **언어를 알아서 알아내게 두거나, 직접 알려 줍니다.** 메뉴에 그 텍스트를 무엇으로 읽었는지가 적히고, 고치는 데는 한 번의 클릭이면 됩니다. 추측은 출발점일 뿐이라, 말없이 적용하는 대신 보여 드립니다.
4. **들여쓰기를 고르거나, 납작하게 눌러 담습니다.** 공백 두 칸, 네 칸, 아니면 탭. 납작하게 누른다는 것은 읽기 위해서만 있던 공백을 전부 걷어 낸 같은 문서라는 뜻이고, 결과에 그것으로 몇 바이트를 아꼈는지가 적힙니다.
5. **오류가 있는 자리에서 오류를 읽습니다.** 여기서 실패하는 파서는 "위치 4193에서 예상치 못한 토큰"이 아니라, 무엇을 발견했는지와 몇째 줄 몇째 칸인지를 말합니다. 대개 다른 것을 열지 않고도 설정 파일을 고치기에 충분합니다.
6. **결과를 가져갑니다.** 복사하거나, 결과가 나온 언어의 이름이 붙은 파일로 내려받으세요.

## 자세한 설명

[누구에게도 넘기지 않고 JSON을 정렬하는 방법](https://abox.tools/ko/가이드/json-정렬하기/): 브라우저 안에서 JSON을 펼치고 확인하고 눌러 담는 방법. 포매터가 남의 파일에서 절대 바꾸면 안 되는 것, 오류 메시지를 읽는 법, 그리고 그걸 붙여 넣는 사이트가 왜 중요한지.

## 상자 속 다른 도구

- [YAML → JSON 변환기](https://abox.tools/ko/yaml-json-변환/): 양쪽 방향 모두, 그리고 각 방향이 무엇을 치르는지도 말해 줍니다. 그 어느 것도 남의 서버에 붙여 넣지 않습니다.
- [XML 포맷터](https://abox.tools/ko/xml-포맷터/): 읽으라고 펼친 XML, 보내라고 납작하게 누른 XML, 그리고 양쪽으로 오가는 JSON 변환. 그 어느 것도 남의 서버에 붙여 넣지 않습니다.
- [텍스트 비교](https://abox.tools/ko/텍스트-비교/): 두 텍스트를 넣으면 모든 차이가 줄 단위, 단어 단위로 표시됩니다. 남의 서버에 붙여 넣는 것은 없습니다.
- [Base64 인코더 · 디코더](https://abox.tools/ko/base64-인코딩/): Base64, 퍼센트 인코딩, HTML 엔티티, 16진수, 역슬래시 이스케이프를 양방향으로. 남의 서버에 붙여 넣는 것은 없습니다.

## 자주 묻는 질문

### 제 텍스트가 어딘가로 업로드되나요?

아닙니다. 이 페이지의 모든 파서와 프린터는 내 기기에서, 내 브라우저 안에서 도는 함수입니다. 이 도구에는 네트워크 기능이 하나도 없어서 무언가를 가져오지도, 보내지도 않습니다. 이 페이지의 `Content-Security-Policy`에 연결해도 되는 주소가 전부 적혀 있는데, 그중 이 사이트 것은 하나도 없습니다. 액세스 토큰이나 세션 쿠키, 고객 기록에 이 도구를 써야 하는 이유가 그것입니다. 그런 것을 남의 포매터에 붙여 넣는 것은 그들에게 그것을 주는 일이니까요.

### JSON을 정렬하면 배치 말고 달라지는 것이 있나요?

없습니다. 들리는 것보다 어려운 일입니다. 키는 쓰신 순서를 지킵니다. `JSON.parse` 위에 세운 포매터는 정수처럼 생긴 키를 말없이 앞으로 옮겨서, `{"10":a,"2":b}`가 `{"2":b,"10":a}`로 돌아옵니다. 숫자는 입력하신 자릿수를 지켜서, 스무 자리 id가 배정밀도 수 때문에 마지막 세 자리를 잃지 않고 `1e999`가 `null`이 되지도 않습니다. 중복된 키는 둘 다 남깁니다. 표준이 어느 쪽이 이기는지 말하지 않는데, 하나를 버리는 것은 대신 골라 드리는 일이기 때문입니다.

### 어떤 언어를 정렬할 수 있나요?

JSON, XML, HTML, CSS, YAML입니다. JSON과 XML, HTML, CSS는 납작하게 눌러 담을 수도 있습니다. YAML은 안 됩니다. 그 짧은 형태가 플로 스타일인데 읽을 수가 없고, 읽을 수 없다는 것은 파일을 YAML로 두는 이유의 정반대이기 때문입니다. JavaScript는 일부러 목록에 없습니다. 아래의 그에 대한 질문을 보세요.

### JavaScript나 Python, SQL은 왜 정렬하지 않나요?

프로그래밍 언어를 배치한다는 것은 그것을 제대로 파싱한다는 뜻이고, 거의 맞게 해내는 포매터는 없느니만 못하기 때문입니다. 멀쩡해 보이면서 다른 일을 하는 코드를 만들어 내니까요. JSON, XML, CSS, YAML은 문법이 손으로 읽고 누구나 돌려 볼 수 있는 테스트로 확인할 만큼 작습니다. JavaScript 포매터는 Prettier이고, 그건 1메가바이트짜리 파서이며, 웹페이지가 아니라 편집기에 있어야 할 물건입니다.

### 제 YAML의 no가 JSON에서 문자열로 나왔습니다. 왜죠?

문자열이 맞기 때문이고, 이 도구가 YAML 1.1이 아니라 1.2로 읽기 때문입니다. YAML 1.1에서는 `yes`, `no`, `on`, `off`가 불리언이었는데, 노르웨이의 국가 코드를 `false`로 만들어 버리는 그 유명한 버그가 거기서 나옵니다. YAML 1.2가 그것을 걷어 냈고 이 도구도 그렇습니다. `true`, `false`, `null`, `~`만 글자 아닌 것으로 읽습니다. 반대 방향에서는 그 낱말들을 *따옴표로 감싸* 씁니다. 이 도구라면 따옴표 없이도 글자로 읽겠지만, 다음에 그 파일을 여는 것이 그러지 않을 수 있기 때문입니다. PyYAML은 아직 1.1이 기본입니다. 엄격하게 읽고 보수적으로 쓰는 것이 양쪽 모두에서 옳은 유일한 조합입니다.

### YAML을 JSON으로 바꾸면 무엇을 잃나요?

주석입니다. JSON에는 그걸 넣을 자리가 없습니다. 앵커와 별칭, 태그는 짐작하는 대신 아예 거부합니다. 각각이 JSON은 말할 수 없는 것을 말하고 있는데, 조용히 하나를 골라 해석하는 변환기는 그 파일이 말한 것이 아닌 문서를 건네주는 셈이니까요. 반대 방향은 잃는 것이 없습니다. 모든 JSON 문서는 이미 YAML 문서입니다.

### JSON을 XML로 바꾸면 무엇을 잃나요?

빈 객체와 빈 배열, 빈 문자열의 차이입니다. 셋 다 빈 요소가 됩니다. 그리고 모든 값의 타입입니다. XML에는 타입이 없기 때문인데, 반대 변환이 `8080`을 숫자라고 판단하는 대신 전부 문자열로 두는 이유이기도 합니다. 배열은 되풀이되는 요소가 되는데, 다시 읽히는 형태가 그것뿐입니다. 요소 이름이 담을 수 없는 키는 어떤 파서도 읽지 않을 문서로 내보내지 않고 곤란한 글자를 바꿔 둡니다.

### HTML을 다시 들여쓰면 페이지 모양이 달라지나요?

달라질 수 있고, 그 점은 정직하게 말씀드립니다. 인라인 요소 둘 사이의 공백은 두 낱말 사이의 공백이라, 그걸 옮기는 것은 공짜가 아닙니다. 그걸 붙들어 두는 장치가 둘 있습니다. `<pre>`와 `<textarea>`는 있던 그대로 복사되고, 글자만 담고 있는 요소는 한 줄에 그대로 남습니다. 그 밖의 것들이 배치됩니다.

### 얼마나 큰 파일까지 다룰 수 있나요?

여기 정해 둔 제한은 없습니다. 그 값을 치를 서버가 없으니까요. 현실적인 한계는 기기 쪽입니다. 몇 메가바이트짜리 JSON은 괜찮고, 아주 긴 문서라면 페이지가 키보드를 두고 다투는 대신 타이핑이 잠시 멎기를 기다렸다가 다시 정렬합니다.

### 무료인가요? 가입해야 하나요?

무료이고 계정도, 로그인도, 체험판도 없으며 붙여 넣는 양에도 제한이 없습니다. 이 사이트는 광고로 유지되는데, 그 광고에도 내 텍스트에 관한 것은 넘어가지 않습니다.

### 오프라인에서도 되나요?

됩니다. 페이지를 한 번 불러온 다음 인터넷을 끊어도 계속 동작합니다. 아무것도 업로드되지 않는다는 가장 간단한 증명이기도 하고요. 텍스트를 어딘가로 보내서 정렬해 오는 도구라면 선을 뽑는 순간 멈춰 버릴 테니까요.

## 이 약속을 직접 확인하는 방법

- **붙여 넣은 것은 나갈 곳이 없습니다.** 이 페이지가 연결해도 되는 주소는 Content-Security-Policy에 모두 적혀 있는데, 그중 이 사이트 것은 하나도 없습니다. 붙여 넣은 토큰이 모일 만한 수신 지점이 없고, 설령 있더라도 거기로 무언가를 보낼 코드가 없습니다.
- **여기서는 아무것도 가져오지 않습니다.** `src/` 어디에도 `fetch`도, `XMLHttpRequest`도, `sendBeacon`도 없습니다. 모든 파서와 모든 프린터는 문자열을 받아 문자열을 돌려주는 이 페이지 안의 함수입니다.
- **포매터는 받은 것을 그대로 지킵니다.** JSON 객체는 쓰신 순서대로 키를 달고, 적으신 대로 숫자를 적은 채 돌아옵니다. `src/shared/parse-json.js`가 `JSON.parse` 호출이 아니라 직접 쓴 파서이기 때문입니다. `JSON.parse`는 정수처럼 생긴 키의 순서를 바꾸고 스무 자리 id를 가장 가까운 배정밀도 수로 만들어 버립니다. `tests/js/text-format.test.js`의 테스트가 정확히 그것을 확인합니다.
- **구글이 불러오는 것과, 구글에게 주지 않는 것.** 광고와 측정 스크립트는 구글에서, 후원 버튼은 Buy Me a Coffee에서 옵니다. 어느 쪽에도 내 텍스트는 한 글자도 넘어가지 않습니다. 그것을 읽고 해석하고 쓰는 코드는 한 줄도 빠짐없이 이 출처에서 제공되고 저장소에 공개되어 있습니다.
- **오프라인에서도 동작합니다.** 네트워크를 끊어도 도구는 그대로입니다. 애초에 네트워크를 쓰는 단계가 없었으니까요. 가장 간단한 증거입니다.

**직접 확인해 보세요.** 위에 적은 어느 것도 그냥 믿으실 필요는 없습니다. 이 페이지는 저장소 안의 템플릿과 설정을 빌드 스크립트가 찍어 낸 결과이고, 그 스크립트는 누구나 읽고 직접 돌려 볼 수 있습니다. 결과물은 `dist` 브랜치에 그대로 올라가 있고요. 그래서 실제로 제공되는 파일과 소스를 빌드한 결과를 나란히 놓고 비교해 보실 수 있습니다: https://github.com/A-Box-of-Tools/website

먼저 읽어 볼 파일을 꼽자면, Content-Security-Policy는 `config/site.toml`, 쓴 순서 그대로 키를 지키는 파서는 `src/shared/parse-json.js`에 있습니다. 변환이 왜 파서 하나와 프린터 하나로 이루어지고 그 사이에 두 형식을 동시에 아는 것이 하나도 없는지는 `src/convert.js`를 보시면 됩니다.
