Function bodies 942 total
normalizeUser function · typescript · L26-L50 (25 LOC)snipxn_app/src/api/user.ts
function normalizeUser(raw: Record<string, unknown>): User {
const now = new Date().toISOString();
const createdAt = normalizeNullableString(raw.createdAt) ?? now;
const updatedAt = normalizeNullableString(raw.updatedAt) ?? createdAt;
return {
id: String(raw.id ?? ''),
email: normalizeNullableString(raw.email) ?? '',
nickname: normalizeNullableString(raw.nickname),
avatar: normalizeNullableString(raw.avatar),
bio: normalizeNullableString(raw.bio),
gender: normalizeNumber(raw.gender, 0),
birthday: normalizeNullableString(raw.birthday),
website: normalizeNullableString(raw.website),
github: normalizeNullableString(raw.github),
location: normalizeNullableString(raw.location),
company: normalizeNullableString(raw.company),
techStack: normalizeNullableString(raw.techStack),
storageLimit: normalizeNumber(raw.storageLimit, 0),
storageUsed: normalizeNumber(raw.storageUsed, 0),
status: normalizeStatus(raw.status),
createdAgetMe function · typescript · L52-L55 (4 LOC)snipxn_app/src/api/user.ts
export async function getMe(): Promise<User> {
const data = await apiClient.get<Record<string, unknown>>(USER_BASE_URL);
return normalizeUser(data);
}updateMe function · typescript · L57-L60 (4 LOC)snipxn_app/src/api/user.ts
export async function updateMe(data: UpdateMeRequest): Promise<User> {
const response = await apiClient.put<Record<string, unknown>, UpdateMeRequest>(USER_BASE_URL, data);
return normalizeUser(response);
}changePassword function · typescript · L62-L66 (5 LOC)snipxn_app/src/api/user.ts
export function changePassword(password: string): Promise<void> {
return apiClient.put<void, ChangePasswordRequest>(`${USER_BASE_URL}/password`, {
password,
});
}normalizeDevice function · typescript · L68-L78 (11 LOC)snipxn_app/src/api/user.ts
function normalizeDevice(raw: Record<string, unknown>): UserDevice {
return {
id: String(raw.id ?? raw.deviceId ?? ''),
deviceName: normalizeNullableString(raw.deviceName),
deviceId: String(raw.deviceId ?? ''),
lastLoginIp: normalizeNullableString(raw.lastLoginIp),
lastLoginAt: normalizeNullableString(raw.lastLoginAt) ?? new Date().toISOString(),
isRevoked: raw.isRevoked === true,
createdAt: normalizeNullableString(raw.createdAt) ?? new Date().toISOString(),
};
}getDevices function · typescript · L80-L83 (4 LOC)snipxn_app/src/api/user.ts
export async function getDevices(): Promise<UserDevice[]> {
const data = await apiClient.get<Record<string, unknown>[]>(`${USER_BASE_URL}/devices`);
return Array.isArray(data) ? data.map(normalizeDevice) : [];
}revokeDevice function · typescript · L85-L87 (3 LOC)snipxn_app/src/api/user.ts
export function revokeDevice(deviceId: string): Promise<void> {
return apiClient.delete<void>(`${USER_BASE_URL}/devices/${deviceId}`);
}Source: Repobility analyzer · https://repobility.com
revokeOtherDevices function · typescript · L89-L91 (3 LOC)snipxn_app/src/api/user.ts
export function revokeOtherDevices(): Promise<void> {
return apiClient.delete<void>(`${USER_BASE_URL}/devices`);
}getLinkedAccounts function · typescript · L93-L95 (3 LOC)snipxn_app/src/api/user.ts
export function getLinkedAccounts(): Promise<LinkedAccount[]> {
return apiClient.get<LinkedAccount[]>(`${USER_BASE_URL}/linked-accounts`);
}bindGithub function · typescript · L97-L105 (9 LOC)snipxn_app/src/api/user.ts
export function bindGithub(code: string, redirectUri: string): Promise<void> {
return apiClient.post<void, OAuthBindRequest>(
`${USER_BASE_URL}/linked-accounts/github`,
{
code,
redirectUri,
},
);
}bindGoogle function · typescript · L107-L115 (9 LOC)snipxn_app/src/api/user.ts
export function bindGoogle(code: string, redirectUri: string): Promise<void> {
return apiClient.post<void, OAuthBindRequest>(
`${USER_BASE_URL}/linked-accounts/google`,
{
code,
redirectUri,
},
);
}unlinkAccount function · typescript · L117-L121 (5 LOC)snipxn_app/src/api/user.ts
export function unlinkAccount(
identityType: LinkedAccount['identityType'],
): Promise<void> {
return apiClient.delete<void>(`${USER_BASE_URL}/linked-accounts/${identityType}`);
}AdaptiveLayout function · typescript · L21-L71 (51 LOC)snipxn_app/src/components/common/AdaptiveLayout.tsx
export function AdaptiveLayout({
renderSidebar,
renderList,
renderContent,
sidebarWidth = DEFAULT_SIDEBAR_WIDTH,
listWidth = DEFAULT_LIST_WIDTH,
}: AdaptiveLayoutProps) {
const { showSidebar, showMasterDetail } = useDeviceType();
const { palette } = useAppTheme();
const shouldRenderSidebarPane = showMasterDetail && sidebarWidth > 0;
if (!showSidebar) {
return (
<Animated.View layout={APP_LAYOUT_TRANSITION} style={{ flex: 1, minWidth: 0 }}>
{renderList()}
</Animated.View>
);
}
if (!showMasterDetail || !shouldRenderSidebarPane) {
return (
<MasterDetail
masterWidth={listWidth}
renderMaster={renderList}
renderDetail={renderContent}
showDetail
/>
);
}
return (
<Animated.View
layout={APP_LAYOUT_TRANSITION}
style={{ flex: 1, minWidth: 0, flexDirection: 'row', backgroundColor: palette.canvas }}>
<Animated.View
layout={APP_LAYOUT_TRANSITION}
style={{getPanelBackground function · typescript · L21-L38 (18 LOC)snipxn_app/src/components/common/AppChrome.tsx
function getPanelBackground(
variant: NonNullable<GlassPanelProps['variant']>,
palette: ReturnType<typeof useAppTheme>['palette'],
) {
if (variant === 'strong') {
return palette.panelStrong;
}
if (variant === 'subtle') {
return palette.panelSubtle;
}
if (variant === 'inset') {
return palette.panelInset;
}
return palette.panelRaised;
}AppCanvas function · typescript · L40-L113 (74 LOC)snipxn_app/src/components/common/AppChrome.tsx
export function AppCanvas({
children,
className = 'flex-1',
style,
decorative = true,
}: CanvasProps) {
const { isTablet, palette } = useAppTheme();
return (
<View className={className} style={[{ backgroundColor: palette.canvas }, style]}>
{decorative ? (
<View pointerEvents="none" style={StyleSheet.absoluteFill}>
<View
style={[
styles.blob,
{
width: isTablet ? 320 : 240,
height: isTablet ? 320 : 240,
top: isTablet ? -84 : -72,
left: isTablet ? -88 : -64,
backgroundColor: palette.backdropPrimary,
},
]}
/>
<View
style={[
styles.blob,
{
width: isTablet ? 280 : 210,
height: isTablet ? 280 : 210,
top: isTablet ? -32 : -20,
right: isTablet ? -60 : -40,
backgroundColor: Repobility · open methodology · https://repobility.com/research/
GlassPanel function · typescript · L115-L144 (30 LOC)snipxn_app/src/components/common/AppChrome.tsx
export function GlassPanel({
children,
className = '',
style,
variant = 'raised',
highlight = null,
}: GlassPanelProps) {
const { theme, palette } = useAppTheme();
const shadowOpacity =
variant === 'raised' ? (theme === 'dark' ? 0.26 : 0.12) : theme === 'dark' ? 0.18 : 0.08;
return (
<View
className={`overflow-hidden rounded-[12px] border ${className}`.trim()}
style={[
{
borderColor: highlight ? withAlpha(highlight, 0.22) : palette.border,
backgroundColor: getPanelBackground(variant, palette),
shadowColor: palette.shadow,
shadowOpacity,
shadowRadius: variant === 'raised' ? 18 : 12,
shadowOffset: { width: 0, height: variant === 'raised' ? 12 : 8 },
elevation: variant === 'raised' ? 10 : 5,
},
style,
]}>
{children}
</View>
);
}IconBadge function · typescript · L146-L177 (32 LOC)snipxn_app/src/components/common/AppChrome.tsx
export function IconBadge({
icon,
size = 46,
iconSize = 20,
color,
backgroundColor,
round = false,
}: {
icon: AppIconName;
size?: number;
iconSize?: number;
color?: string;
backgroundColor?: string;
round?: boolean;
}) {
const { palette } = useAppTheme();
const resolvedColor = color ?? palette.primary;
const resolvedBackgroundColor = backgroundColor ?? palette.primarySoft;
return (
<View
className="items-center justify-center"
style={{
width: size,
height: size,
borderRadius: round ? size / 2 : Math.max(8, size * 0.22),
backgroundColor: resolvedBackgroundColor,
}}>
<AppIcon color={resolvedColor} name={icon} size={iconSize} />
</View>
);
}SectionEyebrow function · typescript · L179-L187 (9 LOC)snipxn_app/src/components/common/AppChrome.tsx
export function SectionEyebrow({ children }: { children: ReactNode }) {
const { palette, typography } = useAppTheme();
return (
<Text className={typography.caption} style={{ color: palette.primary }}>
{children}
</Text>
);
}MetricPill function · typescript · L189-L211 (23 LOC)snipxn_app/src/components/common/AppChrome.tsx
export function MetricPill({
label,
tone = 'default',
}: {
label: string;
tone?: 'default' | 'accent' | 'cta';
}) {
const { palette, typography } = useAppTheme();
const toneColor = tone === 'accent' ? palette.accent : tone === 'cta' ? palette.cta : palette.textMuted;
return (
<View
className="rounded-full border px-3.5 py-2"
style={{
borderColor: withAlpha(toneColor, 0.16),
backgroundColor: tone === 'default' ? palette.panelInset : withAlpha(toneColor, 0.12),
}}>
<Text className={typography.caption} style={{ color: tone === 'default' ? palette.textMuted : toneColor }}>
{label}
</Text>
</View>
);
}MetricCard function · typescript · L213-L232 (20 LOC)snipxn_app/src/components/common/AppChrome.tsx
export function MetricCard({
value,
label,
}: {
value: string | number;
label: string;
}) {
const { palette, typography } = useAppTheme();
return (
<GlassPanel className="min-w-[84px] px-3.5 py-3" variant="inset">
<Text className={typography.h3} style={{ color: palette.text }}>
{value}
</Text>
<Text className={typography.caption} style={{ color: palette.textSoft }}>
{label}
</Text>
</GlassPanel>
);
}AppIcon function · typescript · L60-L397 (338 LOC)snipxn_app/src/components/common/AppIcon.tsx
export function AppIcon({
name,
size = 20,
color = 'currentColor',
strokeWidth = 1.9,
filled = false,
}: AppIconProps) {
const commonProps = {
fill: 'none',
stroke: color,
strokeLinecap: 'round' as const,
strokeLinejoin: 'round' as const,
strokeWidth,
};
const effectiveFilled =
filled || name === 'star-filled' || name === 'heart-filled' || name === 'bookmark-filled';
return (
<Svg height={size} viewBox="0 0 24 24" width={size}>
{name === 'search' ? (
<>
<Circle cx="11" cy="11" r="7" {...commonProps} />
<Line x1="20" x2="16.65" y1="20" y2="16.65" {...commonProps} />
</>
) : null}
{name === 'plus' ? (
<>
<Line x1="12" x2="12" y1="5" y2="19" {...commonProps} />
<Line x1="5" x2="19" y1="12" y2="12" {...commonProps} />
</>
) : null}
{name === 'sparkles' ? (
<>
<Path d="M12 3l1.4 4.1L17.5 8.5l-4.1 1.4L12 14l-1.4-4.1L6.5 8.5lEllipseFallback function · typescript · L399-L420 (22 LOC)snipxn_app/src/components/common/AppIcon.tsx
function EllipseFallback({
color,
strokeWidth,
y,
}: {
color: string;
strokeWidth: number;
y: string;
}) {
return (
<>
<Path
d={`M5 ${y}c0 1.7 3.1 3 7 3s7-1.3 7-3-3.1-3-7-3-7 1.3-7 3z`}
fill="none"
stroke={color}
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={strokeWidth}
/>
</>
);
}MotionPressable function · typescript · L55-L96 (42 LOC)snipxn_app/src/components/common/AppMotion.tsx
export function MotionPressable({
children,
className,
pressedScale = 0.975,
style,
onPressIn,
onPressOut,
...props
}: MotionPressableProps) {
const scale = useSharedValue(1);
const animatedStyle = useAnimatedStyle(() => {
'worklet';
return {
transform: [{ scale: scale.value }],
};
});
const handlePressIn = (event: GestureResponderEvent) => {
scale.value = withSpring(pressedScale, PRESS_SPRING_CONFIG);
onPressIn?.(event);
};
const handlePressOut = (event: GestureResponderEvent) => {
scale.value = withSpring(1, PRESS_SPRING_CONFIG);
onPressOut?.(event);
};
return (
<Animated.View style={animatedStyle}>
<Pressable
{...props}
className={className}
onPressIn={handlePressIn}
onPressOut={handlePressOut}
style={style}>
{children}
</Pressable>
</Animated.View>
);
}Repobility (the analyzer behind this table) · https://repobility.com
MasterDetail function · typescript · L19-L55 (37 LOC)snipxn_app/src/components/common/MasterDetail.tsx
export function MasterDetail({
masterWidth = DEFAULT_MASTER_WIDTH,
renderMaster,
renderDetail,
showDetail,
}: MasterDetailProps) {
const { showMasterDetail, showSidebar } = useDeviceType();
const { palette } = useAppTheme();
if (!showSidebar || !showDetail) {
return (
<Animated.View layout={APP_LAYOUT_TRANSITION} style={{ flex: 1, minWidth: 0 }}>
{renderMaster()}
</Animated.View>
);
}
const resolvedMasterWidth = showMasterDetail
? masterWidth
: Math.min(masterWidth, NARROW_MASTER_MAX_WIDTH);
return (
<Animated.View
layout={APP_LAYOUT_TRANSITION}
style={{ flex: 1, minWidth: 0, flexDirection: 'row', backgroundColor: palette.canvas }}>
<Animated.View
layout={APP_LAYOUT_TRANSITION}
style={{ minWidth: 0, flexShrink: 0, width: resolvedMasterWidth }}>
{renderMaster()}
</Animated.View>
<Animated.View layout={APP_LAYOUT_TRANSITION} style={{ width: 1, backgroundColor: palette.bordCommentItem function · typescript · L142-L241 (100 LOC)snipxn_app/src/components/community/CommentItem.tsx
export function CommentItem({
comment,
replies,
currentUserId,
isLoadingReplies = false,
onPressUser,
onReply,
onDelete,
onToggleLike,
onLoadReplies,
}: CommentItemProps) {
const { typography } = useAppTheme();
const { isEnglish, t } = useI18n();
const [repliesVisible, setRepliesVisible] = useState(false);
const [showAllReplies, setShowAllReplies] = useState(false);
const totalReplies = Math.max(comment.replyCount ?? 0, replies.length);
const visibleReplies = useMemo(
() => (showAllReplies ? replies : replies.slice(0, MAX_VISIBLE_REPLIES)),
[replies, showAllReplies],
);
const hasMoreReplies = totalReplies > MAX_VISIBLE_REPLIES || replies.length > MAX_VISIBLE_REPLIES;
const handleExpandAll = () => {
if (totalReplies > replies.length) {
onLoadReplies(comment.id);
}
setShowAllReplies(true);
};
const handleCollapseAll = () => {
setRepliesVisible(false);
setShowAllReplies(false);
};
const handleExpandReplies =CommentSection function · typescript · L23-L249 (227 LOC)snipxn_app/src/components/community/CommentSection.tsx
export function CommentSection({
postId,
headerComponent = null,
onPressUser,
onReply,
}: CommentSectionProps) {
const { palette, typography } = useAppTheme();
const { t } = useI18n();
const currentUserId = useAuthStore(state => state.user?.id ?? null);
const { comments, loading, fetchComments, fetchReplies, deleteComment, likeComment, unlikeComment } = useCommunityStore(useShallow(state => ({
comments: state.comments,
loading: state.loading,
fetchComments: state.fetchComments,
fetchReplies: state.fetchReplies,
deleteComment: state.deleteComment,
likeComment: state.likeComment,
unlikeComment: state.unlikeComment,
})));
const [page, setPage] = useState(1);
const [hasMore, setHasMore] = useState(true);
const [loadingMore, setLoadingMore] = useState(false);
const [loadingReplyId, setLoadingReplyId] = useState<string | null>(null);
const [feedback, setFeedback] = useState<string | null>(null);
const topLevelComments = useMemo(
CommunityActionPill function · typescript · L32-L66 (35 LOC)snipxn_app/src/components/community/CommunityActionPill.tsx
export function CommunityActionPill({
icon,
label,
active = false,
activeIcon,
color,
disabled = false,
size = 'sm',
onPress,
}: CommunityActionPillProps) {
const { palette, typography } = useAppTheme();
const iconName = active && activeIcon ? activeIcon : icon;
const tintColor = active ? color : palette.textMuted;
return (
<MotionPressable
accessibilityRole="button"
className={`rounded-full border ${SIZE_CLASS_NAME[size]}`}
disabled={disabled}
pressedScale={disabled ? 1 : 0.96}
onPress={onPress}
style={{
borderColor: active ? withAlpha(color, 0.28) : palette.border,
backgroundColor: active ? withAlpha(color, 0.12) : palette.surfaceAlt,
opacity: disabled ? 0.6 : 1,
}}>
<View className="flex-row items-center gap-1.5">
<AppIcon color={tintColor} name={iconName} size={ICON_SIZE[size]} />
<Text className={`${typography.bodySmall} font-medium`} style={{ color: tintColor }}>
resolveCommunityAssetUrl function · typescript · L9-L16 (8 LOC)snipxn_app/src/components/community/communityUtils.ts
export function resolveCommunityAssetUrl(value: string | null): string | null {
if (!value) {
return null;
}
if (/^https?:\/\//i.test(value)) {
return value;
}getUserAvatarFallback function · typescript · L22-L25 (4 LOC)snipxn_app/src/components/community/communityUtils.ts
export function getUserAvatarFallback(name: string | null | undefined): string {
const source = name?.trim() || 'S';
return source.slice(0, 1).toUpperCase();
}getCommunityErrorMessage function · typescript · L27-L38 (12 LOC)snipxn_app/src/components/community/communityUtils.ts
export function getCommunityErrorMessage(error: unknown, fallback: string): string {
if (
typeof error === 'object' &&
error !== null &&
'message' in error &&
typeof error.message === 'string'
) {
return translateLiteral(error.message);
}
return fallback;
}getRuntimeEnv function · typescript · L40-L43 (4 LOC)snipxn_app/src/components/community/communityUtils.ts
function getRuntimeEnv(): Record<string, string | undefined> {
const runtime = globalThis as typeof globalThis & { process?: RuntimeProcess };
return runtime.process?.env ?? {};
}Same scanner, your repo: https://repobility.com — Repobility
resolveWebBaseUrl function · typescript · L45-L55 (11 LOC)snipxn_app/src/components/community/communityUtils.ts
function resolveWebBaseUrl(): string {
const env = getRuntimeEnv();
const configuredBaseUrl =
env.SNIPXN_WEB_BASE_URL ?? env.WEB_BASE_URL ?? env.REACT_NATIVE_WEB_BASE_URL;
if (configuredBaseUrl && configuredBaseUrl.trim().length > 0) {
return configuredBaseUrl.replace(/\/+$/, '');
}
return API_BASE_URL.replace(/\/api\/v1\/?$/, '');
}buildCommunityShareUrl function · typescript · L57-L59 (3 LOC)snipxn_app/src/components/community/communityUtils.ts
export function buildCommunityShareUrl(shareToken: string): string {
return `${resolveWebBaseUrl()}/share/${shareToken}`;
}PostCard function · typescript · L22-L133 (112 LOC)snipxn_app/src/components/community/PostCard.tsx
export function PostCard({
post,
onPress,
onPressAuthor,
onPressLike,
onPressCollect,
onPressComment,
}: PostCardProps) {
const { palette, typography } = useAppTheme();
const { isEnglish, t } = useI18n();
const avatarUri = resolveCommunityAssetUrl(post.authorAvatar);
const visibleTags = post.tags.filter(tag => tag.trim().length > 0).slice(0, 3);
const extraTagCount = Math.max(post.tags.length - visibleTags.length, 0);
return (
<View
className="overflow-hidden rounded-[20px] border px-4 py-4"
style={{
borderColor: palette.border,
backgroundColor: palette.surface,
shadowColor: palette.shadow,
shadowOpacity: 0.1,
shadowRadius: 14,
shadowOffset: { width: 0, height: 10 },
elevation: 6,
}}>
<View className="flex-row items-center justify-between gap-3">
<Pressable
accessibilityRole="button"
className="mingetErrorMessage function · typescript · L26-L37 (12 LOC)snipxn_app/src/components/note/AiPanel.tsx
function getErrorMessage(error: unknown, fallback: string): string {
if (
typeof error === 'object' &&
error !== null &&
'message' in error &&
typeof error.message === 'string'
) {
return error.message;
}
return fallback;
}AiPanel function · typescript · L39-L413 (375 LOC)snipxn_app/src/components/note/AiPanel.tsx
export function AiPanel({
isOpen,
currentContent,
currentLanguage,
onOpenChange,
onInsertGenerated,
onBusyChange,
inline,
}: AiPanelProps) {
const { screenHeight } = useDeviceType();
const { palette, theme, typography } = useAppTheme();
const [activeTab, setActiveTab] = useState<AiTab>('review');
const [reviewFocus, setReviewFocus] = useState('请从潜在 bug、边界条件、可读性和性能优化角度审查当前代码。');
const [reviewLoading, setReviewLoading] = useState(false);
const [reviewResult, setReviewResult] = useState<AiResponse | null>(null);
const [reviewError, setReviewError] = useState<string | null>(null);
const [generatePrompt, setGeneratePrompt] = useState('');
const [generateLoading, setGenerateLoading] = useState(false);
const [generatedResult, setGeneratedResult] = useState<AiResponse | null>(null);
const [generateError, setGenerateError] = useState<string | null>(null);
const [fontSize, setFontSize] = useState<number>(DEFAULT_CODE_FONT_SIZE);
useEffect(() => {
letnormalizeRunnerLanguage function · typescript · L32-L34 (3 LOC)snipxn_app/src/components/note/CodeBlockRunner.tsx
function normalizeRunnerLanguage(language: string): string | null {
return RUNNABLE_LANGUAGE_MAP[language.trim().toLowerCase()] ?? null;
}getErrorMessage function · typescript · L36-L47 (12 LOC)snipxn_app/src/components/note/CodeBlockRunner.tsx
function getErrorMessage(error: unknown, fallback: string): string {
if (
typeof error === 'object' &&
error !== null &&
'message' in error &&
typeof error.message === 'string'
) {
return error.message;
}
return fallback;
}pickNumber function · typescript · L49-L57 (9 LOC)snipxn_app/src/components/note/CodeBlockRunner.tsx
function pickNumber(source: RunCodeResponse, keys: string[]): number | null {
for (const key of keys) {
const value = source[key];
if (typeof value === 'number' && Number.isFinite(value)) {
return value;
}
}
return null;
}Source: Repobility analyzer · https://repobility.com
pickString function · typescript · L59-L67 (9 LOC)snipxn_app/src/components/note/CodeBlockRunner.tsx
function pickString(source: RunCodeResponse, keys: string[]): string | null {
for (const key of keys) {
const value = source[key];
if (typeof value === 'string' && value.trim().length > 0) {
return value.trim();
}
}
return null;
}formatBytes function · typescript · L69-L84 (16 LOC)snipxn_app/src/components/note/CodeBlockRunner.tsx
function formatBytes(bytes: number): string {
if (bytes < 1024) {
return `${bytes} B`;
}
const units = ['KB', 'MB', 'GB'];
let value = bytes / 1024;
let unitIndex = 0;
while (value >= 1024 && unitIndex < units.length - 1) {
value /= 1024;
unitIndex += 1;
}
return `${value.toFixed(value >= 100 ? 0 : 1)} ${units[unitIndex]}`;
}formatDuration function · typescript · L86-L103 (18 LOC)snipxn_app/src/components/note/CodeBlockRunner.tsx
function formatDuration(response: RunCodeResponse | null): string {
if (!response) {
return '--';
}
const numericDuration = pickNumber(response, [
'executionTimeMs',
'timeMs',
'durationMs',
'runtimeMs',
]);
if (numericDuration !== null) {
return `${numericDuration} ms`;
}
return pickString(response, ['executionTime', 'duration', 'runtime']) ?? '--';
}formatMemory function · typescript · L105-L126 (22 LOC)snipxn_app/src/components/note/CodeBlockRunner.tsx
function formatMemory(response: RunCodeResponse | null): string {
if (!response) {
return '--';
}
const memoryBytes = pickNumber(response, ['memoryBytes', 'memoryUsedBytes']);
if (memoryBytes !== null) {
return formatBytes(memoryBytes);
}
const memoryKb = pickNumber(response, ['memoryKb', 'memoryKB', 'memoryUsedKb']);
if (memoryKb !== null) {
return `${memoryKb} KB`;
}
const memoryMb = pickNumber(response, ['memoryMb', 'memoryMB', 'memoryUsedMb']);
if (memoryMb !== null) {
return `${memoryMb} MB`;
}
return pickString(response, ['memory', 'memoryUsed']) ?? '--';
}resolveRunnerStatus function · typescript · L128-L144 (17 LOC)snipxn_app/src/components/note/CodeBlockRunner.tsx
function resolveRunnerStatus(response: RunCodeResponse): RunnerStatus {
const status = typeof response.status === 'string' ? response.status.toLowerCase() : '';
if (status.includes('timeout')) {
return 'timeout';
}
if (status.includes('error') || status.includes('fail')) {
return 'error';
}
if (typeof response.stderr === 'string' && response.stderr.trim().length > 0) {
return 'error';
}
return 'success';
}CodeBlockRunner function · typescript · L154-L442 (289 LOC)snipxn_app/src/components/note/CodeBlockRunner.tsx
export function CodeBlockRunner({
content,
documentLanguage,
onClose,
onScrollToLine,
onStatusChange,
}: CodeBlockRunnerProps) {
const { palette, typography } = useAppTheme();
const { t } = useI18n();
const blocks = useMemo(
() => extractCodeBlocks(content, documentLanguage),
[content, documentLanguage],
);
const [currentIndex, setCurrentIndex] = useState(0);
const [status, setStatus] = useState<RunnerStatus>('idle');
const [result, setResult] = useState<RunCodeResponse | null>(null);
const [fontSize, setFontSize] = useState<number>(DEFAULT_CODE_FONT_SIZE);
useEffect(() => {
let isMounted = true;
void getStoredCodeFontSize().then(value => {
if (isMounted) {
setFontSize(value);
}
});
return () => {
isMounted = false;
};
}, []);
useEffect(() => {
onStatusChange?.(status);
}, [onStatusChange, status]);
// Clamp index if blocks change
useEffect(() => {
if (blocks.length === 0) {
sgetErrorMessage function · typescript · L67-L78 (12 LOC)snipxn_app/src/components/note/CodeEditor.tsx
function getErrorMessage(error: unknown, fallback: string): string {
if (
typeof error === 'object' &&
error !== null &&
'message' in error &&
typeof error.message === 'string'
) {
return translateLiteral(error.message);
}
return fallback;
}normalizeLanguage function · typescript · L80-L82 (3 LOC)snipxn_app/src/components/note/CodeEditor.tsx
function normalizeLanguage(language: string): string {
return language.trim().length > 0 ? language.trim() : 'markdown';
}Repobility · open methodology · https://repobility.com/research/
createBootScript function · typescript · L84-L92 (9 LOC)snipxn_app/src/components/note/CodeEditor.tsx
function createBootScript(config: {
content: string;
language: string;
readOnly: boolean;
theme: EditorTheme;
fontSize: number;
}): string {
return `window.__SNIPXN_EDITOR_BOOT__ = ${JSON.stringify(config)}; true;`;
}FallbackCodeEditor function · typescript · L94-L121 (28 LOC)snipxn_app/src/components/note/CodeEditor.tsx
function FallbackCodeEditor({
content,
readOnly = false,
onContentChange,
}: CodeEditorProps) {
const { palette, typography } = useAppTheme();
const { isTablet } = useDeviceType();
const { t } = useI18n();
return (
<GlassPanel className="flex-1 gap-3 px-4 py-4" variant="inset">
<Text className={typography.bodySmall} style={{ color: palette.textSoft }}>
{t('当前使用兼容编辑模式。')}
</Text>
<TextInput
autoCapitalize="none"
className={`${typography.code} flex-1`}
editable={!readOnly}
multiline
onChangeText={onContentChange}
placeholder={t('开始编写 Markdown 或代码片段...')}
placeholderTextColor={palette.placeholder}
style={{ color: palette.text, fontSize: isTablet ? 16 : 14, textAlignVertical: 'top' }}
value={content}
/>
</GlassPanel>
);
}getErrorMessage function · typescript · L45-L56 (12 LOC)snipxn_app/src/components/note/CodeRunnerPanel.tsx
function getErrorMessage(error: unknown, fallback: string): string {
if (
typeof error === 'object' &&
error !== null &&
'message' in error &&
typeof error.message === 'string'
) {
return error.message;
}
return fallback;
}