Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions src/StyleContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,6 @@ export interface StyleContextProps {
/** Hardcode here since transformer not support take effect on serialize currently */
autoPrefix?: boolean;

/** Nonce for CSP (Content Security Policy) */
nonce?: string | (() => string);
}

const StyleContext = React.createContext<StyleContextProps>({
Expand Down
4 changes: 2 additions & 2 deletions src/hooks/useCSSVarRegister.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,15 @@ const useCSSVarRegister = <V, T extends Record<string, V>>(
scope?: string | string[];
token: any;
hashId?: string;
nonce?: string | (() => string);
},
fn: () => T,
) => {
const { key, prefix, unitless, ignore, token, hashId, scope } = config;
const { key, prefix, unitless, ignore, token, hashId, scope, nonce } = config;
const {
cache: { instanceId },
container,
hashPriority,
nonce,
} = useContext(StyleContext);
const { _tokenKey: tokenKey } = token;

Expand Down
3 changes: 2 additions & 1 deletion src/hooks/useCacheToken.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ export interface Option<DerivativeToken, DesignToken> {
preserve?: Record<string, boolean>;
/** Key for current theme. Useful for customizing and should be unique */
key: string;
nonce?: string | (() => string);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

类型定义与实现不一致导致编译失败。

nonce 被定义在 cssVar 对象内部(第 70 行),但在第 172 行代码尝试从 option 根级别解构 nonce。这导致了 pipeline 中的 TypeScript 错误:TS2339: Property 'nonce' does not exist on type 'Option'

根据 PR 目标和测试用例的写法,nonce 应该放在 Option 接口的根级别,而不是嵌套在 cssVar 内。

🐛 建议修复:将 nonce 移至 Option 根级别
 export interface Option<DerivativeToken, DesignToken> {
   /**
    * Generate token with salt.
    * This is used to generate different hashId even same derivative token for different version.
    */
   salt?: string;
   override?: object;
+  /**
+   * CSP nonce for style injection.
+   */
+  nonce?: string | (() => string);
   /**
    * Format token as you need. Such as:
    *
    * - rename token
    * - merge token
    * - delete token
    *
    * This should always be the same since it's one time process.
    * It's ok to useMemo outside but this has better cache strategy.
    */
   formatToken?: (mergedToken: any) => DerivativeToken;
   // ... other fields ...

   /**
    * Transform token to css variables.
    */
   cssVar: {
     hashed?: boolean;
     /** Prefix for css variables */
     prefix?: string;
     /** Tokens that should not be appended with unit */
     unitless?: Record<string, boolean>;
     /** Tokens that should not be transformed to css variables */
     ignore?: Record<string, boolean>;
     /** Tokens that preserves origin value */
     preserve?: Record<string, boolean>;
     /** Key for current theme. Useful for customizing and should be unique */
     key: string;
-    nonce?: string | (() => string);
   };
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/hooks/useCacheToken.tsx` at line 70, The TypeScript error comes from
placing nonce inside cssVar while the code destructures nonce from the Option
root; move the nonce property from the cssVar object into the Option interface
root so the type matches usage. Update the Option type declaration to include
nonce?: string | (() => string) at root level (remove it from cssVar), and
ensure any references or defaults that read nonce (e.g., where options are
destructured) still compile against the new shape; adjust any tests or callers
that passed nonce inside cssVar to pass it at the Option root.

};
}

Expand Down Expand Up @@ -161,14 +162,14 @@ export default function useCacheToken<
cache: { instanceId },
container,
hashPriority,
nonce,
} = useContext(StyleContext);
const {
salt = '',
override = EMPTY_OVERRIDE,
formatToken,
getComputedToken: compute,
cssVar,
nonce,
} = option;

// Basic - We do basic cache here
Expand Down
56 changes: 38 additions & 18 deletions tests/index.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -507,26 +507,46 @@ describe('csssinjs', () => {
test('function', () => 'bamboo');
});

describe('StyleProvider nonce for CSS var', () => {
function testWithStyleProvider(name: string, nonce: string | (() => string)) {
it(name, () => {
const { unmount } = render(
<StyleProvider cache={createCache()} nonce={nonce}>
<Box />
</StyleProvider>,
);
describe('useCacheToken with nonce parameter', () => {
it('should apply nonce from parameter (string)', () => {
const NonceBox = () => {
const [token] = useCacheToken<DerivativeToken>(theme, [baseToken], {
cssVar: {
key: 'css-var-test',
},
nonce: 'bamboo',
});

const styles = Array.from(document.head.querySelectorAll('style'));
// Box 组件使用 useCacheToken 注册 CSS var,应该有 nonce
const cssVarStyle = styles.find(s => s.innerHTML.includes('--primary-color'));
expect(cssVarStyle).toBeDefined();
expect(cssVarStyle?.nonce).toBe('bamboo');
// unmount 后样式清理行为取决于 cache 配置
});
}
return <div className="box-nonced">{token.primaryColor}</div>;
};

render(<NonceBox />);

testWithStyleProvider('string', 'bamboo');
testWithStyleProvider('function', () => 'bamboo');
const styles = Array.from(document.head.querySelectorAll('style'));
const cssVarStyle = styles.find(s => s.innerHTML.includes('--primary-color'));
expect(cssVarStyle).toBeDefined();
expect(cssVarStyle?.nonce).toBe('bamboo');
});

it('should apply nonce from parameter (function)', () => {
const NonceBox = () => {
const [token] = useCacheToken<DerivativeToken>(theme, [baseToken], {
cssVar: {
key: 'css-var-test',
},
nonce: () => 'bamboo',
});

return <div className="box-nonced">{token.primaryColor}</div>;
};

render(<NonceBox />);

const styles = Array.from(document.head.querySelectorAll('style'));
const cssVarStyle = styles.find(s => s.innerHTML.includes('--primary-color'));
expect(cssVarStyle).toBeDefined();
expect(cssVarStyle?.nonce).toBe('bamboo');
});
});

it('should not insert style with different instanceId', () => {
Expand Down
Loading