sellmate-design-system-react 3.2.0 → 3.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,21 +4,57 @@
4
4
  */
5
5
 
6
6
  /**
7
- * 오른쪽 정렬 대상 — 숫자가 들어가는 모든 컬럼.
8
- * 식별자(주문번호·상품코드)도 숫자라 자릿수를 맞춰야 하므로 포함한다.
7
+ * 오른쪽 정렬·세 자리 콤마 대상 — 값의 "크기"를 비교하는 수량 컬럼.
8
+ *
9
+ * 식별자(주문번호·상품코드)는 자릿수가 있어도 대소를 비교하지 않으므로 뺀다.
10
+ * 우측 정렬의 근거가 "자릿수를 세로로 맞춰 크기를 읽는다"이고,
11
+ * 송장번호 `123456789` 에 콤마를 넣으면 `123,456,789` 라는 오표시가 된다.
9
12
  */
10
13
  export const NUMERIC_LABEL =
11
- /금액|가격|단가|판매가|원가|비용|수수료|배송비|할인|합계|총액|잔액|포인트|적립|수량|재고|개수|건수|횟수|비율|퍼센트|평점|점수|무게|용량|길이|면적|번호|코드|순번|순위|나이|연차/;
14
+ /금액|가격|단가|판매가|원가|비용|수수료|배송비|할인|합계|총액|잔액|포인트|적립|수량|재고|개수|건수|횟수|비율|퍼센트|평점|점수|무게|용량|길이|면적|나이|연차/;
12
15
 
13
16
  /**
14
- * 하이픈 등 서식이 들어간 문자열 숫자가 아니므로 정렬·서식 규칙 모두 대상이 아니다.
15
- * (전화번호 010-1234-5678, 사업자번호 123-45-67890)
17
+ * 식별자숫자로 이루어져 있어도 크기 비교 대상이 아니다.
18
+ * 정렬·서식 규칙 모두에서 뺀다.
19
+ *
20
+ * (전화번호 010-1234-5678, 사업자번호 123-45-67890, 송장번호 123456789)
21
+ *
22
+ * `주문`·`오더` 같은 도메인 접두어는 넣지 않는다 — `주문 금액`·`오더 합계` 처럼
23
+ * 실제 수량 컬럼까지 함께 빠진다. 식별자 쪽은 뒤에 붙는 `번호`·`코드` 로 잡힌다.
16
24
  */
17
- export const IDENTIFIER_ONLY = /전화|휴대폰|연락처|사업자|주민|계좌|우편/;
25
+ export const IDENTIFIER_ONLY =
26
+ /전화|휴대폰|연락처|사업자|주민|계좌|우편|번호|코드|순번|순위|송장|운송장|전표|슬립|정산서|바코드|SKU|사번|일련/;
27
+
28
+ /**
29
+ * 일자·일시 — 서식이 정해진 값이라 우측 정렬도 세 자리 콤마도 대상이 아니다 (§3-4 중앙 정렬).
30
+ * `format` 에 `Number(` 가 섞여도 숫자로 되살아나지 않게 따로 뺀다.
31
+ */
32
+ export const DATE_LABEL = /일자|일시|날짜|기간|시각|등록일|수정일|생성일|만료일/;
33
+
34
+ /**
35
+ * 상태·구분 컬럼 — 수량 어휘를 부분 문자열로 포함해도 값은 숫자가 아니다.
36
+ * (`비용 입력 여부` 가 `비용` 에 걸리는 것을 막는다)
37
+ */
38
+ export const NON_NUMERIC_SUFFIX = /(여부|유무|상태|구분|타입|종류|명|이름)$/;
18
39
 
19
40
  /** format 본문에 숫자 서식이 있으면 숫자 컬럼으로 본다 */
