源码快照 @ 2026-09-01 (source-only, 剔除非源码素材)
Publish Claude Code Binaries / Stage and publish binaries (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-arm64 (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build linux-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build windows-amd64 (push) Canceled after 0s
Sync Tutti Agent Skills / sync (push) Canceled after 0s
Windows Agent Adapters / Test Windows agent adapters (push) Canceled after 0s
Windows Daemon Adapters / Test Windows daemon adapters (push) Canceled after 0s
Publish Tutti App Runtime / Publish runtime catalog (push) Canceled after 0s
Publish Claude Code Binaries / Stage and publish binaries (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-arm64 (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build linux-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build windows-amd64 (push) Canceled after 0s
Sync Tutti Agent Skills / sync (push) Canceled after 0s
Windows Agent Adapters / Test Windows agent adapters (push) Canceled after 0s
Windows Daemon Adapters / Test Windows daemon adapters (push) Canceled after 0s
Publish Tutti App Runtime / Publish runtime catalog (push) Canceled after 0s
This commit is contained in:
@@ -0,0 +1,238 @@
|
||||
const forbiddenClassSubjects = [
|
||||
"agent-gui-conversation__assistant-message-flow",
|
||||
"agent-gui-conversation__user-message-flow",
|
||||
"agent-gui-node__body",
|
||||
"agent-gui-node__conversation-list",
|
||||
"agent-gui-node__detail",
|
||||
"agent-gui-node__detail-panel",
|
||||
"agent-gui-node__layout",
|
||||
"agent-gui-node__provider-rail-panel",
|
||||
"agent-gui-node__rail",
|
||||
"agent-gui-node__shell",
|
||||
"agent-gui-node__timeline",
|
||||
"agent-gui-node__timeline-with-composer",
|
||||
"agent-gui-transcript-row",
|
||||
"desktop-dock",
|
||||
"desktop-dock-plate",
|
||||
"workbench-surface",
|
||||
"workbench-window",
|
||||
"workbench-window-shell",
|
||||
"workspace-node-window",
|
||||
"workspace-node-window__body"
|
||||
];
|
||||
|
||||
export function analyzeCssHasPerformance({ path, source }) {
|
||||
const diagnostics = [];
|
||||
const maskedSource = maskCssNonCode(source);
|
||||
|
||||
for (const rule of collectCssRulePreludes(maskedSource)) {
|
||||
const hasPattern = /:has\s*\(/giu;
|
||||
for (const match of rule.prelude.matchAll(hasPattern)) {
|
||||
const compound = readSubjectCompound(rule.prelude.slice(0, match.index));
|
||||
const subject = findForbiddenSubject(compound);
|
||||
if (!subject) {
|
||||
continue;
|
||||
}
|
||||
|
||||
diagnostics.push(
|
||||
diagnosticAt({
|
||||
index: rule.startIndex + match.index,
|
||||
message:
|
||||
`do not use :has() on large dynamic subject ${subject}; ` +
|
||||
"project the state onto the subject with a data attribute",
|
||||
path,
|
||||
selector: source
|
||||
.slice(rule.startIndex, rule.endIndex)
|
||||
.replace(/\s+/gu, " ")
|
||||
.trim(),
|
||||
source,
|
||||
subject
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return diagnostics;
|
||||
}
|
||||
|
||||
export function isCssHasPerformancePath(path) {
|
||||
const normalized = path.replaceAll("\\", "/");
|
||||
return (
|
||||
/^(?:apps|packages|services)\//u.test(normalized) &&
|
||||
normalized.endsWith(".css") &&
|
||||
!/(?:^|\/)(?:coverage|dist|node_modules|out|\.tmp)(?:\/|$)/u.test(
|
||||
normalized
|
||||
) &&
|
||||
!/(?:^|\/)[^/]+\.(?:spec|test)\.css$/u.test(normalized)
|
||||
);
|
||||
}
|
||||
|
||||
function collectCssRulePreludes(maskedSource) {
|
||||
const rules = [];
|
||||
let statementStart = 0;
|
||||
|
||||
for (let index = 0; index < maskedSource.length; index += 1) {
|
||||
const character = maskedSource[index];
|
||||
if (character === "{") {
|
||||
const statement = maskedSource.slice(statementStart, index);
|
||||
const firstCodeOffset = findFirstCodeOffset(statement);
|
||||
if (firstCodeOffset >= 0) {
|
||||
const startIndex = statementStart + firstCodeOffset;
|
||||
const prelude = maskedSource.slice(startIndex, index);
|
||||
if (!prelude.startsWith("@")) {
|
||||
rules.push({ endIndex: index, prelude, startIndex });
|
||||
}
|
||||
}
|
||||
statementStart = index + 1;
|
||||
continue;
|
||||
}
|
||||
if (character === "}" || character === ";") {
|
||||
statementStart = index + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return rules;
|
||||
}
|
||||
|
||||
function readSubjectCompound(prefix) {
|
||||
let bracketDepth = 0;
|
||||
let parenthesisDepth = 0;
|
||||
let start = 0;
|
||||
|
||||
for (let index = 0; index < prefix.length; index += 1) {
|
||||
const character = prefix[index];
|
||||
if (character === "\u0000") {
|
||||
continue;
|
||||
}
|
||||
if (character === "[") {
|
||||
bracketDepth += 1;
|
||||
continue;
|
||||
}
|
||||
if (character === "]") {
|
||||
bracketDepth = Math.max(0, bracketDepth - 1);
|
||||
continue;
|
||||
}
|
||||
if (character === "(") {
|
||||
parenthesisDepth += 1;
|
||||
continue;
|
||||
}
|
||||
if (character === ")") {
|
||||
parenthesisDepth = Math.max(0, parenthesisDepth - 1);
|
||||
continue;
|
||||
}
|
||||
if (bracketDepth > 0 || parenthesisDepth > 0) {
|
||||
continue;
|
||||
}
|
||||
if (
|
||||
character === "," ||
|
||||
character === ">" ||
|
||||
character === "+" ||
|
||||
character === "~"
|
||||
) {
|
||||
start = index + 1;
|
||||
continue;
|
||||
}
|
||||
if (/\s/u.test(character)) {
|
||||
start = index + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return prefix.slice(start).trim();
|
||||
}
|
||||
|
||||
function findForbiddenSubject(compound) {
|
||||
if (/^:root(?=[.#[:]|$)/u.test(compound)) {
|
||||
return ":root";
|
||||
}
|
||||
const typeSubject = /^(?:\*?\|)?(body|html)(?=[.#[:]|$)/u.exec(compound);
|
||||
if (typeSubject) {
|
||||
return typeSubject[1];
|
||||
}
|
||||
|
||||
for (const className of forbiddenClassSubjects) {
|
||||
const pattern = new RegExp(
|
||||
`(?:^|[^a-zA-Z0-9_-])\\.${escapeRegExp(className)}(?![a-zA-Z0-9_-])`,
|
||||
"u"
|
||||
);
|
||||
if (pattern.test(compound)) {
|
||||
return `.${className}`;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function maskCssNonCode(source) {
|
||||
const characters = source.split("");
|
||||
let inComment = false;
|
||||
let quote = null;
|
||||
|
||||
for (let index = 0; index < characters.length; index += 1) {
|
||||
const character = characters[index];
|
||||
const next = characters[index + 1];
|
||||
if (inComment) {
|
||||
characters[index] = "\u0000";
|
||||
if (character === "*" && next === "/") {
|
||||
characters[index + 1] = "\u0000";
|
||||
inComment = false;
|
||||
index += 1;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (quote) {
|
||||
if (character !== "\n") {
|
||||
characters[index] = " ";
|
||||
}
|
||||
if (character === "\\") {
|
||||
if (next !== "\n") {
|
||||
characters[index + 1] = " ";
|
||||
}
|
||||
index += 1;
|
||||
} else if (character === quote) {
|
||||
quote = null;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (character === "/" && next === "*") {
|
||||
characters[index] = "\u0000";
|
||||
characters[index + 1] = "\u0000";
|
||||
inComment = true;
|
||||
index += 1;
|
||||
continue;
|
||||
}
|
||||
if (character === '"' || character === "'") {
|
||||
characters[index] = " ";
|
||||
quote = character;
|
||||
}
|
||||
}
|
||||
|
||||
return characters.join("");
|
||||
}
|
||||
|
||||
function diagnosticAt({ index, message, path, selector, source, subject }) {
|
||||
const prefix = source.slice(0, index);
|
||||
const lines = prefix.split("\n");
|
||||
return {
|
||||
column: lines.at(-1).length + 1,
|
||||
kind: "large-dynamic-has-subject",
|
||||
line: lines.length,
|
||||
message,
|
||||
path,
|
||||
selector,
|
||||
subject,
|
||||
token: ":has"
|
||||
};
|
||||
}
|
||||
|
||||
function escapeRegExp(value) {
|
||||
return value.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
|
||||
}
|
||||
|
||||
function findFirstCodeOffset(source) {
|
||||
for (let index = 0; index < source.length; index += 1) {
|
||||
if (source[index] !== "\u0000" && !/\s/u.test(source[index])) {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
Reference in New Issue
Block a user