( config: ResolvedConfig, )
| 1326 | } |
| 1327 | |
| 1328 | export function injectNonceAttributeTagHook( |
| 1329 | config: ResolvedConfig, |
| 1330 | ): IndexHtmlTransformHook { |
| 1331 | const processRelType = new Set(['stylesheet', 'modulepreload', 'preload']) |
| 1332 | |
| 1333 | return async (html, { filename }) => { |
| 1334 | const nonce = config.html?.cspNonce |
| 1335 | if (!nonce) return |
| 1336 | |
| 1337 | const s = new MagicString(html) |
| 1338 | |
| 1339 | await traverseHtml(html, filename, config.logger.warn, (node) => { |
| 1340 | if (!nodeIsElement(node)) { |
| 1341 | return |
| 1342 | } |
| 1343 | |
| 1344 | const { nodeName, attrs, sourceCodeLocation } = node |
| 1345 | |
| 1346 | if ( |
| 1347 | nodeName === 'script' || |
| 1348 | nodeName === 'style' || |
| 1349 | (nodeName === 'link' && |
| 1350 | attrs.some( |
| 1351 | (attr) => |
| 1352 | attr.name === 'rel' && |
| 1353 | parseRelAttr(attr.value).some((a) => processRelType.has(a)), |
| 1354 | )) |
| 1355 | ) { |
| 1356 | // If we already have a nonce attribute, we don't need to add another one |
| 1357 | if (attrs.some(({ name }) => name === 'nonce')) { |
| 1358 | return |
| 1359 | } |
| 1360 | |
| 1361 | const startTagEndOffset = sourceCodeLocation!.startTag!.endOffset |
| 1362 | |
| 1363 | // if the closing of the start tag includes a `/`, the offset should be 2 so the nonce |
| 1364 | // is appended prior to the `/` |
| 1365 | const appendOffset = html[startTagEndOffset - 2] === '/' ? 2 : 1 |
| 1366 | |
| 1367 | s.appendRight(startTagEndOffset - appendOffset, ` nonce="${nonce}"`) |
| 1368 | } |
| 1369 | }) |
| 1370 | |
| 1371 | return s.toString() |
| 1372 | } |
| 1373 | } |
| 1374 | |
| 1375 | export function resolveHtmlTransforms( |
| 1376 | plugins: readonly Plugin[], |
no test coverage detected