tftsr-devops_investigation/node_modules/unist-util-is/lib/index.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

297 lines
8.8 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* @import {Node, Parent} from 'unist'
*/
/**
* @template Fn
* @template Fallback
* @typedef {Fn extends (value: any) => value is infer Thing ? Thing : Fallback} Predicate
*/
/**
* @callback Check
* Check that an arbitrary value is a node.
* @param {unknown} this
* The given context.
* @param {unknown} [node]
* Anything (typically a node).
* @param {number | null | undefined} [index]
* The nodes position in its parent.
* @param {Parent | null | undefined} [parent]
* The nodes parent.
* @returns {boolean}
* Whether this is a node and passes a test.
*
* @typedef {Record<string, unknown> | Node} Props
* Object to check for equivalence.
*
* Note: `Node` is included as it is common but is not indexable.
*
* @typedef {Array<Props | TestFunction | string> | ReadonlyArray<Props | TestFunction | string> | Props | TestFunction | string | null | undefined} Test
* Check for an arbitrary node.
*
* @callback TestFunction
* Check if a node passes a test.
* @param {unknown} this
* The given context.
* @param {Node} node
* A node.
* @param {number | undefined} [index]
* The nodes position in its parent.
* @param {Parent | undefined} [parent]
* The nodes parent.
* @returns {boolean | undefined | void}
* Whether this node passes the test.
*
* Note: `void` is included until TS sees no return as `undefined`.
*/
/**
* Check if `node` is a `Node` and whether it passes the given test.
*
* @param {unknown} node
* Thing to check, typically `Node`.
* @param {Test} test
* A check for a specific node.
* @param {number | null | undefined} index
* The nodes position in its parent.
* @param {Parent | null | undefined} parent
* The nodes parent.
* @param {unknown} context
* Context object (`this`) to pass to `test` functions.
* @returns {boolean}
* Whether `node` is a node and passes a test.
*/
export const is =
// Note: overloads in JSDoc cant yet use different `@template`s.
/**
* @type {(
* (<Condition extends ReadonlyArray<string>>(node: unknown, test: Condition, index?: number | null | undefined, parent?: Parent | null | undefined, context?: unknown) => node is Node & {type: Condition[number]}) &
* (<Condition extends Array<string>>(node: unknown, test: Condition, index?: number | null | undefined, parent?: Parent | null | undefined, context?: unknown) => node is Node & {type: Condition[number]}) &
* (<Condition extends string>(node: unknown, test: Condition, index?: number | null | undefined, parent?: Parent | null | undefined, context?: unknown) => node is Node & {type: Condition}) &
* (<Condition extends Props>(node: unknown, test: Condition, index?: number | null | undefined, parent?: Parent | null | undefined, context?: unknown) => node is Node & Condition) &
* (<Condition extends TestFunction>(node: unknown, test: Condition, index?: number | null | undefined, parent?: Parent | null | undefined, context?: unknown) => node is Node & Predicate<Condition, Node>) &
* ((node?: null | undefined) => false) &
* ((node: unknown, test?: null | undefined, index?: number | null | undefined, parent?: Parent | null | undefined, context?: unknown) => node is Node) &
* ((node: unknown, test?: Test, index?: number | null | undefined, parent?: Parent | null | undefined, context?: unknown) => boolean)
* )}
*/
(
/**
* @param {unknown} [node]
* @param {Test} [test]
* @param {number | null | undefined} [index]
* @param {Parent | null | undefined} [parent]
* @param {unknown} [context]
* @returns {boolean}
*/
// eslint-disable-next-line max-params
function (node, test, index, parent, context) {
const check = convert(test)
if (
index !== undefined &&
index !== null &&
(typeof index !== 'number' ||
index < 0 ||
index === Number.POSITIVE_INFINITY)
) {
throw new Error('Expected positive finite index')
}
if (
parent !== undefined &&
parent !== null &&
(!is(parent) || !parent.children)
) {
throw new Error('Expected parent node')
}
if (
(parent === undefined || parent === null) !==
(index === undefined || index === null)
) {
throw new Error('Expected both parent and index')
}
return looksLikeANode(node)
? check.call(context, node, index, parent)
: false
}
)
/**
* Generate an assertion from a test.
*
* Useful if youre going to test many nodes, for example when creating a
* utility where something else passes a compatible test.
*
* The created function is a bit faster because it expects valid input only:
* a `node`, `index`, and `parent`.
*
* @param {Test} test
* * when nullish, checks if `node` is a `Node`.
* * when `string`, works like passing `(node) => node.type === test`.
* * when `function` checks if function passed the node is true.
* * when `object`, checks that all keys in test are in node, and that they have (strictly) equal values.
* * when `array`, checks if any one of the subtests pass.
* @returns {Check}
* An assertion.
*/
export const convert =
// Note: overloads in JSDoc cant yet use different `@template`s.
/**
* @type {(
* (<Condition extends string>(test: Condition) => (node: unknown, index?: number | null | undefined, parent?: Parent | null | undefined, context?: unknown) => node is Node & {type: Condition}) &
* (<Condition extends Props>(test: Condition) => (node: unknown, index?: number | null | undefined, parent?: Parent | null | undefined, context?: unknown) => node is Node & Condition) &
* (<Condition extends TestFunction>(test: Condition) => (node: unknown, index?: number | null | undefined, parent?: Parent | null | undefined, context?: unknown) => node is Node & Predicate<Condition, Node>) &
* ((test?: null | undefined) => (node?: unknown, index?: number | null | undefined, parent?: Parent | null | undefined, context?: unknown) => node is Node) &
* ((test?: Test) => Check)
* )}
*/
(
/**
* @param {Test} [test]
* @returns {Check}
*/
function (test) {
if (test === null || test === undefined) {
return ok
}
if (typeof test === 'function') {
return castFactory(test)
}
if (typeof test === 'object') {
return Array.isArray(test)
? anyFactory(test)
: // Cast because `ReadonlyArray` goes into the above but `isArray`
// narrows to `Array`.
propertiesFactory(/** @type {Props} */ (test))
}
if (typeof test === 'string') {
return typeFactory(test)
}
throw new Error('Expected function, string, or object as test')
}
)
/**
* @param {Array<Props | TestFunction | string>} tests
* @returns {Check}
*/
function anyFactory(tests) {
/** @type {Array<Check>} */
const checks = []
let index = -1
while (++index < tests.length) {
checks[index] = convert(tests[index])
}
return castFactory(any)
/**
* @this {unknown}
* @type {TestFunction}
*/
function any(...parameters) {
let index = -1
while (++index < checks.length) {
if (checks[index].apply(this, parameters)) return true
}
return false
}
}
/**
* Turn an object into a test for a node with a certain fields.
*
* @param {Props} check
* @returns {Check}
*/
function propertiesFactory(check) {
const checkAsRecord = /** @type {Record<string, unknown>} */ (check)
return castFactory(all)
/**
* @param {Node} node
* @returns {boolean}
*/
function all(node) {
const nodeAsRecord = /** @type {Record<string, unknown>} */ (
/** @type {unknown} */ (node)
)
/** @type {string} */
let key
for (key in check) {
if (nodeAsRecord[key] !== checkAsRecord[key]) return false
}
return true
}
}
/**
* Turn a string into a test for a node with a certain type.
*
* @param {string} check
* @returns {Check}
*/
function typeFactory(check) {
return castFactory(type)
/**
* @param {Node} node
*/
function type(node) {
return node && node.type === check
}
}
/**
* Turn a custom test into a test for a node that passes that test.
*
* @param {TestFunction} testFunction
* @returns {Check}
*/
function castFactory(testFunction) {
return check
/**
* @this {unknown}
* @type {Check}
*/
function check(value, index, parent) {
return Boolean(
looksLikeANode(value) &&
testFunction.call(
this,
value,
typeof index === 'number' ? index : undefined,
parent || undefined
)
)
}
}
function ok() {
return true
}
/**
* @param {unknown} value
* @returns {value is Node}
*/
function looksLikeANode(value) {
return value !== null && typeof value === 'object' && 'type' in value
}