diff --git a/.github/workflows/node-ci.yml b/.github/workflows/node-ci.yml index 9ed07ff47..f2579e2c2 100644 --- a/.github/workflows/node-ci.yml +++ b/.github/workflows/node-ci.yml @@ -163,7 +163,7 @@ jobs: #Requires permissions.checks: write - name: Publish test results if: ${{ inputs.output-test-results && always() }} - uses: phoenix-actions/test-reporting@v10 + uses: phoenix-actions/test-reporting@v15 with: name: Test results path: ${{ inputs.test-results-file-pattern }} diff --git a/package-lock.json b/package-lock.json index b25292c3b..2b10da0b3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13544,7 +13544,7 @@ }, "packages/algo-ts/dist": { "name": "@algorandfoundation/algorand-typescript", - "version": "1.0.0-beta.8", + "version": "1.0.0-beta.9", "dev": true, "peerDependencies": { "tslib": "^2.6.2" diff --git a/packages/algo-ts/package.json b/packages/algo-ts/package.json index 22e8e6dfb..fc178117c 100644 --- a/packages/algo-ts/package.json +++ b/packages/algo-ts/package.json @@ -1,6 +1,6 @@ { "name": "@algorandfoundation/algorand-typescript", - "version": "1.0.0-beta.8", + "version": "1.0.0-beta.9", "description": "This package contains definitions for the types which comprise Algorand TypeScript which can be compiled to run on the Algorand Virtual Machine using the Puya compiler.", "private": false, "main": "index.js", diff --git a/packages/algo-ts/src/arc4/encoded-types.ts b/packages/algo-ts/src/arc4/encoded-types.ts index 2701fe561..4f1a03a28 100644 --- a/packages/algo-ts/src/arc4/encoded-types.ts +++ b/packages/algo-ts/src/arc4/encoded-types.ts @@ -285,7 +285,7 @@ class StructImpl extends StructBase { } } -type StructConstructor = new (initial: T) => StructBase & T +type StructConstructor = new (initial: T) => StructBase & Readonly export const Struct = StructImpl as StructConstructor diff --git a/src/awst_build/arc4-util.ts b/src/awst_build/arc4-util.ts index 622bc59ff..c0267deda 100644 --- a/src/awst_build/arc4-util.ts +++ b/src/awst_build/arc4-util.ts @@ -74,6 +74,7 @@ export function ptypeToArc4EncodedType(ptype: PType, sourceLocation: SourceLocat module: ptype.module, description: ptype.description, fields: Object.fromEntries(ptype.orderedProperties().map(([p, pt]) => [p, ptypeToArc4EncodedType(pt, sourceLocation)])), + frozen: true, }) throw new CodeError(`${ptype} cannot be encoded to an ARC4 type`, { sourceLocation }) diff --git a/src/awst_build/eb/arc28/arc-28-emit-function-builder.ts b/src/awst_build/eb/arc28/arc-28-emit-function-builder.ts index f9b13d2ee..318ed91e1 100644 --- a/src/awst_build/eb/arc28/arc-28-emit-function-builder.ts +++ b/src/awst_build/eb/arc28/arc-28-emit-function-builder.ts @@ -75,6 +75,7 @@ export class Arc28EmitFunctionBuilder extends FunctionBuilder { fields, description: undefined, sourceLocation, + frozen: true, }) const structExpression = nodeFactory.newStruct({ wtype: structType.wtype, diff --git a/src/awst_build/ptypes/arc4-types.ts b/src/awst_build/ptypes/arc4-types.ts index e56a97f87..45bde8914 100644 --- a/src/awst_build/ptypes/arc4-types.ts +++ b/src/awst_build/ptypes/arc4-types.ts @@ -131,8 +131,10 @@ export class ARC4StructType extends ARC4EncodedType { readonly singleton = false readonly fields: Record readonly sourceLocation: SourceLocation | undefined + readonly frozen: boolean constructor({ name, + frozen, module, fields, description, @@ -140,6 +142,7 @@ export class ARC4StructType extends ARC4EncodedType { }: { name: string module: string + frozen: boolean description: string | undefined fields: Record sourceLocation?: SourceLocation @@ -147,6 +150,7 @@ export class ARC4StructType extends ARC4EncodedType { super() this.name = name this.module = module + this.frozen = frozen this.fields = fields this.description = description this.sourceLocation = sourceLocation @@ -162,7 +166,7 @@ export class ARC4StructType extends ARC4EncodedType { fields: Object.fromEntries(Object.entries(this.fields).map(([f, t]) => [f, t.wtype])), sourceLocation: this.sourceLocation, desc: this.description ?? null, - frozen: false, + frozen: this.frozen, }) } @@ -189,6 +193,7 @@ export const arc4StructBaseType = new ARC4StructType({ module: Constants.arc4EncodedTypesModuleName, fields: {}, description: undefined, + frozen: true, }) export const Arc4TupleClass = new LibClassType({ diff --git a/src/awst_build/type-resolver.ts b/src/awst_build/type-resolver.ts index ad7b0008b..30dff967c 100644 --- a/src/awst_build/type-resolver.ts +++ b/src/awst_build/type-resolver.ts @@ -362,6 +362,7 @@ export class TypeResolver { fields: fields, sourceLocation: sourceLocation, description: tryGetTypeDescription(tsType), + frozen: baseType.frozen, }) } diff --git a/src/constants.ts b/src/constants.ts index abfc26de0..7fb4f94d1 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -34,8 +34,7 @@ export const Constants = { zeroAddressEncoded: 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAY5HFKQ', supportedAvmVersions: [10n, 11n], - mainNetAvmVersion: [10n], - targetedPuyaVersion: '4.1.1', + targetedPuyaVersion: '4.2.0', } as const export type SupportedAvmVersion = (typeof Constants.supportedAvmVersions)[number] diff --git a/src/puya/check-puya-version.ts b/src/puya/check-puya-version.ts index 142e7eac5..c8fbceb1d 100644 --- a/src/puya/check-puya-version.ts +++ b/src/puya/check-puya-version.ts @@ -2,7 +2,21 @@ import { Constants } from '../constants' import { logger } from '../logger' import { runPuya } from './run-puya' -export function checkPuyaVersion() { +export enum VersionCompareVerdict { + ExactMatch = 'ExactMatch', + Inconclusive = 'Inconclusive', + MajorMismatch = 'MajorMismatch', + MinorMismatch = 'MinorMismatch', + RevisionMismatch = 'RevisionMismatch', +} + +export function comparePuyaVersion(): { + target: string + found?: string + verdict: VersionCompareVerdict +} { + const target = Constants.targetedPuyaVersion + const versionParser = new VersionParser() runPuya({ command: 'puya', @@ -10,23 +24,36 @@ export function checkPuyaVersion() { onOutput: (line) => versionParser.receiveLine(line), }) - if (versionParser.version) { - const ver = versionParser.version - // Compare - const [major, minor, rev] = Constants.targetedPuyaVersion.split('.').map((x) => Number(x)) - if (major !== ver.major || minor !== ver.minor) { + if (!versionParser.version) return { target, verdict: VersionCompareVerdict.Inconclusive } + const ver = versionParser.version + + // Compare + const [major, minor, rev] = target.split('.').map((x) => Number(x)) + if (ver.major !== major) return { verdict: VersionCompareVerdict.MajorMismatch, target, found: ver.formatted } + if (ver.minor !== minor) return { verdict: VersionCompareVerdict.MinorMismatch, target, found: ver.formatted } + if (ver.rev !== rev) return { verdict: VersionCompareVerdict.RevisionMismatch, target, found: ver.formatted } + return { verdict: VersionCompareVerdict.ExactMatch, target, found: ver.formatted } +} + +export function checkPuyaVersion() { + const result = comparePuyaVersion() + switch (result.verdict) { + case VersionCompareVerdict.Inconclusive: + logger.warn(undefined, `Unable to verify installed puya version. Please ensure version ${result.target} is available`) + break + case VersionCompareVerdict.MajorMismatch: + case VersionCompareVerdict.MinorMismatch: logger.warn( undefined, - `Installed version of puya (${ver.major}.${ver.minor}.${ver.rev}) does not match targeted version for puya-ts (${Constants.targetedPuyaVersion}). There may be compatability issues.`, + `Installed version of puya (${result.found}) does not match targeted version for puya-ts (${result.target}). There may be compatability issues.`, ) - } else if (rev !== ver.rev) { + break + case VersionCompareVerdict.RevisionMismatch: logger.debug( undefined, - `Installed revision of puya (${ver.major}.${ver.minor}.${ver.rev}) does not match targeted revision for puya-ts (${Constants.targetedPuyaVersion})`, + `Installed revision of puya (${result.found}) does not match targeted revision for puya-ts (${Constants.targetedPuyaVersion})`, ) - } - } else { - logger.warn(undefined, `Unable to verify installed puya version. Please ensure version ${Constants.targetedPuyaVersion} is available`) + break } } @@ -34,20 +61,22 @@ type SemVer = { major: number minor: number rev: number + formatted: string } class VersionParser { #ver: SemVer | undefined receiveLine(line: string): void { - const matched = /^puya (\d+)\.(\d+)\.(\d+)$/.exec(line) + const matched = /^puya ((\d+)\.(\d+)\.(\d+))$/.exec(line) if (!matched) { logger.debug(undefined, `'puya --version' command returned unexpected output: "${line}"`) } else { this.#ver = { - major: Number(matched[1]), - minor: Number(matched[2]), - rev: Number(matched[3]), + formatted: matched[1], + major: Number(matched[2]), + minor: Number(matched[3]), + rev: Number(matched[4]), } } } diff --git a/tests/approvals/out/arc-28-events/arc-28-events.awst.json b/tests/approvals/out/arc-28-events/arc-28-events.awst.json index 55096f772..b975591af 100644 --- a/tests/approvals/out/arc-28-events/arc-28-events.awst.json +++ b/tests/approvals/out/arc-28-events/arc-28-events.awst.json @@ -321,7 +321,7 @@ } }, "source_location": null, - "frozen": false, + "frozen": true, "desc": null }, "value": { @@ -1027,7 +1027,7 @@ } }, "source_location": null, - "frozen": false, + "frozen": true, "desc": null }, "value": { @@ -1156,7 +1156,7 @@ "column": 10, "end_column": 11 }, - "frozen": false, + "frozen": true, "desc": null }, "name": "y" @@ -1219,7 +1219,7 @@ "column": 18, "end_column": 29 }, - "frozen": false, + "frozen": true, "desc": null }, "values": { @@ -1698,7 +1698,7 @@ "column": 9, "end_column": 10 }, - "frozen": false, + "frozen": true, "desc": null }, "name": "y" @@ -1789,7 +1789,7 @@ "column": 4, "end_column": 25 }, - "frozen": false, + "frozen": true, "desc": null }, "values": { @@ -1935,7 +1935,7 @@ "column": 4, "end_column": 38 }, - "frozen": false, + "frozen": true, "desc": null }, "values": { @@ -2109,7 +2109,7 @@ "column": 4, "end_column": 60 }, - "frozen": false, + "frozen": true, "desc": null }, "values": { @@ -2500,7 +2500,7 @@ "column": 4, "end_column": 30 }, - "frozen": false, + "frozen": true, "desc": null }, "values": { @@ -2710,7 +2710,7 @@ "column": 4, "end_column": 43 }, - "frozen": false, + "frozen": true, "desc": null }, "values": { @@ -3058,7 +3058,7 @@ "column": 4, "end_column": 35 }, - "frozen": false, + "frozen": true, "desc": null }, "values": { diff --git a/tests/approvals/out/arc4-encode-decode/arc4-encode-decode.awst.json b/tests/approvals/out/arc4-encode-decode/arc4-encode-decode.awst.json index 6253c1887..79a736f9d 100644 --- a/tests/approvals/out/arc4-encode-decode/arc4-encode-decode.awst.json +++ b/tests/approvals/out/arc4-encode-decode/arc4-encode-decode.awst.json @@ -1306,7 +1306,7 @@ } }, "source_location": null, - "frozen": false, + "frozen": true, "desc": null }, "value": { @@ -1477,7 +1477,7 @@ "column": 43, "end_column": 53 }, - "frozen": false, + "frozen": true, "desc": null }, "values": { @@ -3101,7 +3101,7 @@ } }, "source_location": null, - "frozen": false, + "frozen": true, "desc": null }, "expr": { @@ -3457,7 +3457,7 @@ } }, "source_location": null, - "frozen": false, + "frozen": true, "desc": null }, "expr": { diff --git a/tests/approvals/out/arc4-struct/arc4-struct.awst.json b/tests/approvals/out/arc4-struct/arc4-struct.awst.json index 7745d3068..563564cd0 100644 --- a/tests/approvals/out/arc4-struct/arc4-struct.awst.json +++ b/tests/approvals/out/arc4-struct/arc4-struct.awst.json @@ -255,7 +255,7 @@ "column": 10, "end_column": 12 }, - "frozen": false, + "frozen": true, "desc": null }, "name": "v1" @@ -318,7 +318,7 @@ "column": 19, "end_column": 25 }, - "frozen": false, + "frozen": true, "desc": null }, "values": { @@ -844,7 +844,7 @@ "column": 8, "end_column": 10 }, - "frozen": false, + "frozen": true, "desc": null }, "name": "v1" @@ -982,7 +982,7 @@ "column": 8, "end_column": 10 }, - "frozen": false, + "frozen": true, "desc": null }, "name": "v1" @@ -1060,7 +1060,7 @@ "column": 10, "end_column": 12 }, - "frozen": false, + "frozen": true, "desc": null }, "name": "v2" @@ -1123,7 +1123,7 @@ "column": 19, "end_column": 25 }, - "frozen": false, + "frozen": true, "desc": null }, "values": { @@ -2309,7 +2309,7 @@ "column": 11, "end_column": 13 }, - "frozen": false, + "frozen": true, "desc": null }, "name": "v1" @@ -2390,7 +2390,7 @@ "column": 18, "end_column": 20 }, - "frozen": false, + "frozen": true, "desc": null }, "name": "v2" @@ -2494,7 +2494,7 @@ "column": 24, "end_column": 30 }, - "frozen": false, + "frozen": true, "desc": null }, "source_location": { @@ -2557,7 +2557,7 @@ "column": 36, "end_column": 42 }, - "frozen": false, + "frozen": true, "desc": null }, "source_location": { @@ -2618,7 +2618,7 @@ "column": 2, "end_column": 43 }, - "frozen": false, + "frozen": true, "desc": null }, "body": { @@ -2698,7 +2698,7 @@ "column": 15, "end_column": 21 }, - "frozen": false, + "frozen": true, "desc": null }, "values": { @@ -2976,7 +2976,7 @@ "column": 24, "end_column": 26 }, - "frozen": false, + "frozen": true, "desc": null }, "name": "v1" @@ -3084,7 +3084,7 @@ "column": 38, "end_column": 40 }, - "frozen": false, + "frozen": true, "desc": null }, "name": "v2" @@ -3234,7 +3234,7 @@ "column": 24, "end_column": 26 }, - "frozen": false, + "frozen": true, "desc": null }, "name": "v1" @@ -3342,7 +3342,7 @@ "column": 38, "end_column": 40 }, - "frozen": false, + "frozen": true, "desc": null }, "name": "v2" @@ -3632,7 +3632,7 @@ "column": 24, "end_column": 26 }, - "frozen": false, + "frozen": true, "desc": null }, "name": "v1" @@ -3740,7 +3740,7 @@ "column": 38, "end_column": 40 }, - "frozen": false, + "frozen": true, "desc": null }, "name": "v2" @@ -3890,7 +3890,7 @@ "column": 24, "end_column": 26 }, - "frozen": false, + "frozen": true, "desc": null }, "name": "v1" @@ -3998,7 +3998,7 @@ "column": 38, "end_column": 40 }, - "frozen": false, + "frozen": true, "desc": null }, "name": "v2" @@ -4151,7 +4151,7 @@ "column": 41, "end_column": 47 }, - "frozen": false, + "frozen": true, "desc": null }, "source_location": { @@ -4247,7 +4247,7 @@ "column": 10, "end_column": 12 }, - "frozen": false, + "frozen": true, "desc": null }, "name": "v2" @@ -4310,7 +4310,7 @@ "column": 19, "end_column": 25 }, - "frozen": false, + "frozen": true, "desc": null }, "values": { @@ -4505,7 +4505,7 @@ "column": 26, "end_column": 28 }, - "frozen": false, + "frozen": true, "desc": null }, "name": "v1" @@ -4706,7 +4706,7 @@ "column": 26, "end_column": 28 }, - "frozen": false, + "frozen": true, "desc": null }, "name": "v1" @@ -4786,7 +4786,7 @@ "column": 10, "end_column": 12 }, - "frozen": false, + "frozen": true, "desc": null }, "name": "v3" @@ -4849,7 +4849,7 @@ "column": 19, "end_column": 25 }, - "frozen": false, + "frozen": true, "desc": null }, "values": { @@ -5070,7 +5070,7 @@ "column": 31, "end_column": 33 }, - "frozen": false, + "frozen": true, "desc": null }, "name": "v2" @@ -5160,7 +5160,7 @@ "column": 31, "end_column": 33 }, - "frozen": false, + "frozen": true, "desc": null }, "name": "v2" @@ -5390,7 +5390,7 @@ "column": 31, "end_column": 33 }, - "frozen": false, + "frozen": true, "desc": null }, "name": "v2" @@ -5480,7 +5480,7 @@ "column": 31, "end_column": 33 }, - "frozen": false, + "frozen": true, "desc": null }, "name": "v2" @@ -5611,7 +5611,7 @@ "column": 11, "end_column": 13 }, - "frozen": false, + "frozen": true, "desc": null }, "name": "v1" @@ -5692,7 +5692,7 @@ "column": 24, "end_column": 26 }, - "frozen": false, + "frozen": true, "desc": null }, "name": "v2" @@ -5817,7 +5817,7 @@ "column": 11, "end_column": 13 }, - "frozen": false, + "frozen": true, "desc": null }, "name": "v3" @@ -5898,7 +5898,7 @@ "column": 24, "end_column": 26 }, - "frozen": false, + "frozen": true, "desc": null }, "name": "v1" @@ -6016,7 +6016,7 @@ "column": 28, "end_column": 34 }, - "frozen": false, + "frozen": true, "desc": null }, "source_location": { @@ -6077,7 +6077,7 @@ "column": 2, "end_column": 43 }, - "frozen": false, + "frozen": true, "desc": null }, "body": { @@ -6191,7 +6191,7 @@ "column": 21, "end_column": 23 }, - "frozen": false, + "frozen": true, "desc": null }, "name": "v1" @@ -6265,7 +6265,7 @@ "column": 11, "end_column": 44 }, - "frozen": false, + "frozen": true, "desc": null }, "expr": { diff --git a/tests/approvals/out/jsdoc/jsdoc.awst.json b/tests/approvals/out/jsdoc/jsdoc.awst.json index fed7ed0f7..9af9da5f7 100644 --- a/tests/approvals/out/jsdoc/jsdoc.awst.json +++ b/tests/approvals/out/jsdoc/jsdoc.awst.json @@ -241,7 +241,7 @@ "column": 2, "end_column": 39 }, - "frozen": false, + "frozen": true, "desc": "This is the description for demo struct" }, "body": { @@ -305,7 +305,7 @@ "column": 15, "end_column": 25 }, - "frozen": false, + "frozen": true, "desc": "This is the description for demo struct" }, "values": { diff --git a/tests/check-version.spec.ts b/tests/check-version.spec.ts new file mode 100644 index 000000000..4aa0697f9 --- /dev/null +++ b/tests/check-version.spec.ts @@ -0,0 +1,11 @@ +import { describe, expect, test } from 'vitest' +import { comparePuyaVersion, VersionCompareVerdict } from '../src/puya/check-puya-version' + +describe('The puya version available for testing', () => { + test('must match the target version', () => { + const result = comparePuyaVersion() + + expect(result.found).toBe(result.target) + expect(result.verdict, 'Compare version must be exact match').toBe(VersionCompareVerdict.ExactMatch) + }) +})