Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ new uncovered branch.

To prove that a type resolves to what you claim, write
`type _Name = Assert<Equal<Actual, Expected>>` — `Assert` from
`fjs/asserts/module.f.mjs`, `Equal` from `fjs/types/ts/module.f.mjs`. A wrong
`fjs/asserts/types.ts`, `Equal` from `fjs/types/ts/types.ts`. A wrong
claim is then a compile error (TS2344, "Type 'false' does not satisfy the
constraint 'true'"), and the check costs nothing at runtime.

Expand Down
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@ history.

## Unreleased

- **BREAKING CHANGES:** every public type exported by an authored `.f.mjs`
module moves to a sibling `types.ts` (31 modules, including `asserts`,
`types/list`, `types/bit_vec`, `types/result`, `text`, `crypto/sha2`) —
importers of these types must use the `types.ts` specifier. The runtime-empty
`fjs/types/option/module.f.mjs` becomes `fjs/types/option/types.ts`
[#1483](https://github.com/functionalscript/functionalscript/pull/1483)
- `fjs/types/nullable/proof.f.ts`, `fjs/types/range/proof.f.ts`,
`fjs/types/function/proof.f.ts`, `fjs/types/result/proof.f.ts`, and
`fjs/types/function/compare/proof.f.ts` migrate to `proof.f.mjs` under
Expand Down
75 changes: 7 additions & 68 deletions fjs/asn.1/module.f.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,13 @@ import {
vec8,
} from '../types/bit_vec/module.f.mjs'

/** @import { Unpacked, Vec } from '../types/bit_vec/module.f.mjs' */
/** @import { Unpacked, Vec } from '../types/bit_vec/types.ts' */

/**
* @import {
* ObjectIdentifier, Raw, Record, Sequence, SupportedRecord, _Tag,
* } from './types.ts'
*/

import { identity } from '../types/function/module.f.mjs'

Expand Down Expand Up @@ -57,12 +63,6 @@ const tagNumberMask = 0b000_11111n
* @typedef {readonly[_ClassPc, bigint]} _ParsedTag
*/

/**
* ASN.1 tag number.
*
* @typedef {bigint} _Tag
*/

/** @type {([classPc, number]: _ParsedTag) => Vec} */
const parsedTagEncode = ([classPc, number]) => {
const [firstByteNumber, rest] = number < tagNumberMask
Expand Down Expand Up @@ -179,12 +179,6 @@ const lenDecode = v => {

// raw

/**
* Raw ASN.1 TLV tuple.
*
* @typedef {readonly [_Tag, Vec]} Raw
*/

/**
* Encodes a raw ASN.1 TLV tuple into a bit vector.
*
Expand Down Expand Up @@ -265,12 +259,6 @@ export const decodeOctetString = v => v

// object identifier

/**
* ASN.1 OBJECT IDENTIFIER components.
*
* @typedef {readonly bigint[]} ObjectIdentifier
*/

/**
* Encodes an OBJECT IDENTIFIER value.
*
Expand Down Expand Up @@ -313,12 +301,6 @@ export const decodeObjectIdentifier = v => {

// sequence

/**
* ASN.1 ordered collection of records.
*
* @typedef {readonly Record[]} Sequence
*/

/**
* @param {(vec: readonly Vec[]) => readonly Vec[]} map
* @return {(...records: Sequence) => Vec}
Expand All @@ -343,12 +325,6 @@ export const decodeSequence = v => decodeAll(decode)(v)

// set

/**
* ASN.1 SET represented as a sequence of records.
*
* @typedef {Sequence} Set
*/

/**
* Encodes a SET payload with canonical byte ordering.
*
Expand All @@ -364,43 +340,6 @@ export const encodeSet =
*/
export const decodeSet = decodeSequence

// Record

/**
* Supported ASN.1 record variants.
*
* @typedef {|
* readonly[typeof boolean, boolean] |
* readonly[typeof integer, bigint] |
* readonly[typeof octetString, Vec] |
* readonly[typeof objectIdentifier, ObjectIdentifier] |
* readonly[typeof constructedSequence, Sequence] |
* readonly[typeof constructedSet, Set]
* } SupportedRecord
*/

// Alternative:
//
// export type SupportedRecord =
// | boolean
// | bigint // integer
// | { tag: typeof octetString, value: Vec }
// | { tag: typeof objectIdentifier, value: ObjectIdentifier }
// | readonly Record[] // sequence
// | { tag: typeof constructedSet, value: readonly Record[] }
//
// export type UnsupportedRecord =
// | { tag: null, value: Vec }

/**
* For unsupported tags, we just store the raw value including the tag and length,
* so that it can be re-encoded without loss of information.
*
* @typedef {Vec} UnsupportedRecord
*/

/** @typedef {SupportedRecord | UnsupportedRecord} Record */

// encode

/** @type {(_: SupportedRecord) => Vec} */
Expand Down
4 changes: 2 additions & 2 deletions fjs/asn.1/proof.f.mjs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { empty, isVec, length, msb, uint, unpack, vec, vec8 } from '../types/bit_vec/module.f.mjs'
/** @import { Vec } from '../types/bit_vec/module.f.mjs' */
/** @import { Vec } from '../types/bit_vec/types.ts' */

import { asBase } from '../types/nominal/module.f.mjs'

Expand All @@ -18,7 +18,7 @@ import {
encodeObjectIdentifier,
decodeObjectIdentifier,
} from './module.f.mjs'
/** @import { SupportedRecord, ObjectIdentifier } from './module.f.mjs' */
/** @import { SupportedRecord, ObjectIdentifier } from './types.ts' */

import { assert, assertEq } from '../asserts/module.f.mjs'

Expand Down
2 changes: 1 addition & 1 deletion fjs/asn.1/todo/65z-asn1-tag-codec-table.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ declaration site per (tag, encode, decode) triple.

### Caveats

- `SupportedRecord` is a discriminated union keyed by tag (`fjs/asn.1/module.f.mjs:272-278`),
- `SupportedRecord` is a discriminated union keyed by tag (`fjs/asn.1/types.ts:45-51`),
so the codec values are heterogeneously typed. The table approach loses the
per-branch payload typing that the switch currently gives `recordToRaw`. A
small per-tag helper that types `encode` against the union branch may be
Expand Down
72 changes: 72 additions & 0 deletions fjs/asn.1/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/**
* Types for ASN.1 BER/DER encoding and decoding over bit vectors.
*
* @module
*/

import type { Vec } from '../types/bit_vec/types.ts'
import type {
boolean as booleanTag,
constructedSequence,
constructedSet,
integer,
objectIdentifier,
octetString,
} from './module.f.mjs'

/**
* ASN.1 tag number.
*/
export type _Tag = bigint

/**
* Raw ASN.1 TLV tuple.
*/
export type Raw = readonly [_Tag, Vec]

/**
* ASN.1 OBJECT IDENTIFIER components.
*/
export type ObjectIdentifier = readonly bigint[]

/**
* ASN.1 ordered collection of records.
*/
export type Sequence = readonly Record[]

/**
* ASN.1 SET represented as a sequence of records.
*/
export type Set = Sequence

/**
* Supported ASN.1 record variants.
*/
export type SupportedRecord =
| readonly [typeof booleanTag, boolean]
| readonly [typeof integer, bigint]
| readonly [typeof octetString, Vec]
| readonly [typeof objectIdentifier, ObjectIdentifier]
| readonly [typeof constructedSequence, Sequence]
| readonly [typeof constructedSet, Set]

// Alternative:
//
// export type SupportedRecord =
// | boolean
// | bigint // integer
// | { tag: typeof octetString, value: Vec }
// | { tag: typeof objectIdentifier, value: ObjectIdentifier }
// | readonly Record[] // sequence
// | { tag: typeof constructedSet, value: readonly Record[] }
//
// export type UnsupportedRecord =
// | { tag: null, value: Vec }

/**
* For unsupported tags, we just store the raw value including the tag and
* length, so that it can be re-encoded without loss of information.
*/
export type UnsupportedRecord = Vec

export type Record = SupportedRecord | UnsupportedRecord
9 changes: 0 additions & 9 deletions fjs/asserts/module.f.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,6 @@ export const assertEq = (...x) => {
assert(a === b, x)
}

/**
* Compile-time-only check: a type resolves only if it is exactly `true`.
* Used to assert type-level properties without any runtime cost, e.g.
* `type _ = Assert<Equal<A, B>>`.
*
* @template {true} T
* @typedef {T} Assert
*/

/**
* Asserts that `a` is neither `null` nor `undefined` and returns it,
* narrowed to `T`.
Expand Down
12 changes: 12 additions & 0 deletions fjs/asserts/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/**
* Type-level assertion helpers.
*
* @module
*/

/**
* Compile-time-only check: a type resolves only if it is exactly `true`.
* Used to assert type-level properties without any runtime cost, e.g.
* `type _ = Assert<Equal<A, B>>`.
*/
Comment on lines +7 to +11

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Add module headers to the new type modules

Add the required module-level JSDoc header before this declaration; the current comment documents Assert rather than the module and omits @module. The same omission exists in the newly added fjs/types/function/types.ts and fjs/types/ordered_map/types.ts, leaving all three type modules without the repository's required module documentation.

AGENTS.md reference: AGENTS.md:L252-L265

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 3fc9579. Added @module headers to all three: fjs/asserts/types.ts ("Type-level assertion helpers."), fjs/types/function/types.ts ("Types for function composition."), fjs/types/ordered_map/types.ts ("Types for the ordered map data structure."). The existing Assert doc comment stays where it is, now below the module header.

Checked the rest of the set while I was in there — the other 30 types.ts files already had headers, so these three were the only gaps.

export type Assert<T extends true> = T

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Point type-proof imports at the new type modules

When a contributor follows the mandatory type-level proof guidance in AGENTS.md, it still directs them to import Assert from fjs/asserts/module.f.mjs and Equal from fjs/types/ts/module.f.mjs, but this change removes both types from those modules. Update that guidance to reference the new types.ts files; otherwise new proofs written according to the repository instructions fail type checking.

AGENTS.md reference: AGENTS.md:L211-L217

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 6949188. AGENTS.md §3.4 now points at fjs/asserts/types.ts and fjs/types/ts/types.ts.

2 changes: 1 addition & 1 deletion fjs/basen/base128/module.f.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
*/

import { vec8, msb, empty } from '../../types/bit_vec/module.f.mjs'
/** @import { Vec } from '../../types/bit_vec/module.f.mjs' */
/** @import { Vec } from '../../types/bit_vec/types.ts' */

const { concat, popFront } = msb

Expand Down
2 changes: 1 addition & 1 deletion fjs/basen/base128/proof.f.mjs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { empty, vec, vec8 } from '../../types/bit_vec/module.f.mjs'
/** @import { Vec } from '../../types/bit_vec/module.f.mjs' */
/** @import { Vec } from '../../types/bit_vec/types.ts' */

import { asBase } from '../../types/nominal/module.f.mjs'

Expand Down
4 changes: 2 additions & 2 deletions fjs/basen/base64/module.f.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
*/

import { msb, length, vec, maxLength } from '../../types/bit_vec/module.f.mjs'
/** @import { Vec } from '../../types/bit_vec/module.f.mjs' */
/** @import { Vec } from '../../types/bit_vec/types.ts' */

/** @import { Nullable } from '../../types/nullable/module.f.mjs' */
/** @import { Nullable } from '../../types/nullable/types.ts' */

import { baseN } from "../module.f.mjs"

Expand Down
2 changes: 1 addition & 1 deletion fjs/basen/base64/proof.f.mjs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { assertEq } from '../../asserts/module.f.mjs'

import { empty, vec, repeat, vec8, maxLength } from '../../types/bit_vec/module.f.mjs'
/** @import { Vec } from '../../types/bit_vec/module.f.mjs' */
/** @import { Vec } from '../../types/bit_vec/types.ts' */

import { encode, decode } from './module.f.mjs'

Expand Down
4 changes: 2 additions & 2 deletions fjs/basen/cbase32/module.f.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
*/

import { msb, lsb, length, vec, empty } from '../../types/bit_vec/module.f.mjs'
/** @import { Vec } from '../../types/bit_vec/module.f.mjs' */
/** @import { Vec } from '../../types/bit_vec/types.ts' */

/** @import { Nullable } from '../../types/nullable/module.f.mjs' */
/** @import { Nullable } from '../../types/nullable/types.ts' */

import { baseN } from '../module.f.mjs'

Expand Down
2 changes: 1 addition & 1 deletion fjs/basen/cbase32/proof.f.mjs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { empty, vec } from '../../types/bit_vec/module.f.mjs'
/** @import { Vec } from '../../types/bit_vec/module.f.mjs' */
/** @import { Vec } from '../../types/bit_vec/types.ts' */

import { cBase32ToVec, cBase32ToVec5x, vec5xToCBase32, vecToCBase32 } from './module.f.mjs'

Expand Down
15 changes: 3 additions & 12 deletions fjs/basen/module.f.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@
*/

import { msb, lsb, vec, chunkList, unpack } from '../types/bit_vec/module.f.mjs'
/** @import { Vec } from '../types/bit_vec/module.f.mjs' */
/** @import { Vec } from '../types/bit_vec/types.ts' */

import { fold } from '../types/list/module.f.mjs'
/** @import { List } from '../types/list/module.f.mjs' */
/** @import { List } from '../types/list/types.ts' */

import { compose } from '../types/function/module.f.mjs'

/** @import { Nullable } from '../types/nullable/module.f.mjs' */
/** @import { BaseN } from './types.ts' */

const { unpackSplit } = msb

Expand All @@ -30,15 +30,6 @@ const { tryListToVec: reversedListToVec } = lsb
// `baseN(...)` codec (base64, cbase32, ...).
const chunkListMsb = chunkList(msb)

/**
* The encode/decode pair returned by {@link baseN}.
*
* @typedef {{
* readonly vecToString: (v: Vec) => string
* readonly stringToVec: (s: string) => Nullable<Vec>
* }} BaseN
*/

/**
* Builds a {@link BaseN} codec for a fixed chunk width and alphabet.
*
Expand Down
16 changes: 16 additions & 0 deletions fjs/basen/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/**
* Types for the shared bit-codec factory.
*
* @module
*/

import type { Vec } from '../types/bit_vec/types.ts'
import type { Nullable } from '../types/nullable/types.ts'

/**
* The encode/decode pair returned by `baseN` in `./module.f.mjs`.
*/
export type BaseN = {
readonly vecToString: (v: Vec) => string
readonly stringToVec: (s: string) => Nullable<Vec>
}
2 changes: 1 addition & 1 deletion fjs/bnf/descent/module.f.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
*
* @module
*/
import { type CodePoint } from '../../text/utf16/module.f.mjs'
import type { CodePoint } from '../../text/utf16/types.ts'
import { rangeDecode, type TerminalRange } from '../module.f.ts'
import { contains as rangeContains } from '../../types/range/module.f.mjs'
import { definedEntries } from '../../types/object/module.f.ts'
Expand Down
3 changes: 2 additions & 1 deletion fjs/bnf/descent/proof.f.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { type CodePoint, stringToCodePointList } from '../../text/utf16/module.f.mjs'
import type { CodePoint } from '../../text/utf16/types.ts'
import { stringToCodePointList } from '../../text/utf16/module.f.mjs'
import { map, toArray } from '../../types/list/module.f.mjs'
import { commaJoin0Plus, option, range, repeat0Plus, set } from '../module.f.ts'
import { deterministic } from '../testlib.f.ts'
Expand Down
Loading
Loading