remove base type, keep primitive type and make hints as unknown optional
This commit is contained in:
Generated
+414
-457
File diff suppressed because it is too large
Load Diff
+6
-5
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@xo-cash/utils",
|
"name": "@xo-cash/utils",
|
||||||
"version": "0.0.5",
|
"version": "0.0.6",
|
||||||
"description": "XO Cash utilities",
|
"description": "XO Cash utilities",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"types": "./dist/index.d.mts",
|
"types": "./dist/index.d.mts",
|
||||||
@@ -45,17 +45,18 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@bitauth/libauth": "^3.1.0-next.8",
|
"@bitauth/libauth": "^3.1.0-next.8",
|
||||||
"@xo-cash/primitives": "0.0.2",
|
"@xo-cash/primitives": "0.0.2",
|
||||||
"@xo-cash/types": "0.0.5",
|
"@xo-cash/types": "0.0.6",
|
||||||
"zod": "^4.3.6"
|
"zod": "^4.3.6"
|
||||||
},
|
},
|
||||||
"overrides": {
|
"overrides": {
|
||||||
"echarts": "6.1.0",
|
"echarts": "6.1.0",
|
||||||
"minimatch": "10.2.6"
|
"minimatch": "10.2.6",
|
||||||
|
"qs": "6.16.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@generalprotocols/cspell-dictionary": "^1.0.1",
|
"@generalprotocols/cspell-dictionary": "^1.0.1",
|
||||||
"@types/node": "^25.5.0",
|
"@types/node": "^25.5.0",
|
||||||
"@vitest/coverage-v8": "^4.0.17",
|
"@vitest/coverage-v8": "^4.1.11",
|
||||||
"@viz-kit/esbuild-analyzer": "^1.0.0",
|
"@viz-kit/esbuild-analyzer": "^1.0.0",
|
||||||
"@xo-cash/eslint-config": "1.0.2",
|
"@xo-cash/eslint-config": "1.0.2",
|
||||||
"@xo-cash/templates": "0.0.3",
|
"@xo-cash/templates": "0.0.3",
|
||||||
@@ -66,6 +67,6 @@
|
|||||||
"typedoc": "^0.28.16",
|
"typedoc": "^0.28.16",
|
||||||
"typedoc-plugin-coverage": "^4.0.2",
|
"typedoc-plugin-coverage": "^4.0.2",
|
||||||
"typescript": "^5.3.2",
|
"typescript": "^5.3.2",
|
||||||
"vitest": "^4.0.17"
|
"vitest": "^4.1.11"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,6 +56,6 @@ export const CASHASSEMBLY_LITERAL_TOKEN_PATTERN = /^[0-9"']/;
|
|||||||
* `requestedSatoshis` does not match (no method)
|
* `requestedSatoshis` does not match (no method)
|
||||||
* `key.schnorr_signature.all_outputs` does not match (more than one dot)
|
* `key.schnorr_signature.all_outputs` does not match (more than one dot)
|
||||||
* `key.public_key` matches the pattern shape but it is only resolved
|
* `key.public_key` matches the pattern shape but it is only resolved
|
||||||
* when `hint` maps to a primitive
|
* when `type` maps to a primitive
|
||||||
*/
|
*/
|
||||||
export const CASHASSEMBLY_VARIABLE_METHOD_REFERENCE_PATTERN = /^([^.]+)\.([^.]+)$/;
|
export const CASHASSEMBLY_VARIABLE_METHOD_REFERENCE_PATTERN = /^([^.]+)\.([^.]+)$/;
|
||||||
|
|||||||
@@ -35,12 +35,12 @@ export class CashAssemblyVariableTypeMismatchError extends Error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Error thrown when a supported primitive hint does not expose the requested method.
|
* Error thrown when a method resolvable primitive type does not expose the requested method.
|
||||||
*/
|
*/
|
||||||
export class CashAssemblyPrimitiveMethodMissingError extends Error {
|
export class CashAssemblyPrimitiveMethodMissingError extends Error {
|
||||||
constructor(identifier: string, methodName: string, hint: string) {
|
constructor(identifier: string, methodName: string, type: string) {
|
||||||
const defaultMessage = 'CashAssembly primitive method does not exist';
|
const defaultMessage = 'CashAssembly primitive method does not exist';
|
||||||
super(`${defaultMessage}: identifier "${identifier}", methodName "${methodName}", hint "${hint}"`);
|
super(`${defaultMessage}: identifier "${identifier}", methodName "${methodName}", type "${type}"`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,7 +65,7 @@ export class CashAssemblyNumberNotSafeIntegerError extends Error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Error thrown when a supported primitive is selected but its value is missing when provided in the variables map.
|
* Error thrown when a method resolvable primitive is selected but its value is missing from the variables map.
|
||||||
*/
|
*/
|
||||||
export class CashAssemblyPrimitiveVariableMissingError extends Error {
|
export class CashAssemblyPrimitiveVariableMissingError extends Error {
|
||||||
constructor(identifier: string, variableName: string) {
|
constructor(identifier: string, variableName: string) {
|
||||||
|
|||||||
@@ -79,8 +79,8 @@ export type CompileCashAssemblyStringParameters = {
|
|||||||
evaluationDecodeMode?: CompiledCashAssemblyDecodeMode;
|
evaluationDecodeMode?: CompiledCashAssemblyDecodeMode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Optional template variable definitions. When provided, each `<name.method>` push whose `hint`
|
* Optional template variable definitions. When provided, each `<name.method>` push whose `type`
|
||||||
* maps to a supported primitive class is resolved to bytes before CashAssembly compilation.
|
* maps to a method resolvable primitive class is resolved to bytes before CashAssembly compilation.
|
||||||
*/
|
*/
|
||||||
templateVariables?: XOTemplate['variables'];
|
templateVariables?: XOTemplate['variables'];
|
||||||
};
|
};
|
||||||
@@ -295,11 +295,11 @@ export const compileCashAssemblyEvaluations = (evaluations: string[]): CompilerB
|
|||||||
* @param {CompiledCashAssemblyDecodeMode} [parameters.evaluationDecodeMode='utf8'] - The decode mode used
|
* @param {CompiledCashAssemblyDecodeMode} [parameters.evaluationDecodeMode='utf8'] - The decode mode used
|
||||||
* after each evaluation is compiled. See {@link decodeCompiledCashAssemblyEvaluation}.
|
* after each evaluation is compiled. See {@link decodeCompiledCashAssemblyEvaluation}.
|
||||||
* @param {XOTemplate['variables']} [parameters.templateVariables] - Optional template variable definitions
|
* @param {XOTemplate['variables']} [parameters.templateVariables] - Optional template variable definitions
|
||||||
* used to resolve supported `<name.method>` pushes via each variable's `hint`.
|
* used to resolve method resolvable `<name.method>` pushes via each variable's `type`.
|
||||||
* @returns {string} Compiled text with all evaluations replaced by decoded string values.
|
* @returns {string} Compiled text with all evaluations replaced by decoded string values.
|
||||||
* @throws {@link CashAssemblyRequiredVariableMissingError} When a required variable is not present in the variables map.
|
* @throws {@link CashAssemblyRequiredVariableMissingError} When a required variable is not present in the variables map.
|
||||||
* @throws {@link CashAssemblyPrimitiveMethodMissingError} When a supported primitive hint has an unknown method.
|
* @throws {@link CashAssemblyPrimitiveMethodMissingError} When a method resolvable primitive type has an unknown method.
|
||||||
* @throws {@link CashAssemblyPrimitiveVariableMissingError} When a supported primitive method is missing its runtime value.
|
* @throws {@link CashAssemblyPrimitiveVariableMissingError} When a method resolvable primitive method is missing its runtime value.
|
||||||
* @throws {@link CashAssemblyUnsupportedValueTypeError} When a primitive method return type cannot be embedded as bytes.
|
* @throws {@link CashAssemblyUnsupportedValueTypeError} When a primitive method return type cannot be embedded as bytes.
|
||||||
* @throws {@link CashAssemblyNumberNotSafeIntegerError} When a number variable is not a safe integer.
|
* @throws {@link CashAssemblyNumberNotSafeIntegerError} When a number variable is not a safe integer.
|
||||||
* @throws {@link CashAssemblyVmNumberDecodeError} When `evaluationDecodeMode` is `bigint` and an evaluation is not a VM number.
|
* @throws {@link CashAssemblyVmNumberDecodeError} When `evaluationDecodeMode` is `bigint` and an evaluation is not a VM number.
|
||||||
|
|||||||
@@ -16,10 +16,10 @@ import { CASHASSEMBLY_VARIABLE_METHOD_REFERENCE_PATTERN } from './defaults.ts';
|
|||||||
import { convertValueToBytes } from './bytes.ts';
|
import { convertValueToBytes } from './bytes.ts';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Template hint values mapped to a primitive class for resolving primitive method evaluations.
|
* Maps method resolvable template types to `@xo-cash/primitives` classes for `base.method` resolution.
|
||||||
* Keys are values from XOTemplatePrimitiveTypes.
|
* Keys are a subset of {@link XOTemplatePrimitiveTypes}.
|
||||||
*/
|
*/
|
||||||
const PRIMITIVE_BY_TEMPLATE_HINT = {
|
const RESOLVABLE_PRIMITIVE_CLASS_BY_TYPE = {
|
||||||
[XOTemplatePrimitiveTypes.FUNGIBLE_TOKEN_AMOUNT]: FungibleTokenAmount,
|
[XOTemplatePrimitiveTypes.FUNGIBLE_TOKEN_AMOUNT]: FungibleTokenAmount,
|
||||||
[XOTemplatePrimitiveTypes.NFT_COMMITMENT]: NFTCommitment,
|
[XOTemplatePrimitiveTypes.NFT_COMMITMENT]: NFTCommitment,
|
||||||
[XOTemplatePrimitiveTypes.PUBLIC_KEY]: PublicKey,
|
[XOTemplatePrimitiveTypes.PUBLIC_KEY]: PublicKey,
|
||||||
@@ -31,7 +31,11 @@ const PRIMITIVE_BY_TEMPLATE_HINT = {
|
|||||||
[XOTemplatePrimitiveTypes.TRANSACTION_HASH]: TransactionHash,
|
[XOTemplatePrimitiveTypes.TRANSACTION_HASH]: TransactionHash,
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
type SupportedPrimitiveHint = keyof typeof PRIMITIVE_BY_TEMPLATE_HINT;
|
/**
|
||||||
|
* Template primitive types that map to an `@xo-cash/primitives` class for `base.method` resolution.
|
||||||
|
* This is a subset of {@link XOTemplatePrimitiveType}, not every declared template type.
|
||||||
|
*/
|
||||||
|
type ResolvablePrimitiveType = keyof typeof RESOLVABLE_PRIMITIVE_CLASS_BY_TYPE;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inputs needed to call a primitive method for a `name.method` push.
|
* Inputs needed to call a primitive method for a `name.method` push.
|
||||||
@@ -54,9 +58,9 @@ type CallPrimitiveMethodParameters = {
|
|||||||
value: unknown;
|
value: unknown;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Supported template hint that selects the primitive class.
|
* Method resolvable template type that selects the primitive class.
|
||||||
*/
|
*/
|
||||||
hint: SupportedPrimitiveHint;
|
type: ResolvablePrimitiveType;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -77,30 +81,30 @@ export type ResolvePrimitiveMethodBytesParameters = {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Template variable definitions. When omitted, no primitive methods are resolved.
|
* Template variable definitions. When omitted, no primitive methods are resolved.
|
||||||
* The `hint` on each entry selects the primitive class.
|
* The `type` on each entry selects the primitive class.
|
||||||
*/
|
*/
|
||||||
templateVariables?: XOTemplate['variables'];
|
templateVariables?: XOTemplate['variables'];
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true when `hint` maps to a supported primitive class in `PRIMITIVE_BY_TEMPLATE_HINT`.
|
* Returns true when `type` maps to a primitive class in `RESOLVABLE_PRIMITIVE_CLASS_BY_TYPE` for method resolution.
|
||||||
*
|
*
|
||||||
* @param {XOTemplatePrimitiveType | undefined} hint - Template variable hint.
|
* @param {XOTemplatePrimitiveType | undefined} type - Template variable type.
|
||||||
* @returns {boolean} True when the hint selects a supported primitive class.
|
* @returns {boolean} True when the type can resolve `base.method` through a primitive class.
|
||||||
*/
|
*/
|
||||||
const isSupportedPrimitiveHint = (hint: XOTemplatePrimitiveType | undefined): hint is SupportedPrimitiveHint => {
|
const isResolvablePrimitiveType = (type: XOTemplatePrimitiveType | undefined): type is ResolvablePrimitiveType => {
|
||||||
return hint !== undefined && Object.hasOwn(PRIMITIVE_BY_TEMPLATE_HINT, hint) === true;
|
return type !== undefined && Object.hasOwn(RESOLVABLE_PRIMITIVE_CLASS_BY_TYPE, type) === true;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true when `methodName` is an own function on the primitive class for `hint`.
|
* Returns true when `methodName` is an own function on the primitive class for `type`.
|
||||||
*
|
*
|
||||||
* @param {SupportedPrimitiveHint} hint - Supported template hint.
|
* @param {ResolvablePrimitiveType} type - Method resolvable template type.
|
||||||
* @param {string} methodName - Method name from the evaluation text, for example `toSatoshis`.
|
* @param {string} methodName - Method name from the evaluation text, for example `toSatoshis`.
|
||||||
* @returns {boolean} True when that class exposes the named method.
|
* @returns {boolean} True when that class exposes the named method.
|
||||||
*/
|
*/
|
||||||
const canResolvePrimitiveMethod = (hint: SupportedPrimitiveHint, methodName: string): boolean => {
|
const canResolvePrimitiveMethod = (type: ResolvablePrimitiveType, methodName: string): boolean => {
|
||||||
const PrimitiveClass = PRIMITIVE_BY_TEMPLATE_HINT[hint];
|
const PrimitiveClass = RESOLVABLE_PRIMITIVE_CLASS_BY_TYPE[type];
|
||||||
|
|
||||||
// Check own properties only so inherited Object.prototype names are rejected without needing a value.
|
// Check own properties only so inherited Object.prototype names are rejected without needing a value.
|
||||||
if (Object.hasOwn(PrimitiveClass.prototype, methodName) === false) {
|
if (Object.hasOwn(PrimitiveClass.prototype, methodName) === false) {
|
||||||
@@ -113,17 +117,17 @@ const canResolvePrimitiveMethod = (hint: SupportedPrimitiveHint, methodName: str
|
|||||||
/**
|
/**
|
||||||
* Constructs a primitive from a raw value and calls one instance method on it.
|
* Constructs a primitive from a raw value and calls one instance method on it.
|
||||||
*
|
*
|
||||||
* Call only after `canResolvePrimitiveMethod` is true for the same hint and method.
|
* Call only after `canResolvePrimitiveMethod` is true for the same type and method.
|
||||||
*
|
*
|
||||||
* @param {CallPrimitiveMethodParameters} parameters - Identifier, method, value, and supported hint.
|
* @param {CallPrimitiveMethodParameters} parameters - Identifier, method, value, and resolvable type.
|
||||||
* @returns {unknown} Method return value, later encoded as CashAssembly push bytes.
|
* @returns {unknown} Method return value, later encoded as CashAssembly push bytes.
|
||||||
* @throws {@link CashAssemblyPrimitiveMethodMissingError} When the prototype member is not a function.
|
* @throws {@link CashAssemblyPrimitiveMethodMissingError} When the prototype member is not a function.
|
||||||
* @throws When the primitive constructor rejects the raw value (validation errors from `@xo-cash/primitives`).
|
* @throws When the primitive constructor rejects the raw value (validation errors from `@xo-cash/primitives`).
|
||||||
*/
|
*/
|
||||||
const callPrimitiveMethod = (parameters: CallPrimitiveMethodParameters): unknown => {
|
const callPrimitiveMethod = (parameters: CallPrimitiveMethodParameters): unknown => {
|
||||||
const { identifier, methodName, value, hint } = parameters;
|
const { identifier, methodName, value, type } = parameters;
|
||||||
|
|
||||||
const PrimitiveClass = PRIMITIVE_BY_TEMPLATE_HINT[hint];
|
const PrimitiveClass = RESOLVABLE_PRIMITIVE_CLASS_BY_TYPE[type];
|
||||||
|
|
||||||
// Constructing runs each primitive's own input validation (range checks, hex length, etc).
|
// Constructing runs each primitive's own input validation (range checks, hex length, etc).
|
||||||
// `as never` satisfies TypeScript across constructors that accept different input shapes.
|
// `as never` satisfies TypeScript across constructors that accept different input shapes.
|
||||||
@@ -133,23 +137,23 @@ const callPrimitiveMethod = (parameters: CallPrimitiveMethodParameters): unknown
|
|||||||
const primitiveMethod = Reflect.get(PrimitiveClass.prototype, methodName);
|
const primitiveMethod = Reflect.get(PrimitiveClass.prototype, methodName);
|
||||||
|
|
||||||
if (typeof primitiveMethod !== 'function') {
|
if (typeof primitiveMethod !== 'function') {
|
||||||
throw new CashAssemblyPrimitiveMethodMissingError(identifier, methodName, hint);
|
throw new CashAssemblyPrimitiveMethodMissingError(identifier, methodName, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
return primitiveMethod.call(primitiveInstance);
|
return primitiveMethod.call(primitiveInstance);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolves supported `base.method` identifiers to CashAssembly variable bytes.
|
* Resolves method resolvable `base.method` identifiers to CashAssembly variable bytes.
|
||||||
*
|
*
|
||||||
* Each single dot identifier whose `hint` maps to a supported primitive is resolved and stored under
|
* Each single dot identifier whose `type` is in `RESOLVABLE_PRIMITIVE_CLASS_BY_TYPE` is resolved and stored under
|
||||||
* the full identifier (`base.method`). Unsupported or multi dot identifiers are left for CashAssembly.
|
* the full identifier (`base.method`). Other template types or multi dot identifiers are left for CashAssembly.
|
||||||
*
|
*
|
||||||
* When `templateVariables` is omitted, returns an empty map.
|
* When `templateVariables` is omitted, returns an empty map.
|
||||||
*
|
*
|
||||||
* @param {ResolvePrimitiveMethodBytesParameters} parameters - Identifiers, values, and optional template metadata.
|
* @param {ResolvePrimitiveMethodBytesParameters} parameters - Identifiers, values, and optional template metadata.
|
||||||
* @returns {Record<string, Uint8Array>} Resolved method identifiers mapped to bytes for CashAssembly pushes.
|
* @returns {Record<string, Uint8Array>} Resolved method identifiers mapped to bytes for CashAssembly pushes.
|
||||||
* @throws {@link CashAssemblyPrimitiveMethodMissingError} When the hint is a supported primitive but the method is missing.
|
* @throws {@link CashAssemblyPrimitiveMethodMissingError} When the type is method resolvable but the method is missing.
|
||||||
* @throws {@link CashAssemblyPrimitiveVariableMissingError} When the runtime value is missing from the variables map.
|
* @throws {@link CashAssemblyPrimitiveVariableMissingError} When the runtime value is missing from the variables map.
|
||||||
* @throws {@link CashAssemblyUnsupportedValueTypeError} When the method return type cannot be embedded.
|
* @throws {@link CashAssemblyUnsupportedValueTypeError} When the method return type cannot be embedded.
|
||||||
* @throws {@link CashAssemblyNumberNotSafeIntegerError} When a method return value is a number that is not a safe integer.
|
* @throws {@link CashAssemblyNumberNotSafeIntegerError} When a method return value is a number that is not a safe integer.
|
||||||
@@ -157,7 +161,7 @@ const callPrimitiveMethod = (parameters: CallPrimitiveMethodParameters): unknown
|
|||||||
export const resolvePrimitiveMethodBytes = (parameters: ResolvePrimitiveMethodBytesParameters): Record<string, Uint8Array> => {
|
export const resolvePrimitiveMethodBytes = (parameters: ResolvePrimitiveMethodBytesParameters): Record<string, Uint8Array> => {
|
||||||
const { identifiers, templateVariables, variables } = parameters;
|
const { identifiers, templateVariables, variables } = parameters;
|
||||||
|
|
||||||
// Without template metadata there is no hint to select a primitive class.
|
// Without template metadata there is no type to select a primitive class.
|
||||||
if (templateVariables === undefined) {
|
if (templateVariables === undefined) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@@ -185,15 +189,16 @@ export const resolvePrimitiveMethodBytes = (parameters: ResolvePrimitiveMethodBy
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const hint = templateVariables[baseName].hint;
|
const type = templateVariables[baseName].type;
|
||||||
|
|
||||||
if (isSupportedPrimitiveHint(hint) === false) {
|
// Template types without a mapped primitive class are left for CashAssembly.
|
||||||
|
if (isResolvablePrimitiveType(type) === false) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Supported hint with an unknown method should be thrown as an error.
|
// Method resolvable type with an unknown method should throw.
|
||||||
if (canResolvePrimitiveMethod(hint, methodName) === false) {
|
if (canResolvePrimitiveMethod(type, methodName) === false) {
|
||||||
throw new CashAssemblyPrimitiveMethodMissingError(identifier, methodName, hint);
|
throw new CashAssemblyPrimitiveMethodMissingError(identifier, methodName, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the method is known but the runtime value is missing, throw an error.
|
// If the method is known but the runtime value is missing, throw an error.
|
||||||
@@ -205,7 +210,7 @@ export const resolvePrimitiveMethodBytes = (parameters: ResolvePrimitiveMethodBy
|
|||||||
identifier,
|
identifier,
|
||||||
methodName,
|
methodName,
|
||||||
value: variables[baseName],
|
value: variables[baseName],
|
||||||
hint,
|
type,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Store the result under identifier.
|
// Store the result under identifier.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/* eslint-disable @stylistic/newline-per-chained-call */
|
/* eslint-disable @stylistic/newline-per-chained-call */
|
||||||
import { BchVmVersions, XOTemplateBaseTypes, XOTemplatePrimitiveTypes, XOTemplateLockingTypes, XOTemplateNftCapabilities } from '@xo-cash/types';
|
import { BchVmVersions, XOTemplatePrimitiveTypes, XOTemplateLockingTypes, XOTemplateNftCapabilities } from '@xo-cash/types';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
|
|
||||||
// ============================================================
|
// ============================================================
|
||||||
@@ -58,12 +58,6 @@ export const xoTemplateNftCapabilitySchema = z.enum(XOTemplateNftCapabilities);
|
|||||||
*/
|
*/
|
||||||
export const xoTemplateLockingTypeSchema = z.enum(XOTemplateLockingTypes);
|
export const xoTemplateLockingTypeSchema = z.enum(XOTemplateLockingTypes);
|
||||||
|
|
||||||
/**
|
|
||||||
* Validation schema for a base type identifier.
|
|
||||||
* Accepts values from XOTemplateBaseTypes for the `type` field on constants, variables, and data.
|
|
||||||
*/
|
|
||||||
export const xoTemplateBaseTypeSchema = z.enum(XOTemplateBaseTypes);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validation schema for a primitive type identifier.
|
* Validation schema for a primitive type identifier.
|
||||||
* Accepts values from XOTemplatePrimitiveTypes for the `hint` field on constants, variables, and data.
|
* Accepts values from XOTemplatePrimitiveTypes for the `hint` field on constants, variables, and data.
|
||||||
@@ -743,9 +737,9 @@ export const xoTemplateTransactionSchema = xoTemplateViewPropertiesSchema
|
|||||||
*/
|
*/
|
||||||
export const xoTemplateConstantSchema = xoTemplateViewPropertiesSchema
|
export const xoTemplateConstantSchema = xoTemplateViewPropertiesSchema
|
||||||
.extend({
|
.extend({
|
||||||
type: xoTemplateBaseTypeSchema.describe('The data type of this constant.'),
|
type: xoTemplatePrimitiveTypeSchema.describe('The data type of this constant.'),
|
||||||
value: z.unknown().describe('The value of this constant.'),
|
value: z.unknown().describe('The value of this constant.'),
|
||||||
hint: xoTemplatePrimitiveTypeSchema.optional().describe('An optional hint to help apps and users understand what this constant represents.'),
|
hint: z.unknown().optional().describe('An optional hint to help apps and users understand what this constant represents.'),
|
||||||
})
|
})
|
||||||
.strict();
|
.strict();
|
||||||
|
|
||||||
@@ -762,9 +756,9 @@ export const xoTemplateConstantSchema = xoTemplateViewPropertiesSchema
|
|||||||
*/
|
*/
|
||||||
export const xoTemplateDataSchema = z
|
export const xoTemplateDataSchema = z
|
||||||
.object({
|
.object({
|
||||||
type: xoTemplateBaseTypeSchema.describe('The data type of this data field.'),
|
type: xoTemplatePrimitiveTypeSchema.describe('The data type of this data field.'),
|
||||||
value: z.unknown().describe('The value for this data field.'),
|
value: z.unknown().describe('The value for this data field.'),
|
||||||
hint: xoTemplatePrimitiveTypeSchema.optional().describe('An optional hint to help apps and users understand this data field.'),
|
hint: z.unknown().optional().describe('An optional hint to help apps and users understand this data field.'),
|
||||||
})
|
})
|
||||||
.strict();
|
.strict();
|
||||||
|
|
||||||
@@ -800,8 +794,8 @@ export const xoTemplateImportDefaultValueSchema = xoTemplateIntentSchema
|
|||||||
*/
|
*/
|
||||||
export const xoTemplateVariableSchema = xoTemplateViewPropertiesSchema
|
export const xoTemplateVariableSchema = xoTemplateViewPropertiesSchema
|
||||||
.extend({
|
.extend({
|
||||||
type: xoTemplateBaseTypeSchema.optional().describe('The data type of this variable.'),
|
type: xoTemplatePrimitiveTypeSchema.optional().describe('The data type of this variable.'),
|
||||||
hint: xoTemplatePrimitiveTypeSchema.optional().describe('A hint to help users understand what value to provide.'),
|
hint: z.unknown().optional().describe('A hint to help users understand what value to provide.'),
|
||||||
|
|
||||||
// A neutral intent that the engine uses to populate the default value for this variable.
|
// A neutral intent that the engine uses to populate the default value for this variable.
|
||||||
// View properties (name, description, icon) may contain CashASM expressions that the
|
// View properties (name, description, icon) may contain CashASM expressions that the
|
||||||
|
|||||||
+18
-24
@@ -10,7 +10,7 @@ import {
|
|||||||
secp256k1,
|
secp256k1,
|
||||||
utf8ToBin,
|
utf8ToBin,
|
||||||
} from '@bitauth/libauth';
|
} from '@bitauth/libauth';
|
||||||
import { XOTemplateBaseTypes, XOTemplatePrimitiveTypes } from '@xo-cash/types';
|
import { XOTemplatePrimitiveTypes } from '@xo-cash/types';
|
||||||
import {
|
import {
|
||||||
isCashAssemblyExpression,
|
isCashAssemblyExpression,
|
||||||
extractCashAssemblyEvaluations,
|
extractCashAssemblyEvaluations,
|
||||||
@@ -383,10 +383,10 @@ const testCompileCashAssemblyStringLeavesMethodEvaluationForCashAssemblyWithoutT
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests that an unsupported or missing hint leaves the evaluation for CashAssembly instead of throwing.
|
* Tests that a type without a mapped primitive class leaves the evaluation for CashAssembly instead of throwing.
|
||||||
*/
|
*/
|
||||||
const testCompileCashAssemblyStringSkipsWhenHintIsNotASupportedPrimitive = (): void => {
|
const testCompileCashAssemblyStringSkipsWhenTypeIsNotAResolvablePrimitive = (): void => {
|
||||||
const compileWithNonPrimitiveHint = (): string =>
|
const compileWithNonPrimitiveType = (): string =>
|
||||||
compileCashAssemblyString({
|
compileCashAssemblyString({
|
||||||
cashAssemblyText: '$(<label.toIso8601>)',
|
cashAssemblyText: '$(<label.toIso8601>)',
|
||||||
variables: { label: 'hello' },
|
variables: { label: 'hello' },
|
||||||
@@ -394,19 +394,19 @@ const testCompileCashAssemblyStringSkipsWhenHintIsNotASupportedPrimitive = (): v
|
|||||||
label: {
|
label: {
|
||||||
name: 'Label',
|
name: 'Label',
|
||||||
description: 'A text label',
|
description: 'A text label',
|
||||||
type: XOTemplateBaseTypes.STRING,
|
type: XOTemplatePrimitiveTypes.STRING,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(compileWithNonPrimitiveHint).toThrow(CashAssemblyRequiredVariableMissingError);
|
expect(compileWithNonPrimitiveType).toThrow(CashAssemblyRequiredVariableMissingError);
|
||||||
expect(compileWithNonPrimitiveHint).toThrow('Missing required variable: variableNames [label.toIso8601]');
|
expect(compileWithNonPrimitiveType).toThrow('Missing required variable: variableNames [label.toIso8601]');
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests that a supported hint with an unknown method throws CashAssemblyPrimitiveMethodMissingError.
|
* Tests that a method resolvable type with an unknown method throws CashAssemblyPrimitiveMethodMissingError.
|
||||||
*
|
*
|
||||||
* Once the hint maps to a supported primitive class, a missing method is a primitive resolution
|
* Once the type maps to a primitive class for method resolution, a missing method is a primitive resolution
|
||||||
* failure rather than a CashAssembly missing variable.
|
* failure rather than a CashAssembly missing variable.
|
||||||
*/
|
*/
|
||||||
const testCompileCashAssemblyStringThrowsWhenMethodDoesNotExistOnPrimitive = (): void => {
|
const testCompileCashAssemblyStringThrowsWhenMethodDoesNotExistOnPrimitive = (): void => {
|
||||||
@@ -418,14 +418,13 @@ const testCompileCashAssemblyStringThrowsWhenMethodDoesNotExistOnPrimitive = ():
|
|||||||
expiry: {
|
expiry: {
|
||||||
name: 'Expiry',
|
name: 'Expiry',
|
||||||
description: 'Invitation expiry time',
|
description: 'Invitation expiry time',
|
||||||
type: XOTemplateBaseTypes.INTEGER,
|
type: XOTemplatePrimitiveTypes.TIMESTAMP,
|
||||||
hint: XOTemplatePrimitiveTypes.TIMESTAMP,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(compileWithUnknownMethod).toThrow(CashAssemblyPrimitiveMethodMissingError);
|
expect(compileWithUnknownMethod).toThrow(CashAssemblyPrimitiveMethodMissingError);
|
||||||
expect(compileWithUnknownMethod).toThrow('CashAssembly primitive method does not exist: identifier "expiry.notARealMethod", methodName "notARealMethod", hint "timestamp"');
|
expect(compileWithUnknownMethod).toThrow('CashAssembly primitive method does not exist: identifier "expiry.notARealMethod", methodName "notARealMethod", type "timestamp"');
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -440,8 +439,7 @@ const testCompileCashAssemblyStringThrowsWhenSupportedTransformIsMissingRuntimeV
|
|||||||
expiry: {
|
expiry: {
|
||||||
name: 'Expiry',
|
name: 'Expiry',
|
||||||
description: 'Invitation expiry time',
|
description: 'Invitation expiry time',
|
||||||
type: XOTemplateBaseTypes.INTEGER,
|
type: XOTemplatePrimitiveTypes.TIMESTAMP,
|
||||||
hint: XOTemplatePrimitiveTypes.TIMESTAMP,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -464,14 +462,12 @@ const testCompileCashAssemblyStringResolvesMultiplePrimitiveMethodPushesInOneEva
|
|||||||
amount: {
|
amount: {
|
||||||
name: 'Amount',
|
name: 'Amount',
|
||||||
description: 'Payment in satoshis',
|
description: 'Payment in satoshis',
|
||||||
type: XOTemplateBaseTypes.BIGINT,
|
type: XOTemplatePrimitiveTypes.SATOSHIS,
|
||||||
hint: XOTemplatePrimitiveTypes.SATOSHIS,
|
|
||||||
},
|
},
|
||||||
fee: {
|
fee: {
|
||||||
name: 'Fee',
|
name: 'Fee',
|
||||||
description: 'Network fee in satoshis',
|
description: 'Network fee in satoshis',
|
||||||
type: XOTemplateBaseTypes.BIGINT,
|
type: XOTemplatePrimitiveTypes.SATOSHIS,
|
||||||
hint: XOTemplatePrimitiveTypes.SATOSHIS,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
evaluationDecodeMode: 'bigint',
|
evaluationDecodeMode: 'bigint',
|
||||||
@@ -542,14 +538,12 @@ const testP2sh32RedeemWithPrimitiveAddAndSchnorrSignatureSpendsSuccessfully = ()
|
|||||||
price: {
|
price: {
|
||||||
name: 'Price',
|
name: 'Price',
|
||||||
description: 'Base payment in satoshis',
|
description: 'Base payment in satoshis',
|
||||||
type: XOTemplateBaseTypes.BIGINT,
|
type: XOTemplatePrimitiveTypes.SATOSHIS,
|
||||||
hint: XOTemplatePrimitiveTypes.SATOSHIS,
|
|
||||||
},
|
},
|
||||||
fee: {
|
fee: {
|
||||||
name: 'Fee',
|
name: 'Fee',
|
||||||
description: 'Network fee in satoshis',
|
description: 'Network fee in satoshis',
|
||||||
type: XOTemplateBaseTypes.BIGINT,
|
type: XOTemplatePrimitiveTypes.SATOSHIS,
|
||||||
hint: XOTemplatePrimitiveTypes.SATOSHIS,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -781,8 +775,8 @@ const runTests = async (): Promise<void> => {
|
|||||||
testCompileCashAssemblyStringLeavesMethodEvaluationForCashAssemblyWithoutTemplateVariables,
|
testCompileCashAssemblyStringLeavesMethodEvaluationForCashAssemblyWithoutTemplateVariables,
|
||||||
);
|
);
|
||||||
test(
|
test(
|
||||||
'compileCashAssemblyString: skips when hint is not a supported primitive',
|
'compileCashAssemblyString: skips when type is not a resolvable primitive',
|
||||||
testCompileCashAssemblyStringSkipsWhenHintIsNotASupportedPrimitive,
|
testCompileCashAssemblyStringSkipsWhenTypeIsNotAResolvablePrimitive,
|
||||||
);
|
);
|
||||||
test(
|
test(
|
||||||
'compileCashAssemblyString: throws when method does not exist on the primitive',
|
'compileCashAssemblyString: throws when method does not exist on the primitive',
|
||||||
|
|||||||
Reference in New Issue
Block a user