20
41
  export const NUMERIC_FORMAT = /toLocaleString|toFixed|Number\s*\(|parseInt|parseFloat/;
21
42
 
43
+ /**
44
+ * 셀을 우측 정렬하는 클래스.
45
+ * `align` 은 헤더·셀에 공통 적용되므로 "헤더 가운데 + 셀 우측" 은 `tdClass` 로만 표현된다.
46
+ */
47
+ export const CELL_RIGHT_CLASS = /\btext-right\b/;
48
+
49
+ /**
50
+ * 수량 판정에서 아예 빼야 하는 라벨인지 — 식별자·일자·상태/구분 컬럼.
51
+ * 라벨 분기·format 분기보다 먼저 확인해야 한다.
52
+ * (`사업자번호` 처럼 식별자여도 format 에 `Number(` 가 있으면 숫자로 되돌아간다)
53
+ */
54
+ export function isNonQuantityLabel(label) {
55
+ return IDENTIFIER_ONLY.test(label) || DATE_LABEL.test(label) || NON_NUMERIC_SUFFIX.test(label);
56
+ }
57
+
22
58
  /** 객체 리터럴에서 프로퍼티 노드를 이름으로 찾는다 */
23
59
  export function prop(objectNode, name) {
24
60
  return objectNode.properties.find(
@@ -1,14 +1,15 @@
1
1
  /**
2
2
  * 숫자 컬럼은 예외 없이 `toLocaleString()` 으로 세 자리 콤마를 넣도록 강제한다.
3
3
  *
4
- * 전화번호·사업자번호처럼 하이픈이 들어가는 값은 숫자가 아니라 서식이 정해진
5
- * 문자열이므로 대상에서 뺀다. 밖에 예외가 필요하면 `allow` 로 컬럼을 지정한다.
4
+ * 전화번호·송장번호처럼 식별자로 쓰이는 값은 크기를 비교하는 숫자가 아니라
5
+ * 서식이 정해진 문자열이므로 대상에서 뺀다 (§5 체크리스트 "번호·코드는 제외").
6
+ * 그 밖에 예외가 필요하면 `allow` 로 컬럼을 지정한다.
6
7
  *
7
8
  * AGENTS.md §1-4 / §3-4.
8
9
  */
9
10
  import {
10
11
  NUMERIC_LABEL,
11
- IDENTIFIER_ONLY,
12
+ isNonQuantityLabel,
12
13
  prop,
13
14
  asColumn,
14
15
  } from "../lib/table-column.mjs";
@@ -48,11 +49,12 @@ export default {
48
49
  const { labelProp, label, columnName } = column;
49
50
  if (columnName && allow.has(columnName)) return;
50
51
 
51
- // 숫자 컬럼이면 모두 대상 — 하이픈 서식 문자열(전화번호 등)만 뺀다
52
- if (!NUMERIC_LABEL.test(label) || IDENTIFIER_ONLY.test(label)) return;
52
+ // 수량 컬럼이면 모두 대상 — 식별자(전화번호·송장번호)와 상태 컬럼은 뺀다
53
+ if (!NUMERIC_LABEL.test(label) || isNonQuantityLabel(label)) return;
53
54
 
54
- // render 로 셀을 직접 그리는 경우는 이 규칙이 판단하지 않는다
55
- if (prop(node, "render")) return;
55
+ // render / renderCell 로 셀을 직접 그리는 경우는 이 규칙이 판단하지 않는다
56
+ // (renderCell 은 3.x STable 의 `<td>` 커스텀 렌더 — 2.2.0 에서 추가됐다)
57
+ if (prop(node, "render") || prop(node, "renderCell")) return;
56
58
 
57
59
  const unit = /금액|가격|단가|판매가|원가|비용|수수료|배송비|할인|합계|총액|잔액/.test(label)
58
60
  ? "원"
@@ -3,6 +3,7 @@
3
3
  *
4
4
  * 자릿수가 세로로 맞아야 값의 크기를 비교할 수 있으므로,
5
5
  * 금액·수량·개수처럼 숫자가 들어가는 컬럼은 예외 없이 오른쪽 정렬한다.
6
+ * 크기를 비교하지 않는 식별자(주문번호·상품코드)는 대상이 아니다.
6
7
  *
7
8
  * 대상은 `name` · `label` · `field` 를 모두 가진 객체 리터럴(= STableColumn 형태)뿐이라
8
9
  * 일반 객체를 오탐하지 않는다.
@@ -12,8 +13,9 @@
12
13
 
13
14
  import {
14
15
  NUMERIC_LABEL,
15
- IDENTIFIER_ONLY,
16
16
  NUMERIC_FORMAT,
17
+ CELL_RIGHT_CLASS,
18
+ isNonQuantityLabel,
17
19
  prop,
18
20
  literalString,
19
21
  asColumn,
@@ -53,13 +55,18 @@ export default {
53
55
  const { labelProp, label, columnName } = column;
54
56
  if (columnName && allow.has(columnName)) return;
55
57
 
58
+ // 식별자(송장번호)·상태 컬럼(비용 입력 여부)은 크기를 비교하지 않는다.
59
+ // label·format 두 분기보다 먼저 빼야 format 의 `Number(` 로 되살아나지 않는다.
60
+ if (isNonQuantityLabel(label)) return;
61
+
62
+ // render/renderCell 로 셀을 직접 그리면 라벨만으로 숫자 여부를 알 수 없다
63
+ // (`정산서 번호` → 링크, `순번` → 핀 아이콘). 실제 숫자 서식이 있을 때만 숫자로 본다.
64
+ const renderProp = prop(node, "renderCell") ?? prop(node, "render");
65
+ if (renderProp && !NUMERIC_FORMAT.test(context.sourceCode.getText(renderProp))) return;
66
+
56
67
  // 숫자 판정 — label 키워드 또는 format 의 숫자 서식
57
68
  let reason = "";
58
- let numeric = false;
59
-
60
- if (NUMERIC_LABEL.test(label) && !IDENTIFIER_ONLY.test(label)) {
61
- numeric = true;
62
- }
69
+ let numeric = NUMERIC_LABEL.test(label);
63
70
 
64
71
  const formatProp = prop(node, "format");
65
72
  if (formatProp) {
@@ -75,6 +82,10 @@ export default {
75
82
  const alignProp = prop(node, "align");
76
83
  if (literalString(alignProp) === "right") return;
77
84
 
85
+ // align 은 헤더·셀 공통이라 "헤더 가운데 + 셀 우측" 은 tdClass 로만 표현된다
86
+ const tdClassProp = prop(node, "tdClass");
87
+ if (tdClassProp && CELL_RIGHT_CLASS.test(context.sourceCode.getText(tdClassProp))) return;
88
+
78
89
  context.report({
79
90
  node: alignProp ?? labelProp,
80
91
  messageId: "needsRight",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sellmate-design-system-react",
3
- "version": "3.2.0",
3
+ "version": "3.3.1",
4
4
  "description": "Sellmate Design System — React (TypeScript + Tailwind v4) port",
5
5
  "license": "UNLICENSED",
6
6
  "keywords": [