[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6CBWATH88SAWX5BFRMC2SVZ":3,"skill-same:01M6CBWATH88SAWX5BFRMC2SVZ":45},{"skillNo":4,"name":5,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":15,"categories":16,"keywords":17,"publishedAt":20,"linkOnly":21,"markdownContent":22,"markdownBody":22,"frontMatter":23,"refName":24,"commitSha":25,"skillDirectory":26,"forksCount":13,"repositoryHtmlUrl":27,"repositoryHomepageUrl":6,"ownerHtmlUrl":28,"ownerBlogUrl":6,"ownerDescription":29,"updatedAt":30,"install":31,"resources":44},"01M6CBWATH88SAWX5BFRMC2SVZ","52-table-enumgen",null,"devwinsoft\u002Fdevian","devwinsoft","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F22570160?v=4","01M6C6RR8W05NH8NPKQNCE3Q72","maoshy","01M6C6RRDJ5TJJCZXRTY801YDH",0,"MIT","https:\u002F\u002Fgithub.com\u002Fdevwinsoft\u002Fdevian\u002Fblob\u002Fmain\u002Fskills\u002Fdevian\u002F80-tools\u002F11-builder\u002F52-table-enumgen\u002FSKILL.md",[],[18,19],"table","52 table enumgen","2026-11-10 10:12:30",false,"# 52-table-enumgen\n\nStatus: ACTIVE  \nAppliesTo: v10  \nSSOT: skills\u002Fdevian\u002F10-module\u002F03-ssot\u002FSKILL.md\n\n## Overview\n\nDATA 테이블(예: XLSX)의 Options Row(3번째 줄)에서 `gen:\u003CEnumName>` 옵션을 선언하면:\n\n1. 해당 컬럼(gen 컬럼)이 **PK 컬럼**이 된다 (gen 컬럼 = PK 컬럼).\n2. 해당 컬럼의 각 row 값이 **enum 멤버 이름(name)** 이 된다.\n3. enum 멤버 값(value)은 **결정적 자동 할당** (이름 오름차순 정렬 후 0부터 순차).\n4. TB 캐시에 `Find(\u003CEnumName> key)` \u002F `TryFind(\u003CEnumName> key)` **헬퍼가 자동 생성**된다.\n\n---\n\n## Terminology\n\n| 용어 | 설명 |\n|------|------|\n| Options Row | XLSX 3번째 줄 (열별 옵션 정의) |\n| Gen Column | `gen:\u003CEnumName>` 옵션이 선언된 컬럼 (= PK 컬럼, enum NAME source) |\n\n---\n\n## Hard Rules (MUST)\n\n### 1. Gen Column = PK Column\n\n- `gen:\u003CEnumName>` 옵션이 붙은 컬럼은 **반드시 `pk`여야 한다**.\n- 즉, gen 컬럼 = PK 컬럼 (같은 컬럼).\n- gen 컬럼에 `pk`가 없으면 빌드 **FAIL**.\n- gen 컬럼은 테이블당 **딱 1개**만 허용한다 (2개 이상 FAIL).\n\n### 2. Enum Member Name = Gen\u002FPK Column Value\n\n- gen\u002FPK 컬럼의 각 row 값이 enum 멤버 이름이 된다.\n- 멤버 이름은 유효한 식별자여야 한다 (`^[A-Za-z_][A-Za-z0-9_]*$`).\n- enum 멤버 이름은 **대문자 SNAKE_CASE**를 사용한다.\n\n### 2.1 Enum Type Name = UPPER_SNAKE_CASE\n\n- `gen:\u003CEnumName>`의 `EnumName`은 **대문자 SNAKE_CASE**를 사용한다.\n- Good: `MISSION_CONDITION_TYPE`, `COMPLEX_POLICY_TYPE`\n- Bad: `MissionConditionType`, `ComplexPolicyType`\n\n### 3. Enum Member Value = Deterministic Auto-Assignment\n\nenum 멤버 값은 **결정적 자동 할당**으로 생성된다:\n\n1. 모든 멤버 이름을 **오름차순(ASCII) 정렬**한다.\n2. 정렬된 순서대로 **0부터 1씩 증가하는 int 값**을 할당한다.\n\n예시:\n```\n테이블 데이터: CriRate, AttackPower, MaxHealth\n정렬 후:       AttackPower, CriRate, MaxHealth\n할당 결과:     AttackPower=0, CriRate=1, MaxHealth=2\n```\n\n### 3.1 Enum Member Value = code(int) (Opt-in)\n\nOptions Row(3번째 줄)에서 gen 컬럼(=PK 컬럼)에 `code` 키워드를 함께 선언하면:\n\n- 예: `pk, gen:SERVER_ERROR_TYPE, code`\n- 이 경우 enum 멤버 value는 0..N-1 자동 할당이 아니라, **같은 row의 `code` 컬럼(int) 값**을 사용한다.\n- 출력 순서는 여전히 **멤버 이름 오름차순(결정적)** 으로 유지한다.\n\nFailure Conditions (MUST fail):\n- `code` 컬럼이 없으면 FAIL\n- `code` 타입이 int가 아니면 FAIL\n- row의 `code`가 비어있으면 FAIL\n- `code` 값이 중복이면 FAIL\n\n### 4. 식별자 규칙 위반은 실패\n\n- gen 컬럼 값(enum 멤버 이름)이 C#\u002FTS 식별자 규칙을 위반하면 빌드 실패한다.\n- 정규식: `^[A-Za-z_][A-Za-z0-9_]*$`\n- 자동 치환(공백→_, 특수문자 제거) 같은 \"추측 기반 보정\"은 **금지**한다.\n\n### 5. 중복은 실패\n\n- enum 멤버 이름(gen 컬럼 값) 중복: **FAIL**\n\n### 6. 결정적 출력\n\n- enum 멤버 나열 순서는 **이름 오름차순**으로 고정한다.\n- 동일 입력에서 동일 출력이 보장되어야 한다.\n\n### 7. Find\u002FTryFind 헬퍼\n\n- `TB_\u003Cn>.Find(\u003CEnumName> key)` \u002F `TryFind(\u003CEnumName> key)` 헬퍼가 생성된다.\n- keyType이 이미 `enum:\u003CEnumName>`인 경우, 중복 오버로드는 생성하지 않는다.\n- Find\u002FTryFind는 gen 테이블에만 생성된다.\n\n---\n\n## Table Authoring Spec\n\n### Required Columns\n\n| 역할 | 컬럼명 | Type (권장) | Options | 설명 |\n|------|--------|-------------|---------|------|\n| PK + Enum Name | (자유) | `enum:\u003CEnumName>` | `pk, gen:\u003CEnumName>` | PK이자 enum 멤버 이름 source |\n\n### Example: TB_COMPLEX_POLICY\n\n```\nRow 1 (Header):    key                      | fallbackValue | minValue | maxValue\nRow 2 (Type):      enum:COMPLEX_POLICY_TYPE   | Variant       | Variant  | Variant\nRow 3 (Options):   pk, gen:COMPLEX_POLICY_TYPE |              |          |\nRow 4 (Comment):   (ignored)\nRow 5+ (Data):     ATTACK_POWER             | i:0           | i:0      | i:10000\n                   CRI_RATE                 | f:0           | f:0      | f:3.5\n                   MAX_HEALTH               | i:100         | i:1      | i:99999\n```\n\n여기서:\n- `key` 컬럼 = PK = gen 컬럼 (같은 컬럼, 옵션: `pk, gen:COMPLEX_POLICY_TYPE`)\n- `key` 컬럼의 값이 enum 멤버 이름\n- enum 값은 자동 할당: `ATTACK_POWER=0`, `CRI_RATE=1`, `MAX_HEALTH=2` (이름 정렬 순)\n- **Variant 컬럼은 NDJSON에서 `{k, i|f|s}` 오브젝트로 저장되며, `i`\u002F`f`\u002F`s`는 Complex shape(CInt\u002FCFloat\u002FCString)이다.**\n\n---\n\n## Output Artifacts\n\n### C# Enum\n\n```csharp\nnamespace Devian.Domain.Common\n{\n    public enum COMPLEX_POLICY_TYPE : int\n    {\n        ATTACK_POWER = 0,\n        CRI_RATE = 1,\n        MAX_HEALTH = 2,\n    }\n}\n```\n\n### C# TB Cache Find\u002FTryFind\n\n```csharp\npublic static class TB_COMPLEX_POLICY\n{\n    \u002F\u002F 기존 Get\u002FTryGet 유지...\n\n    \u002F\u002F Find\u002FTryFind - keyType이 enum이므로 기본 버전만 생성\n    public static Row Find(COMPLEX_POLICY_TYPE key) { ... }\n    public static bool TryFind(COMPLEX_POLICY_TYPE key, out Row? row) { ... }\n}\n```\n\n### TypeScript Enum\n\n```typescript\nexport enum COMPLEX_POLICY_TYPE {\n    ATTACK_POWER = 0,\n    CRI_RATE = 1,\n    MAX_HEALTH = 2,\n}\n```\n\n### TypeScript TB Cache find\u002FtryFind\n\n```typescript\nexport class TB_COMPLEX_POLICY {\n    \u002F\u002F 기존 get\u002FtryGet 유지...\n\n    \u002F\u002F keyType이 enum이므로 기본 버전만\n    static find(key: COMPLEX_POLICY_TYPE): Row { ... }\n    static tryFind(key: COMPLEX_POLICY_TYPE): Row | undefined { ... }\n}\n```\n\n---\n\n## Failure Conditions (Build MUST fail)\n\n| 조건 | 에러 메시지 예시 |\n|------|-----------------|\n| gen 컬럼이 2개 이상 | `[gen:] Table '...': only one gen column allowed per table` |\n| gen 컬럼에 pk가 없음 | `[gen:] Table '...': gen field must be pk (gen column is the PK)` |\n| EnumName이 비어있음 | `[gen:] Table '...': enum name required` |\n| EnumName이 식별자 규칙 위반 | `[gen:] Table '...': invalid enum name '...'` |\n| enum 멤버 이름이 식별자 규칙 위반 | `[gen:] Table '...': invalid member name '...'` |\n| enum 멤버 이름 중복 | `[gen:] Table '...': duplicate member name '...'` |\n| row의 gen 컬럼 값이 비어있음 | `[gen:] Table '...': empty enum member name at row ...` |\n| key:true 또는 key 옵션 사용 | `Option 'key' is not supported. Use 'pk'.` |\n\n---\n\n## DoD (Definition of Done)\n\n- [x] `gen:\u003CEnumName>` 옵션이 Options Row에서 파싱된다\n- [x] gen 컬럼은 반드시 `pk`여야 한다 (gen = PK)\n- [x] gen\u002FPK 컬럼 값이 enum 멤버 이름으로 사용된다\n- [x] enum 멤버 값이 이름 정렬 + 0..N-1 자동 할당된다\n- [x] enum 코드(C#\u002FTS)가 생성된다\n- [x] enum 멤버 순서가 이름 오름차순으로 결정적이다\n- [x] TB 캐시에 Find\u002FTryFind 헬퍼가 생성된다 (gen 테이블만)\n- [x] keyType이 enum이면 중복 오버로드를 생성하지 않는다\n- [x] 식별자 위반\u002F중복 시 빌드가 실패한다\n- [x] key:true 또는 key 옵션 사용 시 빌드가 실패한다\n- [x] 기존 테이블(gen 미사용)은 영향 없다\n\n---\n\n## Reference\n\n- Table Authoring Rules: `skills\u002Fdevian\u002F80-tools\u002F11-builder\u002F32-table-authoring\u002FSKILL.md`\n- TableGen Implementation: `skills\u002Fdevian\u002F80-tools\u002F11-builder\u002F51-table-codegen\u002FSKILL.md`\n- Variant Feature: `skills\u002Fdevian\u002F10-module\u002F20-core\u002F32-variable-variant\u002FSKILL.md`\n",{},"main","8cb5bd877a3a7004867d2f55697cb9e4ff2f1734","skills\u002Fdevian\u002F80-tools\u002F11-builder\u002F52-table-enumgen","https:\u002F\u002Fgithub.com\u002Fdevwinsoft\u002Fdevian","https:\u002F\u002Fgithub.com\u002Fdevwinsoft","Kim Hyong Joon","2026-04-12 18:44:10",{"source":7,"skillName":5,"commands":32,"prompt":42,"zipAvailable":43},[33,36,39],{"tool":34,"command":35},"npx","npx skills add devwinsoft\u002Fdevian --skill 52-table-enumgen",{"tool":37,"command":38},"bunx","bunx skills add devwinsoft\u002Fdevian --skill 52-table-enumgen",{"tool":40,"command":41},"pnpm","pnpm dlx skills add devwinsoft\u002Fdevian --skill 52-table-enumgen","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fdevwinsoft\u002Fdevian\u002Fblob\u002Fmain\u002Fskills\u002Fdevian\u002F80-tools\u002F11-builder\u002F52-table-enumgen\u002FSKILL.md",true,[],[46,52,60,68,77,84],{"skillNo":47,"name":48,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":49,"categories":50,"keywords":51,"publishedAt":20},"01M6CBX3K2JJV38ANHVGCAT8A0","devian","https:\u002F\u002Fgithub.com\u002Fdevwinsoft\u002Fdevian\u002Fblob\u002Fmain\u002Fskills\u002Fdevian\u002FSKILL.md",[],[48],{"skillNo":53,"name":54,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":55,"categories":56,"keywords":57,"publishedAt":20},"01M6CBX210BFMM8AMN770J9WY8","90-project-archive","https:\u002F\u002Fgithub.com\u002Fdevwinsoft\u002Fdevian\u002Fblob\u002Fmain\u002Fskills\u002Fdevian\u002F80-tools\u002F90-project-archive\u002FSKILL.md",[],[58,59],"archive","90 project archive",{"skillNo":61,"name":62,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":63,"categories":64,"keywords":65,"publishedAt":20},"01M6CBWZSGRR9R3YJZB3177667","30-env-management","https:\u002F\u002Fgithub.com\u002Fdevwinsoft\u002Fdevian\u002Fblob\u002Fmain\u002Fskills\u002Fdevian\u002F80-tools\u002F30-env-management\u002FSKILL.md",[],[66,67],"management","30 env management",{"skillNo":69,"name":70,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":71,"categories":72,"keywords":73,"publishedAt":20},"01M6CBWYD3TGWBQV7V35551THF","19-page-push-send","https:\u002F\u002Fgithub.com\u002Fdevwinsoft\u002Fdevian\u002Fblob\u002Fmain\u002Fskills\u002Fdevian\u002F80-tools\u002F20-operation\u002F19-page-push-send\u002FSKILL.md",[],[74,75,76],"push","page","19 page push send",{"skillNo":78,"name":79,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":80,"categories":81,"keywords":82,"publishedAt":20},"01M6CBWWRQ05A7604GHJKTPJTF","18-page-savedata","https:\u002F\u002Fgithub.com\u002Fdevwinsoft\u002Fdevian\u002Fblob\u002Fmain\u002Fskills\u002Fdevian\u002F80-tools\u002F20-operation\u002F18-page-savedata\u002FSKILL.md",[],[75,83],"18 page savedata",{"skillNo":85,"name":86,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":87,"categories":88,"keywords":89,"publishedAt":20},"01M6CBWVH4S2VF1V7B2GBTESCT","17-page-deobfuscate","https:\u002F\u002Fgithub.com\u002Fdevwinsoft\u002Fdevian\u002Fblob\u002Fmain\u002Fskills\u002Fdevian\u002F80-tools\u002F20-operation\u002F17-page-deobfuscate\u002FSKILL.md",[],[75,90],"17 page deobfuscate"]