tjs-lang 0.8.7 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +12 -4
- package/dist/experiments/ambient/probe.d.ts +52 -0
- package/dist/index.js +115 -171
- package/dist/index.js.map +4 -4
- package/dist/scripts/build-editors.d.ts +19 -0
- package/dist/src/css/dimensions.d.ts +23 -0
- package/dist/src/css/index.d.ts +85 -0
- package/dist/src/css/predicates.d.ts +38 -0
- package/dist/src/css/shorthands.d.ts +31 -0
- package/dist/src/css/style.d.ts +48 -0
- package/dist/src/lang/emitters/js.d.ts +9 -1
- package/dist/src/lang/index.d.ts +2 -2
- package/dist/src/lang/parser-transforms.d.ts +9 -5
- package/dist/src/lang/parser.d.ts +2 -0
- package/dist/src/lang/predicate.d.ts +60 -0
- package/dist/src/lang/transpiler.d.ts +3 -2
- package/dist/src/lang/types.d.ts +16 -0
- package/dist/src/schema/index.d.ts +12 -0
- package/dist/tjs-browser-from-ts.js +20 -20
- package/dist/tjs-browser-from-ts.js.map +3 -3
- package/dist/tjs-browser.js +100 -90
- package/dist/tjs-browser.js.map +4 -4
- package/dist/tjs-css.js +193 -0
- package/dist/tjs-css.js.map +7 -0
- package/dist/tjs-eval.js +43 -42
- package/dist/tjs-eval.js.map +4 -4
- package/dist/tjs-from-ts.js +13 -13
- package/dist/tjs-from-ts.js.map +2 -2
- package/dist/tjs-lang.js +102 -92
- package/dist/tjs-lang.js.map +4 -4
- package/dist/tjs-runtime.js +10 -0
- package/dist/tjs-runtime.js.map +7 -0
- package/dist/tjs-schema.js +6 -0
- package/dist/tjs-schema.js.map +7 -0
- package/dist/tjs-vm.js +55 -54
- package/dist/tjs-vm.js.map +4 -4
- package/docs/ambient-contracts.md +261 -0
- package/editors/ace/ajs-mode.js +214 -233
- package/editors/codemirror/ajs-language.js +1570 -233
- package/editors/editors-build.test.ts +29 -0
- package/editors/monaco/ajs-monarch.js +239 -195
- package/llms.txt +4 -0
- package/package.json +35 -4
- package/src/css/css.test.ts +122 -0
- package/src/css/dimensions.test.ts +112 -0
- package/src/css/dimensions.ts +146 -0
- package/src/css/index.ts +243 -0
- package/src/css/perf.bench.test.ts +109 -0
- package/src/css/predicates.ts +232 -0
- package/src/css/property-aware.test.ts +84 -0
- package/src/css/shorthands.test.ts +90 -0
- package/src/css/shorthands.ts +113 -0
- package/src/css/style.test.ts +125 -0
- package/src/css/style.ts +134 -0
- package/src/index-tsfree.test.ts +58 -0
- package/src/lang/emit-verified-predicate.test.ts +95 -0
- package/src/lang/emitters/dts.test.ts +31 -0
- package/src/lang/emitters/dts.ts +23 -4
- package/src/lang/emitters/js.ts +33 -1
- package/src/lang/from-ts.test.ts +1 -1
- package/src/lang/generic-verified-predicate.test.ts +39 -0
- package/src/lang/index.ts +14 -5
- package/src/lang/parser-transforms.ts +109 -14
- package/src/lang/parser.ts +9 -2
- package/src/lang/predicate-evaluator.test.ts +49 -0
- package/src/lang/predicate-report.test.ts +54 -0
- package/src/lang/predicate.ts +268 -0
- package/src/lang/redos-lint.test.ts +81 -0
- package/src/lang/transpiler.ts +13 -0
- package/src/lang/type-verified-predicate.test.ts +83 -0
- package/src/lang/types.ts +17 -0
- package/src/lang/typescript-syntax.test.ts +2 -1
- package/src/schema/index.ts +62 -0
- package/src/schema/schema.test.ts +66 -0
- package/src/use-cases/bootstrap.test.ts +14 -4
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
export declare const ROOT: string;
|
|
3
|
+
export interface EditorTarget {
|
|
4
|
+
name: string;
|
|
5
|
+
entry: string;
|
|
6
|
+
outfile: string;
|
|
7
|
+
external: string[];
|
|
8
|
+
description: string;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Bundle one editor target. With `write: true` (default) it writes the `.js` in
|
|
12
|
+
* place and returns its bytes; with `write: false` it returns the bytes without
|
|
13
|
+
* touching disk (used by the anti-drift guard test to compare against the
|
|
14
|
+
* committed file).
|
|
15
|
+
*/
|
|
16
|
+
export declare function bundleEditor(target: EditorTarget, { write }?: {
|
|
17
|
+
write?: boolean;
|
|
18
|
+
}): string;
|
|
19
|
+
export declare const editorTargets: EditorTarget[];
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CSS dimension / numeric value grammar (phase 2) — the other big family of leaf
|
|
3
|
+
* values: lengths, percentages, angles, times, resolutions, plain numbers, and
|
|
4
|
+
* the CSS-wide global keywords. Same rules as the color cluster: pure,
|
|
5
|
+
* synchronous, ReDoS-clean (flat character classes / bounded alternation only),
|
|
6
|
+
* with `var(--…)`/`calc(…)` as the open escapes.
|
|
7
|
+
*
|
|
8
|
+
* The numeric core `[+-]?(\d*\.\d+|\d+)` is a bounded alternation (each branch a
|
|
9
|
+
* single quantifier — no nesting), so it passes the verifier's ReDoS lint.
|
|
10
|
+
*/
|
|
11
|
+
/** Absolute + relative + container + viewport length units (CSS Values 4). */
|
|
12
|
+
export declare const CSS_LENGTH_UNITS: string[];
|
|
13
|
+
/** CSS-wide keywords valid on any property. */
|
|
14
|
+
export declare const CSS_GLOBAL_KEYWORDS: string[];
|
|
15
|
+
/**
|
|
16
|
+
* Dimension predicate cluster (source). Entry points cover each numeric family
|
|
17
|
+
* plus `isDimension` (any of them) and `isGlobalKeyword`. Units are ordered
|
|
18
|
+
* longest-first inside the alternation so e.g. `rem` isn't shadowed by `em`
|
|
19
|
+
* (belt-and-suspenders — the `$` anchor already forces a full match).
|
|
20
|
+
*/
|
|
21
|
+
export declare const CSS_DIMENSION_SOURCE: string;
|
|
22
|
+
/** Entry predicates exported by the dimension cluster (for compile/suggest). */
|
|
23
|
+
export declare const CSS_DIMENSION_ENTRIES: readonly ["isNumber", "isInteger", "isPercentage", "isLength", "isAngle", "isTime", "isResolution", "isGlobalKeyword", "isDimension"];
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `tjs-lang/css` — CSS validation built from verified-safe predicates.
|
|
3
|
+
*
|
|
4
|
+
* The "computational half" of a CSS schema: precise, total validators for the
|
|
5
|
+
* open value grammars TS/JSON-Schema cave to `string` on (colors here in
|
|
6
|
+
* phase 1; lengths, shorthands and the recursive style-object structure land in
|
|
7
|
+
* later phases — see TODO.md #4). Every validator is compiled from a
|
|
8
|
+
* predicate-safe source cluster (`./predicates`), so it is pure, synchronous,
|
|
9
|
+
* fuel-bounded, and ReDoS-clean — safe to run on untrusted input.
|
|
10
|
+
*
|
|
11
|
+
* Autocomplete rides the same source: `suggestColor()` mines the named-color set
|
|
12
|
+
* and the open functional stubs (`var(--`, `color-mix(`, …), validating mined
|
|
13
|
+
* values through the compiled predicate so completions are guaranteed valid.
|
|
14
|
+
*/
|
|
15
|
+
import { type PredicateVerifyResult, type Suggestion } from '../lang/predicate';
|
|
16
|
+
export { CSS_COLOR_SOURCE, CSS_COLOR_ENTRIES, CSS_NAMED_COLORS, } from './predicates';
|
|
17
|
+
export { CSS_DIMENSION_SOURCE, CSS_DIMENSION_ENTRIES, CSS_LENGTH_UNITS, CSS_GLOBAL_KEYWORDS, } from './dimensions';
|
|
18
|
+
export { CSS_STYLE_SOURCE, CSS_STYLE_ENTRIES, cssStyleSchema, cssColorSchema, cssDimensionSchema, } from './style';
|
|
19
|
+
export { CSS_SHORTHAND_SOURCE, CSS_SHORTHAND_ENTRIES, cssAnimationSchema, cssTransitionSchema, } from './shorthands';
|
|
20
|
+
/** Is `v` a valid CSS color (named, hex, rgb/hsl, modern fn, or `var(--…)`)? */
|
|
21
|
+
export declare const isColor: (v: unknown) => boolean;
|
|
22
|
+
/** Like {@link isColor}, but tolerates a trailing `!important`. */
|
|
23
|
+
export declare const isColorValue: (v: unknown) => boolean;
|
|
24
|
+
/** Is `v` a CSS named color (incl. `transparent`/`currentcolor`)? */
|
|
25
|
+
export declare const isNamedColor: (v: unknown) => boolean;
|
|
26
|
+
/** Is `v` a CSS hex color (`#rgb`, `#rgba`, `#rrggbb`, `#rrggbbaa`)? */
|
|
27
|
+
export declare const isHexColor: (v: unknown) => boolean;
|
|
28
|
+
/** Is `v` a CSS `<length>` (unit'd, unitless `0`, or `var()`/`calc()`)? */
|
|
29
|
+
export declare const isLength: (v: unknown) => boolean;
|
|
30
|
+
/** Is `v` a CSS `<percentage>` (`50%`)? */
|
|
31
|
+
export declare const isPercentage: (v: unknown) => boolean;
|
|
32
|
+
/** Is `v` a CSS `<number>` (numeric, or a numeric string)? */
|
|
33
|
+
export declare const isNumber: (v: unknown) => boolean;
|
|
34
|
+
/** Is `v` a CSS `<integer>`? */
|
|
35
|
+
export declare const isInteger: (v: unknown) => boolean;
|
|
36
|
+
/** Is `v` a CSS `<angle>` (`45deg`, `1turn`, `1.5rad`, `100grad`)? */
|
|
37
|
+
export declare const isAngle: (v: unknown) => boolean;
|
|
38
|
+
/** Is `v` a CSS `<time>` (`200ms`, `1s`)? */
|
|
39
|
+
export declare const isTime: (v: unknown) => boolean;
|
|
40
|
+
/** Is `v` any CSS dimension/number (length, %, angle, time, resolution, number)? */
|
|
41
|
+
export declare const isDimension: (v: unknown) => boolean;
|
|
42
|
+
/** Is `v` a CSS-wide keyword (`inherit`/`initial`/`unset`/`revert`/`revert-layer`)? */
|
|
43
|
+
export declare const isGlobalKeyword: (v: unknown) => boolean;
|
|
44
|
+
/**
|
|
45
|
+
* Is `v` a valid CSS **style object** — an open, recursive map of CSS properties
|
|
46
|
+
* to values and selectors/at-rules to nested style objects? Validates the whole
|
|
47
|
+
* structure (keys are properties or selectors; property values are style values,
|
|
48
|
+
* selector values are nested rules), recursively and fuel-bounded. This is the
|
|
49
|
+
* shape TS/JSON-Schema can't express.
|
|
50
|
+
*/
|
|
51
|
+
export declare const isStyleObject: (v: unknown) => boolean;
|
|
52
|
+
/** Is `v` a valid leaf CSS value (a known color/dimension/keyword, else a non-empty string / finite number)? */
|
|
53
|
+
export declare const isStyleValue: (v: unknown) => boolean;
|
|
54
|
+
/**
|
|
55
|
+
* Property-AWARE leaf check: given the property name, tightens the closed value
|
|
56
|
+
* grammars (color/animation/transition) so `isStyleValueFor('color', 'notacolor')`
|
|
57
|
+
* is `false` while `isStyleValueFor('padding', 'anything')` stays permissive.
|
|
58
|
+
* This is what makes {@link isStyleObject} catch real value errors.
|
|
59
|
+
*/
|
|
60
|
+
export declare const isStyleValueFor: (prop: unknown, val: unknown) => boolean;
|
|
61
|
+
/** Is `k` a CSS property name (`color`, `--custom`, `-webkit-foo`)? */
|
|
62
|
+
export declare const isCssProperty: (k: unknown) => boolean;
|
|
63
|
+
/** Is `k` a selector or at-rule key (nests a rule) rather than a property? */
|
|
64
|
+
export declare const isSelectorOrAtRule: (k: unknown) => boolean;
|
|
65
|
+
/** Is `v` a valid CSS `animation` shorthand (comma-separated, order-free tokens)? */
|
|
66
|
+
export declare const isAnimation: (v: unknown) => boolean;
|
|
67
|
+
/** Is `v` a valid CSS `transition` shorthand (comma-separated layers)? */
|
|
68
|
+
export declare const isTransition: (v: unknown) => boolean;
|
|
69
|
+
/** Is `v` a CSS `<easing-function>` (keyword, `cubic-bezier(…)`, `steps(…)`, `linear(…)`)? */
|
|
70
|
+
export declare const isTimingFunction: (v: unknown) => boolean;
|
|
71
|
+
/**
|
|
72
|
+
* Verify every CSS predicate-source cluster is predicate-safe (pure,
|
|
73
|
+
* synchronous, ReDoS-clean). Returns the combined result (safe iff all clusters
|
|
74
|
+
* are; diagnostics carry the cluster name). Always safe for the shipped source —
|
|
75
|
+
* exposed so downstream tools (and the drift test) can assert it, and so a
|
|
76
|
+
* consumer embedding a source in a `$predicate` schema can re-check before
|
|
77
|
+
* trusting it.
|
|
78
|
+
*/
|
|
79
|
+
export declare function verifyCss(): PredicateVerifyResult;
|
|
80
|
+
/**
|
|
81
|
+
* Autocomplete candidates for a CSS color value. Returns concrete named colors
|
|
82
|
+
* (validated through the compiled predicate) plus open-ended stubs mined from
|
|
83
|
+
* the functional forms (`var(--`, `color-mix(`, `oklch(`, …). Prefix-filtered.
|
|
84
|
+
*/
|
|
85
|
+
export declare function suggestColor(prefix?: string, limit?: number): Suggestion[];
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The CSS predicate library — canonical **source** form.
|
|
3
|
+
*
|
|
4
|
+
* Predicates are authored as source strings, not native functions, because the
|
|
5
|
+
* source is the serializable, portable artifact: it feeds the verifier
|
|
6
|
+
* (`verifyPredicate` — certifies pure/synchronous/ReDoS-clean), compiles to the
|
|
7
|
+
* native fast path (`compilePredicate`), mines autocomplete (`suggest`), and
|
|
8
|
+
* embeds into JSON Schema's `$predicate` keyword. This is the "computational
|
|
9
|
+
* half" JSON Schema and TS structural types can't express — CSS is the torture
|
|
10
|
+
* test (open value grammars, order-flexible shorthands, recursive structure).
|
|
11
|
+
*
|
|
12
|
+
* Style rules for anything added here (so it stays verifiable):
|
|
13
|
+
* - pure & synchronous: no IO, no `await`, no `new`, no loops (use
|
|
14
|
+
* `every`/`some`/`map`/recursion — fuel bounds them at function entry);
|
|
15
|
+
* - regexes must be ReDoS-clean (no nested unbounded quantifiers — the
|
|
16
|
+
* verifier rejects `(a+)+` and friends, so keep character classes flat);
|
|
17
|
+
* - compose with `||` and named predicates as callbacks (`toks.every(isX)`).
|
|
18
|
+
*
|
|
19
|
+
* Phase 1 ships the color grammar. Later phases add lengths/dimensions,
|
|
20
|
+
* shorthands, and the recursive style-object structure — see TODO.md (#4).
|
|
21
|
+
*/
|
|
22
|
+
/**
|
|
23
|
+
* The CSS Color Module Level 4 named colors (+ the CSS-wide `transparent` and
|
|
24
|
+
* `currentcolor`), lower-cased. Data, kept in the source so the whole cluster
|
|
25
|
+
* stays serializable as one artifact.
|
|
26
|
+
*/
|
|
27
|
+
export declare const CSS_NAMED_COLORS: string[];
|
|
28
|
+
/**
|
|
29
|
+
* Color predicate cluster (source). Entry points: `isColor` (any CSS color) and
|
|
30
|
+
* `isColorValue` (a color, tolerating a trailing `!important`). Regexes are
|
|
31
|
+
* flat-class (ReDoS-clean). The functional-color forms (`hwb`/`lab`/`lch`/
|
|
32
|
+
* `oklab`/`oklch`/`color`/`color-mix`) are matched by name + balanced parens
|
|
33
|
+
* rather than validating their args — precise enough for validation, open
|
|
34
|
+
* enough not to reject valid modern CSS.
|
|
35
|
+
*/
|
|
36
|
+
export declare const CSS_COLOR_SOURCE: string;
|
|
37
|
+
/** Entry predicates exported by the color cluster (for compile/suggest). */
|
|
38
|
+
export declare const CSS_COLOR_ENTRIES: readonly ["isColor", "isColorValue", "isNamedColor", "isHexColor", "isRgbColor", "isHslColor"];
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CSS order-flexible shorthands (phase 3) — the second torture case from the
|
|
3
|
+
* PoC: a shorthand like `animation` or `transition` is a comma-separated list of
|
|
4
|
+
* layers, each a whitespace-separated bag of tokens whose *order is free*
|
|
5
|
+
* (`3s ease-in 1s infinite alternate slidein` ≡ any permutation). TS unions and
|
|
6
|
+
* JSON Schema can't express "a set of tokens, each classifiable, in any order";
|
|
7
|
+
* a predicate tokenizes and classifies (`toks.every(isAnimToken)`).
|
|
8
|
+
*
|
|
9
|
+
* Built on the dimension leaf cluster (for `isTime`/`isCssVar`/`isCssCalc`).
|
|
10
|
+
* Same rules as the other clusters: pure, synchronous, ReDoS-clean (the split
|
|
11
|
+
* regexes are single-quantifier `\s+` / `,`; classifier regexes are flat).
|
|
12
|
+
*/
|
|
13
|
+
import type { PredicateSchema } from '../lang/predicate-schema';
|
|
14
|
+
/**
|
|
15
|
+
* The shorthand classifiers alone (no leaf cluster prepended). Exported so the
|
|
16
|
+
* combined style cluster (`style.ts`) can compose them for property-aware
|
|
17
|
+
* validation without re-including the dimension source.
|
|
18
|
+
*/
|
|
19
|
+
export declare const CSS_SHORTHAND_FRAGMENT = "\nvar ANIM_TIMING = ['linear','ease','ease-in','ease-out','ease-in-out','step-start','step-end']\nvar ANIM_DIRECTION = ['normal','reverse','alternate','alternate-reverse']\nvar ANIM_FILLMODE = ['none','forwards','backwards','both']\nvar ANIM_PLAYSTATE = ['running','paused']\n\nfunction isTimingFunction(t) {\n if (typeof t !== 'string') { return false }\n if (ANIM_TIMING.includes(t)) { return true }\n return (t.startsWith('cubic-bezier(') || t.startsWith('steps(') || t.startsWith('linear(')) && t.endsWith(')')\n}\nfunction isIterationCount(t) {\n return t === 'infinite' || (typeof t === 'string' && /^[0-9]*\\.?[0-9]+$/.test(t))\n}\nfunction isAnimName(t) {\n // any custom-ident (also matches keywords, which classify earlier anyway)\n return typeof t === 'string' && /^-?[a-z_][a-z0-9_-]*$/i.test(t)\n}\n// Tokenize a whole shorthand value. A function token like cubic-bezier(a, b) is\n// kept whole (arg spaces/commas must not split it); top-level commas (layer\n// separators) and whitespace are delimiters, so they're dropped. Loops are\n// banned in predicates, so this is one .match with a FLAT (ReDoS-clean) regex \u2014\n// note a paren-aware comma *splitter* would be a nested quantifier the verifier\n// rejects, so we tokenize instead and guard empty layers separately.\nfunction cssTokens(v) {\n return typeof v === 'string' ? v.match(/[a-z-]+\\([^)]*\\)|[^\\s,]+/gi) : null\n}\n// Reject leading/trailing/double commas (empty layers). Flat, ReDoS-clean.\nfunction hasEmptyLayer(v) {\n return typeof v === 'string' && /^\\s*,|,\\s*$|,\\s*,/.test(v)\n}\nfunction isAnimToken(t) {\n return isTime(t) || isIterationCount(t) || isTimingFunction(t)\n || ANIM_DIRECTION.includes(t) || ANIM_FILLMODE.includes(t) || ANIM_PLAYSTATE.includes(t)\n || isCssVar(t) || isCssCalc(t) || isAnimName(t)\n}\nfunction isAnimation(v) {\n if (typeof v !== 'string' || v.length === 0 || hasEmptyLayer(v)) { return false }\n var toks = cssTokens(v)\n return toks !== null && toks.length > 0 && toks.every(isAnimToken)\n}\n\nfunction isTransitionProperty(t) {\n return t === 'all' || t === 'none' || isAnimName(t)\n}\nfunction isTransitionToken(t) {\n return isTime(t) || isTimingFunction(t) || isCssVar(t) || isCssCalc(t) || isTransitionProperty(t)\n}\nfunction isTransition(v) {\n if (typeof v !== 'string' || v.length === 0 || hasEmptyLayer(v)) { return false }\n var toks = cssTokens(v)\n return toks !== null && toks.length > 0 && toks.every(isTransitionToken)\n}\n";
|
|
20
|
+
/**
|
|
21
|
+
* Shorthand predicate cluster (source) = dimension leaves + the shorthand
|
|
22
|
+
* classifiers. Entry predicates: `isAnimation`, `isTransition` (each accepts a
|
|
23
|
+
* comma-separated list of order-free token layers).
|
|
24
|
+
*/
|
|
25
|
+
export declare const CSS_SHORTHAND_SOURCE: string;
|
|
26
|
+
/** Entry predicates exported by the shorthand cluster (for compile/verify). */
|
|
27
|
+
export declare const CSS_SHORTHAND_ENTRIES: readonly ["isTimingFunction", "isAnimation", "isTransition"];
|
|
28
|
+
/** `$predicate` schema for a CSS `animation` shorthand value. */
|
|
29
|
+
export declare function cssAnimationSchema(): PredicateSchema;
|
|
30
|
+
/** `$predicate` schema for a CSS `transition` shorthand value. */
|
|
31
|
+
export declare function cssTransitionSchema(): PredicateSchema;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CSS style-object structure (phase 4) — the recursive, open shape TS structural
|
|
3
|
+
* types and JSON Schema can't express, and the `$predicate` schemas that carry
|
|
4
|
+
* it. This is the thesis deliverable: a JSON-Schema node whose *structural* part
|
|
5
|
+
* (`type: 'object'`) a naive validator checks, and whose `$predicate` a
|
|
6
|
+
* predicate-aware validator runs to validate the whole recursive CSS structure —
|
|
7
|
+
* progressive enhancement, one serializable artifact.
|
|
8
|
+
*
|
|
9
|
+
* The combined source concatenates the color + dimension leaf clusters and adds
|
|
10
|
+
* the structure predicates, so `isStyleValue`/`isStyleObject` compose the leaves
|
|
11
|
+
* directly. `isStyleObject` is LAST — the entry the `$predicate` schema runs.
|
|
12
|
+
*
|
|
13
|
+
* Value precision is intentionally two-tier (as in the PoC): the *structure* is
|
|
14
|
+
* validated strictly (keys must be CSS properties or selectors/at-rules; a
|
|
15
|
+
* property maps to a value, a selector to a nested rule), while a generic leaf
|
|
16
|
+
* value falls back to "non-empty string or finite number" so a valid-but-
|
|
17
|
+
* unmodelled value (a shorthand, a not-yet-covered property) is never rejected.
|
|
18
|
+
* Per-property precision comes from the specific value schemas (`cssColorSchema`
|
|
19
|
+
* etc.) and, later, property-aware validation (phase 3 shorthands).
|
|
20
|
+
*/
|
|
21
|
+
import type { PredicateSchema } from '../lang/predicate-schema';
|
|
22
|
+
/**
|
|
23
|
+
* The full CSS style predicate cluster: color + dimension + shorthand leaves +
|
|
24
|
+
* recursive, property-aware structure. Entry = `isStyleObject` (last function).
|
|
25
|
+
* Serializable — this is exactly what a `$predicate` schema carries.
|
|
26
|
+
*/
|
|
27
|
+
export declare const CSS_STYLE_SOURCE: string;
|
|
28
|
+
/** Entry predicates exported by the style cluster (for compile/verify). */
|
|
29
|
+
export declare const CSS_STYLE_ENTRIES: readonly ["isCssProperty", "isSelectorOrAtRule", "isStyleValue", "isStyleValueFor", "isStyleObject"];
|
|
30
|
+
/**
|
|
31
|
+
* A `$predicate` JSON-Schema for a CSS style object (à la a tosijs styleSpec):
|
|
32
|
+
* naive validators check only `type: 'object'`; predicate-aware validators run
|
|
33
|
+
* `isStyleObject`, validating the whole recursive structure (nested selectors,
|
|
34
|
+
* property/value shapes). Progressive enhancement from one serializable schema.
|
|
35
|
+
*/
|
|
36
|
+
export declare function cssStyleSchema(): PredicateSchema;
|
|
37
|
+
/**
|
|
38
|
+
* A `$predicate` schema for a single CSS **color** value (entry `isColorValue`,
|
|
39
|
+
* so a trailing `!important` is tolerated). Naive validators check `type:
|
|
40
|
+
* 'string'`; aware ones validate the color grammar.
|
|
41
|
+
*/
|
|
42
|
+
export declare function cssColorSchema(): PredicateSchema;
|
|
43
|
+
/**
|
|
44
|
+
* A `$predicate` schema for a CSS **dimension** value (length/%/angle/time/
|
|
45
|
+
* number; entry `isDimension`). No structural `type` — a dimension may be a
|
|
46
|
+
* string (`10px`) or a number — so aware validators do all the work.
|
|
47
|
+
*/
|
|
48
|
+
export declare function cssDimensionSchema(): PredicateSchema;
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
* See also: demo/src/tjs-playground.ts which has a manual __tjs stub that
|
|
46
46
|
* must stay in sync with the runtime - a symptom of this leaky abstraction.
|
|
47
47
|
*/
|
|
48
|
-
import type { TypeDescriptor, ParameterDescriptor } from '../types';
|
|
48
|
+
import type { TypeDescriptor, ParameterDescriptor, PredicateVerification } from '../types';
|
|
49
49
|
export { stripModuleSyntax, stripTjsPreamble } from './js-tests';
|
|
50
50
|
export interface TJSTranspileOptions {
|
|
51
51
|
/** Filename for error messages */
|
|
@@ -108,6 +108,14 @@ export interface TJSTranspileResult {
|
|
|
108
108
|
metadata: Record<string, TJSTypeInfo>;
|
|
109
109
|
/** Any warnings during transpilation */
|
|
110
110
|
warnings?: string[];
|
|
111
|
+
/**
|
|
112
|
+
* Per-`Type`/`Generic` predicate verification status: `verified` → compiled to
|
|
113
|
+
* a fuel-bounded, DoS-safe native guard; `!verified` → fell back to a plain
|
|
114
|
+
* function (valid, but not fuel-bounded / not safe on untrusted data — its
|
|
115
|
+
* `reason` is the verifier diagnostic). Unverified entries are also mirrored
|
|
116
|
+
* into `warnings`. Lets tools flag unverifiable predicates.
|
|
117
|
+
*/
|
|
118
|
+
predicates?: PredicateVerification[];
|
|
111
119
|
/** Generated test runner code (if tests were present) - DEPRECATED, tests now run at transpile time */
|
|
112
120
|
testRunner?: string;
|
|
113
121
|
/** Number of tests extracted */
|
package/dist/src/lang/index.d.ts
CHANGED
|
@@ -25,12 +25,12 @@ import type { TranspileOptions, TranspileResult, FunctionSignature } from './typ
|
|
|
25
25
|
export * from './types';
|
|
26
26
|
export { parse, preprocess, extractTDoc, validateSingleFunction, extractFunctions, } from './parser';
|
|
27
27
|
export { dialectForFilename, sourceKindForFilename, type Dialect, type SourceKind, } from './dialect';
|
|
28
|
-
export { verifyPredicate, compilePredicate, suggest, effectfulFromAtoms, formatPredicateDiagnostics, PredicateFuelExhausted, type PredicateDiagnostic, type PredicateVerifyResult, type VerifyPredicateOptions, type CompilePredicateOptions, type Suggestion, type SuggestOptions, } from './predicate';
|
|
28
|
+
export { verifyPredicate, compilePredicate, emitVerifiedPredicate, createPredicateEvaluator, suggest, effectfulFromAtoms, formatPredicateDiagnostics, PredicateFuelExhausted, type PredicateDiagnostic, type PredicateVerifyResult, type VerifyPredicateOptions, type CompilePredicateOptions, type EmitPredicateResult, type PredicateEvaluatorOptions, type Suggestion, type SuggestOptions, } from './predicate';
|
|
29
29
|
export { compilePredicateSchema, validatePredicateSchema, type PredicateSchema, type SchemaError, type SchemaValidationResult, type PredicateSchemaOptions, } from './predicate-schema';
|
|
30
30
|
export { transformFunction } from './emitters/ast';
|
|
31
31
|
export { transpileToJS, stripModuleSyntax, stripTjsPreamble, type TJSTranspileOptions, type TJSTranspileResult, type TJSTypeInfo, } from './emitters/js';
|
|
32
32
|
export { generateDTS, typeDescriptorToTS, type GenerateDTSOptions, } from './emitters/dts';
|
|
33
|
-
export {
|
|
33
|
+
export type { FromTSOptions, FromTSResult } from './emitters/from-ts';
|
|
34
34
|
export * from './inference';
|
|
35
35
|
export { Schema } from './schema';
|
|
36
36
|
export { typeDescriptorToJSONSchema, exampleToJSONSchema, functionMetaToJSONSchema, type JSONSchemaObject, } from './json-schema';
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* These operate on raw source strings before Acorn parsing.
|
|
6
6
|
*/
|
|
7
7
|
import type { WasmBlock, TestBlock } from './parser-types';
|
|
8
|
+
import type { PredicateVerification } from './types';
|
|
8
9
|
export declare function transformTryWithoutCatch(source: string): string;
|
|
9
10
|
/**
|
|
10
11
|
* Extract WASM blocks from source and replace with runtime dispatch code
|
|
@@ -144,12 +145,15 @@ export declare function transformIsOperators(source: string): string;
|
|
|
144
145
|
*/
|
|
145
146
|
export declare function insertAsiProtection(source: string): string;
|
|
146
147
|
/**
|
|
147
|
-
* Transform == and != to
|
|
148
|
+
* Transform == and != to Eq() and NotEq() calls
|
|
148
149
|
*
|
|
149
150
|
* In TJS normal mode:
|
|
150
|
-
* a == b ->
|
|
151
|
-
*
|
|
151
|
+
* a == b -> Eq(a, b) (footgun-free ===: unwraps boxed primitives,
|
|
152
|
+
* null == undefined, but does NOT coerce types and
|
|
153
|
+
* is NOT structural — see PRINCIPLES/guides)
|
|
154
|
+
* a != b -> NotEq(a, b)
|
|
152
155
|
* a === b -> a === b (identity, unchanged)
|
|
156
|
+
* (For deep structural equality use the explicit `Is`/`IsNot` operators.)
|
|
153
157
|
*
|
|
154
158
|
* Uses a two-pass algorithm:
|
|
155
159
|
* 1. Find all == and != positions (outside strings/comments/regex)
|
|
@@ -169,7 +173,7 @@ export declare function transformEqualityToStructural(source: string): string;
|
|
|
169
173
|
*
|
|
170
174
|
* When predicate + example: auto-generate type guard from example
|
|
171
175
|
*/
|
|
172
|
-
export declare function transformTypeDeclarations(source: string): string;
|
|
176
|
+
export declare function transformTypeDeclarations(source: string, report?: PredicateVerification[]): string;
|
|
173
177
|
/**
|
|
174
178
|
* Transform FunctionPredicate declarations
|
|
175
179
|
*
|
|
@@ -203,7 +207,7 @@ export declare function transformFunctionPredicateDeclarations(source: string):
|
|
|
203
207
|
* const Pair = Generic(['T', 'U'], (obj, checkT, checkU) => { ... }, '...')
|
|
204
208
|
* const Container = Generic(['T', ['U', '']], (obj, checkT, checkU) => { ... }, '...')
|
|
205
209
|
*/
|
|
206
|
-
export declare function transformGenericDeclarations(source: string): string;
|
|
210
|
+
export declare function transformGenericDeclarations(source: string, report?: PredicateVerification[]): string;
|
|
207
211
|
/**
|
|
208
212
|
* Transform Union declarations
|
|
209
213
|
*
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* Transform functions are in parser-transforms.ts, param processing in parser-params.ts.
|
|
6
6
|
*/
|
|
7
7
|
import type { Program, FunctionDeclaration } from 'acorn';
|
|
8
|
+
import type { PredicateVerification } from './types';
|
|
8
9
|
export type { ParseOptions, WasmBlock, TestBlock, PreprocessOptions, TjsModes, } from './parser-types';
|
|
9
10
|
import type { ParseOptions, WasmBlock, TestBlock, PreprocessOptions, TjsModes } from './parser-types';
|
|
10
11
|
export { transformExtensionCalls } from './parser-transforms';
|
|
@@ -30,6 +31,7 @@ export declare function preprocess(source: string, options?: PreprocessOptions):
|
|
|
30
31
|
polymorphicNames: Set<string>;
|
|
31
32
|
extensions: Map<string, Set<string>>;
|
|
32
33
|
letAnnotations: Map<string, string>;
|
|
34
|
+
predicates: PredicateVerification[];
|
|
33
35
|
};
|
|
34
36
|
/**
|
|
35
37
|
* Parse source code into an Acorn AST
|
|
@@ -101,3 +101,63 @@ export interface CompilePredicateOptions extends VerifyPredicateOptions {
|
|
|
101
101
|
* opt-in). Emission is offset-spliced source, not a full AJS-AST→JS codegen.
|
|
102
102
|
*/
|
|
103
103
|
export declare function compilePredicate(source: string, exportNames: string[], opts?: CompilePredicateOptions): Record<string, (...args: any[]) => any>;
|
|
104
|
+
export interface EmitPredicateResult {
|
|
105
|
+
/** True iff the cluster passed predicate-safety verification. */
|
|
106
|
+
safe: boolean;
|
|
107
|
+
/**
|
|
108
|
+
* When `safe`, a self-contained JS **expression** that evaluates to the guard
|
|
109
|
+
* function `(...args) => boolean`. Inline it directly into transpiler output —
|
|
110
|
+
* it carries its own fuel counter (no global `__fuel`, no runtime dependency
|
|
111
|
+
* on the predicate engine or the `PredicateFuelExhausted` class). Undefined
|
|
112
|
+
* when `!safe`.
|
|
113
|
+
*/
|
|
114
|
+
code?: string;
|
|
115
|
+
/** Verifier diagnostics (the reasons, when `!safe`). */
|
|
116
|
+
diagnostics: PredicateDiagnostic[];
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Verify a predicate cluster and, if safe, emit a **self-contained source
|
|
120
|
+
* expression** for its guard — the transpile-time counterpart to
|
|
121
|
+
* `compilePredicate` (which evals to live closures). This is what lets a
|
|
122
|
+
* verified `Type`/`FunctionPredicate` predicate compile to a fuel-bounded native
|
|
123
|
+
* guard in standalone output: no import of this module, no shared runtime.
|
|
124
|
+
*
|
|
125
|
+
* Fuel model mirrors `compilePredicate` (function-entry `__fuel()` bounds all
|
|
126
|
+
* iteration since loops are rejected), but because a guard answers a boolean
|
|
127
|
+
* question, a runaway input **returns `false`** ("not a valid instance of this
|
|
128
|
+
* type") instead of throwing — DoS-safe validation that never crashes the caller.
|
|
129
|
+
* A deep-recursion stack overflow is the same runaway signal, normalized the
|
|
130
|
+
* same way.
|
|
131
|
+
*
|
|
132
|
+
* The runtime effectful-global shadow that `compilePredicate` applies is omitted
|
|
133
|
+
* here on purpose: a `safe` cluster provably references no effectful global (the
|
|
134
|
+
* static verifier guarantees it), so the shadow would only bloat emitted output.
|
|
135
|
+
*
|
|
136
|
+
* @param source the predicate cluster (one or more `function` declarations)
|
|
137
|
+
* @param entryName which declared function is the guard entry point
|
|
138
|
+
* @param opts verify options + `fuel` budget (default 1,000,000)
|
|
139
|
+
*/
|
|
140
|
+
export declare function emitVerifiedPredicate(source: string, entryName: string, opts?: CompilePredicateOptions): EmitPredicateResult;
|
|
141
|
+
export interface PredicateEvaluatorOptions extends CompilePredicateOptions {
|
|
142
|
+
/**
|
|
143
|
+
* Called once per source that fails to verify/compile. Default: `console.warn`.
|
|
144
|
+
* The evaluator fails **closed** on such a source (returns `false`), so an
|
|
145
|
+
* unverifiable `$predicate` can never validate a value as `true`.
|
|
146
|
+
*/
|
|
147
|
+
onUnsafe?: (source: string, error: Error) => void;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Build a pluggable `$predicate` evaluator: `(source, value) => boolean`.
|
|
151
|
+
*
|
|
152
|
+
* This is the bridge for a predicate-aware JSON-Schema validator that lives in
|
|
153
|
+
* another package (e.g. `tosijs-schema`, which cannot depend on `tjs-lang` — the
|
|
154
|
+
* dependency runs the other way). Such a validator stays zero-dep and exposes a
|
|
155
|
+
* hook; a consumer that has this engine injects an evaluator built here.
|
|
156
|
+
*
|
|
157
|
+
* Each distinct source is verified + compiled **once** and cached, so repeated
|
|
158
|
+
* validation is just a native call. Semantics match `compilePredicateSchema`:
|
|
159
|
+
* the LAST top-level function is the entry; a source that isn't predicate-safe
|
|
160
|
+
* (or throws / exhausts fuel at runtime) yields `false` — never a thrown error
|
|
161
|
+
* mid-validation, never a silent pass.
|
|
162
|
+
*/
|
|
163
|
+
export declare function createPredicateEvaluator(opts?: PredicateEvaluatorOptions): (source: string, value: unknown) => boolean;
|
|
@@ -12,9 +12,10 @@
|
|
|
12
12
|
export { transpile, ajs, tjs, createAgent, getToolDefinitions } from './core';
|
|
13
13
|
export { parse, preprocess, extractTDoc } from './parser';
|
|
14
14
|
export { dialectForFilename, sourceKindForFilename, type Dialect, type SourceKind, } from './dialect';
|
|
15
|
-
export { verifyPredicate, compilePredicate, suggest, effectfulFromAtoms, formatPredicateDiagnostics, PredicateFuelExhausted, type PredicateDiagnostic, type PredicateVerifyResult, type VerifyPredicateOptions, type CompilePredicateOptions, type Suggestion, type SuggestOptions, } from './predicate';
|
|
15
|
+
export { verifyPredicate, compilePredicate, emitVerifiedPredicate, createPredicateEvaluator, suggest, effectfulFromAtoms, formatPredicateDiagnostics, PredicateFuelExhausted, type PredicateDiagnostic, type PredicateVerifyResult, type VerifyPredicateOptions, type CompilePredicateOptions, type EmitPredicateResult, type PredicateEvaluatorOptions, type Suggestion, type SuggestOptions, } from './predicate';
|
|
16
16
|
export { compilePredicateSchema, validatePredicateSchema, type PredicateSchema, type SchemaError, type SchemaValidationResult, type PredicateSchemaOptions, } from './predicate-schema';
|
|
17
17
|
export { transformFunction } from './emitters/ast';
|
|
18
|
+
export { generateDTS, typeDescriptorToTS, type GenerateDTSOptions, } from './emitters/dts';
|
|
18
19
|
export { transpileToJS } from './emitters/js';
|
|
19
20
|
export type { TJSTranspileOptions, TJSTranspileResult, TJSTypeInfo, } from './emitters/js';
|
|
20
21
|
export * from './inference';
|
|
@@ -25,4 +26,4 @@ export { extractTests, assertFunction, expectFunction, testUtils, } from './test
|
|
|
25
26
|
export type { ExtractedTest, ExtractedMock, TestExtractionResult, } from './tests';
|
|
26
27
|
export { runtime, installRuntime, isError, error, typeOf, checkType, validateArgs, wrap, emitRuntimeWrapper, TJS_VERSION, } from './runtime';
|
|
27
28
|
export type { TJSError } from './runtime';
|
|
28
|
-
export type { TypeDescriptor, ParameterDescriptor, FunctionSignature, TranspileOptions, TranspileResult, TranspileWarning, } from './types';
|
|
29
|
+
export type { TypeDescriptor, ParameterDescriptor, FunctionSignature, TranspileOptions, TranspileResult, TranspileWarning, PredicateVerification, } from './types';
|
package/dist/src/lang/types.d.ts
CHANGED
|
@@ -77,6 +77,22 @@ export interface TranspileWarning {
|
|
|
77
77
|
column: number;
|
|
78
78
|
source?: string;
|
|
79
79
|
}
|
|
80
|
+
/**
|
|
81
|
+
* Per-declaration report of whether a `Type`/`Generic` predicate body verified
|
|
82
|
+
* as predicate-safe (→ compiled to a fuel-bounded, DoS-safe native guard) or
|
|
83
|
+
* fell back to a plain unverified function (still valid — TJS ⊇ JS — but not
|
|
84
|
+
* fuel-bounded or safe to run on untrusted data). Surfaced on the transpile
|
|
85
|
+
* result so tools can flag unverifiable predicates.
|
|
86
|
+
*/
|
|
87
|
+
export interface PredicateVerification {
|
|
88
|
+
/** The `Type` / `Generic` declaration name. */
|
|
89
|
+
name: string;
|
|
90
|
+
kind: 'Type' | 'Generic';
|
|
91
|
+
/** True → verified + compiled to a native guard; false → raw-function fallback. */
|
|
92
|
+
verified: boolean;
|
|
93
|
+
/** When `!verified`, the verifier's reason(s). */
|
|
94
|
+
reason?: string;
|
|
95
|
+
}
|
|
80
96
|
/** Source map for debugging */
|
|
81
97
|
export interface SourceMap {
|
|
82
98
|
version: 3;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type PredicateEvaluatorOptions } from '../lang/predicate';
|
|
2
|
+
export * from 'tosijs-schema';
|
|
3
|
+
export { createPredicateEvaluator, type PredicateEvaluatorOptions, } from '../lang/predicate';
|
|
4
|
+
/**
|
|
5
|
+
* Register tjs-lang's predicate engine as tosijs-schema's `$predicate` evaluator.
|
|
6
|
+
* Called automatically when this module is imported; exposed so callers can
|
|
7
|
+
* re-install with custom {@link PredicateEvaluatorOptions} (e.g. a smaller fuel
|
|
8
|
+
* budget, or an atom-aware effectful set) after opting out.
|
|
9
|
+
*/
|
|
10
|
+
export declare function installPredicateSupport(opts?: PredicateEvaluatorOptions): void;
|
|
11
|
+
/** True once predicate support has been installed (and not since cleared). */
|
|
12
|
+
export declare function predicateSupportInstalled(): boolean;
|