Skip to content

Commit

Permalink
feat: rename satisfies to filter, add docs (#1249)
Browse files Browse the repository at this point in the history
  • Loading branch information
ssalbdivad authored Jan 9, 2025
1 parent f2697df commit 10f6e58
Show file tree
Hide file tree
Showing 70 changed files with 1,553 additions and 509 deletions.
117 changes: 76 additions & 41 deletions ark/attest/cache/ts.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { fromCwd, type SourcePosition } from "@ark/fs"
import { printable, throwInternalError, type dict } from "@ark/util"
import { printable, throwError, throwInternalError, type dict } from "@ark/util"
import * as tsvfs from "@typescript/vfs"
import { readFileSync } from "node:fs"
import { dirname, join } from "node:path"
Expand Down Expand Up @@ -34,7 +34,7 @@ export class TsServer {

const system = tsvfs.createFSBackedSystem(
tsLibPaths.defaultMapFromNodeModules,
dirname(this.tsConfigInfo.path),
this.tsConfigInfo.path ? dirname(this.tsConfigInfo.path) : fromCwd(),
ts
)

Expand Down Expand Up @@ -105,64 +105,99 @@ export const getAbsolutePosition = (
}

export type TsconfigInfo = {
path: string
path: string | undefined
parsed: ts.ParsedCommandLine
}

export const getTsConfigInfoOrThrow = (): TsconfigInfo => {
const config = getConfig()
const tsconfig = config.tsconfig
const configFilePath =
tsconfig ?? ts.findConfigFile(fromCwd(), ts.sys.fileExists, "tsconfig.json")
if (!configFilePath) {
throw new Error(
`File ${tsconfig ?? join(fromCwd(), "tsconfig.json")} must exist`
)

let instantiatedConfig: ts.ParsedCommandLine | undefined
let configFilePath: string | undefined

if (tsconfig !== null) {
configFilePath =
tsconfig ??
ts.findConfigFile(fromCwd(), ts.sys.fileExists, "tsconfig.json")
if (configFilePath)
instantiatedConfig = instantiateTsconfigFromPath(configFilePath)
}

const configFileText = readFileSync(configFilePath).toString()
const result = ts.parseConfigFileTextToJson(configFilePath, configFileText)
if (result.error) {
throw new Error(
ts.formatDiagnostics([result.error], {
getCanonicalFileName: fileName => fileName,
getCurrentDirectory: process.cwd,
getNewLine: () => ts.sys.newLine
})
)
instantiatedConfig ??= instantiateNoFileConfig()

return {
path: configFilePath,
parsed: instantiatedConfig
}
}

type RawTsConfigJson = dict & { compilerOptions: ts.CompilerOptions }

const configJson: dict & { compilerOptions: ts.CompilerOptions } =
result.config
type InstantiatedTsConfigJson = ts.ParsedCommandLine

configJson.compilerOptions = Object.assign(
configJson.compilerOptions ?? {},
config.compilerOptions
const instantiateNoFileConfig = (): InstantiatedTsConfigJson => {
const arkConfig = getConfig()

const instantiatedConfig = ts.parseJsonConfigFileContent(
{
compilerOptions: arkConfig.compilerOptions
},
ts.sys,
fromCwd()
)
const configParseResult = ts.parseJsonConfigFileContent(
configJson,

if (instantiatedConfig.errors.length > 0)
throwConfigInstantiationError(instantiatedConfig)

return instantiatedConfig
}

const instantiateTsconfigFromPath = (
path: string
): InstantiatedTsConfigJson => {
const arkConfig = getConfig()
const configFileText = readFileSync(path).toString()
const result = ts.parseConfigFileTextToJson(path, configFileText)
if (result.error) throwConfigParseError(result.error)

const rawConfig: RawTsConfigJson = result.config

rawConfig.compilerOptions = Object.assign(
rawConfig.compilerOptions ?? {},
arkConfig.compilerOptions
)

const instantiatedConfig = ts.parseJsonConfigFileContent(
rawConfig,
ts.sys,
dirname(configFilePath),
dirname(path),
{},
configFilePath
path
)

if (configParseResult.errors.length > 0) {
throw new Error(
ts.formatDiagnostics(configParseResult.errors, {
getCanonicalFileName: fileName => fileName,
getCurrentDirectory: process.cwd,
getNewLine: () => ts.sys.newLine
})
)
}
if (instantiatedConfig.errors.length > 0)
throwConfigInstantiationError(instantiatedConfig)

return {
path: configFilePath,
parsed: configParseResult
}
return instantiatedConfig
}

const defaultDiagnosticHost: ts.FormatDiagnosticsHost = {
getCanonicalFileName: fileName => fileName,
getCurrentDirectory: process.cwd,
getNewLine: () => ts.sys.newLine
}

const throwConfigParseError = (error: ts.Diagnostic) =>
throwError(ts.formatDiagnostics([error], defaultDiagnosticHost))

const throwConfigInstantiationError = (
instantiatedConfig: InstantiatedTsConfigJson
): never =>
throwError(
ts.formatDiagnostics(instantiatedConfig.errors, defaultDiagnosticHost)
)

type TsLibFiles = {
defaultMapFromNodeModules: Map<string, string>
resolvedPaths: string[]
Expand Down
2 changes: 2 additions & 0 deletions ark/attest/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@ const getParamValue = (param: keyof AttestConfig) => {

if (raw === "false") return false

if (raw === "null") return null

if (param === "benchPercentThreshold")
return tryParseNumber(raw, { errorOnFail: true })

Expand Down
2 changes: 1 addition & 1 deletion ark/attest/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@ark/attest",
"version": "0.36.0",
"version": "0.37.0",
"license": "MIT",
"author": {
"name": "David Blass",
Expand Down
4 changes: 1 addition & 3 deletions ark/attest/tsVersioning.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,7 @@ import ts from "typescript"
*
* Throws an error if any version fails when the associated function is executed.
*
* @param {TsVersionData[]} versions The set of versions for which to exceute the function
* @param {function} fn - The function to execute for each TypeScript version.
* Should spawn a new process so the new symlinked version can be loaded.
* fn should spawn a new process so the new symlinked version can be loaded.
*/
export const forTypeScriptVersions = (
versions: TsVersionData[],
Expand Down
102 changes: 102 additions & 0 deletions ark/docs/components/ApiTable.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import type { JSX } from "react"
import type { ApiGroup, ParsedJsDocPart } from "../../repo/jsdocGen.ts"
import { apiDocsByGroup } from "./apiData.ts"
import { CodeBlock } from "./CodeBlock.tsx"
import { LocalFriendlyUrl } from "./LocalFriendlyUrl.tsx"

export type ApiTableProps = {
group: ApiGroup
rows: JSX.Element[]
}

export const ApiTable = ({ group }: ApiTableProps) => (
<>
<h2>{group}</h2>
<div className="w-full overflow-x-auto">
<table className="w-full table-fixed border-collapse">
<colgroup>
<col className="w-28" />
<col className="w-1/4" />
<col className="w-full" />
</colgroup>
<ApiTableHeader />
<tbody>
{apiDocsByGroup[group].map(props => (
<ApiTableRow key={props.name} {...props} />
))}
</tbody>
</table>
</div>
</>
)

const ApiTableHeader = () => (
<thead>
<tr>
<th className="p-2 text-left align-top whitespace-nowrap w-auto min-w-[100px]">
Name
</th>
<th className="p-2 text-left align-top min-w-[200px]">Summary</th>
<th className="p-2 text-left align-top">Example</th>
</tr>
</thead>
)

interface ApiTableRowProps {
name: string
summary: ParsedJsDocPart[]
example?: string
notes: ParsedJsDocPart[][]
}

const ApiTableRow = ({ name, summary, example, notes }: ApiTableRowProps) => (
<tr key={name}>
<td className="p-2 align-top whitespace-nowrap w-auto">{name}</td>
<td className="p-2 align-top">{JsDocParts(summary)}</td>
<td className="p-2 align-top">
{notes.map((note, i) => (
<div key={i}>{JsDocParts(note)} </div>
))}
<ApiExample>{example}</ApiExample>
</td>
</tr>
)

const JsDocParts = (parts: readonly ParsedJsDocPart[]) =>
parts.map((part, i) => (
<span key={i} style={{ marginRight: "0.25em" }}>
{part.kind === "link" ?
<LocalFriendlyUrl url={part.url} key={i}>
{part.value}
</LocalFriendlyUrl>
: part.kind === "reference" ?
<a href={`#${part.value}`} key={i}>
{part.value}
</a>
: part.kind === "tag" ?
<p key={i}>
{part.name} {JsDocParts(part.value)}
</p>
: <p
style={{ display: "inline" }}
key={i}
dangerouslySetInnerHTML={{
__html: part.value
.replace(/(\*\*|__)([^*_]+)\1/g, "<strong>$2</strong>")
.replace(/(\*|_)([^*_]+)\1/g, "<em>$2</em>")
}}
/>
}
</span>
))

interface ApiExampleProps {
children: string | undefined
}

const ApiExample = ({ children }: ApiExampleProps) =>
children && (
<CodeBlock style={{ margin: 0 }} decorators={["@noErrors"]}>
{children}
</CodeBlock>
)
16 changes: 12 additions & 4 deletions ark/docs/components/CodeBlock.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,11 @@ export type CodeBlockProps = {
style?: React.CSSProperties
className?: string
includesCompletions?: boolean
decorators?: CodeBlockDecorator[]
} & propwiseXor<{ children: string }, { fromFile: SnippetId }>

export type CodeBlockDecorator = "@noErrors"

// preload languages for shiki
// https://github.com/fuma-nama/fumadocs/issues/1095
const highlighter = await getSingletonHighlighter({
Expand Down Expand Up @@ -51,19 +54,24 @@ export const CodeBlock: React.FC<CodeBlockProps> = ({
fromFile,
style,
className,
includesCompletions
includesCompletions,
decorators
}) => {
children ??= snippetContentsById[fromFile!]
let src = children ?? snippetContentsById[fromFile!]

if (!children) {
if (!src) {
throwInternalError(
fromFile ?
`Specified snippet '${fromFile}' does not have a corresponding file`
: `CodeBlock requires either a fromFile prop or a string child representing its text contents`
)
}

const highlighted = highlight(lang, children)
decorators?.forEach(d => {
if (!src.includes(d)) src = `// ${d}\n${src}`
})

const highlighted = highlight(lang, src)

return (
<FumaCodeBlock
Expand Down
27 changes: 27 additions & 0 deletions ark/docs/components/LocalFriendlyUrl.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
"use client"
import { useEffect, useState } from "react"

export interface LocalFriendlyUrlProps {
children: string
url: string
key?: string | number | undefined
}

export const LocalFriendlyUrl = (props: LocalFriendlyUrlProps) => {
const [locallyAccessibleUrl, setLocallyAccessibleUrl] = useState(props.url)

if (process.env.NODE_ENV === "development") {
useEffect(() => {
const devFriendlyUrl = new URL(props.url)
devFriendlyUrl.protocol = "http:"
devFriendlyUrl.host = window.location.host
setLocallyAccessibleUrl(devFriendlyUrl.toString())
}, [props.url])
}

return (
<a href={locallyAccessibleUrl} key={props.key}>
{props.children}
</a>
)
}
Loading

0 comments on commit 10f6e58

Please sign in to comment.