Skip to content
Astera Technology

Why does a shortened label end with half an emoji?

Apply the supplied code-point limit without splitting a surrogate pair.

Download complete case notes and answer keys ↓

Read the source and its declared rule

The original clipping rule permits two code points from A😀B. JavaScript slice counts UTF-16 code units; its cut after two units leaves A plus a lone surrogate. Iterating the supplied valid Unicode scalar text before cutting keeps A😀. This rule counts code points, not user-perceived grapheme clusters.

Filled synthetic input
RecordInput JSON
Base input{"text":"A😀B","limit":2}
Download editable CSV ↓

Compare the actual paths

Correct output has code points 65 and 128512, retaining the source label separately. The malformed bad suffix has surrogate code 55357 instead.

Misleading and corrected outputs
PathOutput JSON
Misleading path{"text":"A\ud83d","codePoints":[65,55357],"source":"A😀B"}
Corrected path{"text":"A😀","codePoints":[65,128512],"source":"A😀B"}
Download editable CSV ↓
Local Node.js program: 22.23.3 or 24.14.1
import {DatabaseSync} from 'node:sqlite';
import {TextDecoder} from 'node:util';
import {inflateSync} from 'node:zlib';
import {posix} from 'node:path';
import {createHash} from 'node:crypto';
const rows=(db,sql)=>db.prepare(sql).all().map(r=>({...r}));
const failed=(action)=>{try{action();return null;}catch(e){return {code:e.errcode??e.code??e.name};}};

import assert from 'node:assert/strict';
const run=function run(i,corrected=true){
    if(!Number.isInteger(i.limit)||i.limit<0)return {accepted:false,error:'invalid-limit'};
    const text=corrected?Array.from(i.text).slice(0,i.limit).join(''):i.text.slice(0,i.limit);
    return {text,codePoints:Array.from(text).map(c=>c.codePointAt(0)),source:i.text};
  };
const cases=[{"label":"misleading base","input":{"text":"A😀B","limit":2},"expected":{"text":"A\ud83d","codePoints":[65,55357],"source":"A😀B"},"corrected":false},{"label":"corrected base","input":{"text":"A😀B","limit":2},"expected":{"text":"A😀","codePoints":[65,128512],"source":"A😀B"},"corrected":true},{"label":"zero character allowance","input":{"text":"A😀B","limit":0},"expected":{"text":"","codePoints":[],"source":"A😀B"},"corrected":true},{"label":"exact full character length","input":{"text":"A😀B","limit":3},"expected":{"text":"A😀B","codePoints":[65,128512,66],"source":"A😀B"},"corrected":true}];
for(const test of cases){
  const actual=run(test.input,test.corrected);
  assert.deepEqual(actual,test.expected,test.label);
  console.log(test.label,actual);
}
Download runnable example ↓

Check boundaries before the next load

Limit zero returns empty text. Limit three retains the entire source without a cut.

Editable boundary records and expected outputs
CaseInput JSONExpected output JSON
Zero allowed code points{"text":"A😀B","limit":0}{"text":"","codePoints":[],"source":"A😀B"}
Exact full source length{"text":"A😀B","limit":3}{"text":"A😀B","codePoints":[65,128512,66],"source":"A😀B"}
Download editable CSV ↓

What two-code-point label should be retained?

Show the worked answer

A😀. Preserve the complete supplementary character; A plus half a surrogate is not the required result.

Related resources