tftsr-devops_investigation/node_modules/tailwindcss/lib/util/parseAnimationValue.js
Shaun Arman 8839075805 feat: initial implementation of TFTSR IT Triage & RCA application
Implements Phases 1-8 of the TFTSR implementation plan.

Rust backend (Tauri 2.x, src-tauri/):
- Multi-provider AI: OpenAI-compatible, Anthropic, Gemini, Mistral, Ollama
- PII detection engine: 11 regex patterns with overlap resolution
- SQLCipher AES-256 encrypted database with 10 versioned migrations
- 28 Tauri IPC commands for triage, analysis, document, and system ops
- Ollama: hardware probe, model recommendations, pull/delete with events
- RCA and blameless post-mortem Markdown document generators
- PDF export via printpdf
- Audit log: SHA-256 hash of every external data send
- Integration stubs for Confluence, ServiceNow, Azure DevOps (v0.2)

Frontend (React 18 + TypeScript + Vite, src/):
- 9 pages: full triage workflow NewIssue→LogUpload→Triage→Resolution→RCA→Postmortem→History+Settings
- 7 components: ChatWindow, TriageProgress, PiiDiffViewer, DocEditor, HardwareReport, ModelSelector, UI primitives
- 3 Zustand stores: session, settings (persisted), history
- Type-safe tauriCommands.ts matching Rust backend types exactly
- 8 IT domain system prompts (Linux, Windows, Network, K8s, DB, Virt, HW, Obs)

DevOps:
- .woodpecker/test.yml: rustfmt, clippy, cargo test, tsc, vitest on every push
- .woodpecker/release.yml: linux/amd64 + linux/arm64 builds, Gogs release upload

Verified:
- cargo check: zero errors
- tsc --noEmit: zero errors
- vitest run: 13/13 unit tests passing

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 22:36:25 -05:00

94 lines
2.8 KiB
JavaScript

"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return parseAnimationValue;
}
});
const DIRECTIONS = new Set([
"normal",
"reverse",
"alternate",
"alternate-reverse"
]);
const PLAY_STATES = new Set([
"running",
"paused"
]);
const FILL_MODES = new Set([
"none",
"forwards",
"backwards",
"both"
]);
const ITERATION_COUNTS = new Set([
"infinite"
]);
const TIMINGS = new Set([
"linear",
"ease",
"ease-in",
"ease-out",
"ease-in-out",
"step-start",
"step-end"
]);
const TIMING_FNS = [
"cubic-bezier",
"steps"
];
const COMMA = /\,(?![^(]*\))/g // Comma separator that is not located between brackets. E.g.: `cubic-bezier(a, b, c)` these don't count.
;
const SPACE = /\ +(?![^(]*\))/g // Similar to the one above, but with spaces instead.
;
const TIME = /^(-?[\d.]+m?s)$/;
const DIGIT = /^(\d+)$/;
function parseAnimationValue(input) {
let animations = input.split(COMMA);
return animations.map((animation)=>{
let value = animation.trim();
let result = {
value
};
let parts = value.split(SPACE);
let seen = new Set();
for (let part of parts){
if (!seen.has("DIRECTIONS") && DIRECTIONS.has(part)) {
result.direction = part;
seen.add("DIRECTIONS");
} else if (!seen.has("PLAY_STATES") && PLAY_STATES.has(part)) {
result.playState = part;
seen.add("PLAY_STATES");
} else if (!seen.has("FILL_MODES") && FILL_MODES.has(part)) {
result.fillMode = part;
seen.add("FILL_MODES");
} else if (!seen.has("ITERATION_COUNTS") && (ITERATION_COUNTS.has(part) || DIGIT.test(part))) {
result.iterationCount = part;
seen.add("ITERATION_COUNTS");
} else if (!seen.has("TIMING_FUNCTION") && TIMINGS.has(part)) {
result.timingFunction = part;
seen.add("TIMING_FUNCTION");
} else if (!seen.has("TIMING_FUNCTION") && TIMING_FNS.some((f)=>part.startsWith(`${f}(`))) {
result.timingFunction = part;
seen.add("TIMING_FUNCTION");
} else if (!seen.has("DURATION") && TIME.test(part)) {
result.duration = part;
seen.add("DURATION");
} else if (!seen.has("DELAY") && TIME.test(part)) {
result.delay = part;
seen.add("DELAY");
} else if (!seen.has("NAME")) {
result.name = part;
seen.add("NAME");
} else {
if (!result.unknown) result.unknown = [];
result.unknown.push(part);
}
}
return result;
});
}