Skip to content

Commit

Permalink
Merge branch 'main' into destructuring-docs
Browse files Browse the repository at this point in the history
  • Loading branch information
novusnota committed Oct 28, 2024
2 parents b45048c + 757e62b commit 9748b5a
Show file tree
Hide file tree
Showing 30 changed files with 1,841 additions and 428 deletions.
6 changes: 4 additions & 2 deletions .github/workflows/tact-docs-prod.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ on:
# The check for the 'main' branch is done on the job level
push:
tags: ["v[0-9]+.[0-9]+.[0-9]+"]
branches: ["main"]

# Allows to run this workflow manually from the Actions tab
workflow_dispatch:
Expand All @@ -29,8 +30,9 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
# with:
# fetch-depth: 0
with:
fetch-depth: 0

- name: Install, build and store site artifact
uses: withastro/action@v3
with:
Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/tact-docs-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ jobs:
cache: "yarn"
cache-dependency-path: "docs/yarn.lock"

- name: Perform syntax and type checking of the Cookbook
working-directory: docs
run: node scripts/check-cookbook-examples.js

- name: Install dependencies
working-directory: docs
run: yarn deps
Expand Down
12 changes: 11 additions & 1 deletion .github/workflows/tact.yml
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,17 @@ jobs:
- name: (pnpm) Test creation of new Blueprint projects
if: ${{ matrix.package-manager == 'pnpm' }}
run: |
npm i -g pnpm
# Installing the specific pnpm version to work around https://github.com/pnpm/pnpm/issues/5000
# and not fail suddenly when a release comes that fixes this
# NOTE: revisit and simplify this step if/when those bugs with pnpm are resolved
npm i -g [email protected]
# To help pnpm recognize the shell (they cannot do it themselves sometimes...)
${{ matrix.os != 'windows-latest' && 'export SHELL=bash' || 'echo windows_noop' }}
pnpm setup -f
# To source .bashrc on Linux:
${{ matrix.os == 'ubuntu-latest' && 'source ~/.bashrc' || 'echo noop' }}
# To expose stuff for pnpm directly on macOS (because otherwise the pre-installed Node.js version gets used):
${{ matrix.os == 'macos-latest' && 'export PNPM_HOME=~/Library/pnpm; export PATH=$PNPM_HOME:$PATH' || 'echo noop' }}
pnpm link -g
cd ..
pnpm create ton@latest test-project --type tact-counter --contractName Counter
Expand Down
8 changes: 6 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- New CSpell dictionaries: TVM instructions and adjusted list of Fift words: PR [#881](https://github.com/tact-lang/tact/pull/881)
- Docs: the `description` property to the frontmatter of the each page for better SEO: PR [#916](https://github.com/tact-lang/tact/pull/916)
- Docs: Google Analytics tags per every page: PR [#921](https://github.com/tact-lang/tact/pull/921)
- Docs: Added NFTs cookbook: PR [#958](https://github.com/tact-lang/tact/pull/958)
- Ability to specify a compile-time method ID expression for getters: PR [#922](https://github.com/tact-lang/tact/pull/922) and PR [#932](https://github.com/tact-lang/tact/pull/932)
- Destructuring of structs and messages: PR [#856](https://github.com/tact-lang/tact/pull/856), PR [#964](https://github.com/tact-lang/tact/pull/964)

### Changed

- The `parseImports` function now returns AST import nodes instead of raw strings: PR [#966](https://github.com/tact-lang/tact/pull/966)
- Optional types for `self` argument in `extends mutates` functions are now allowed: PR [#854](https://github.com/tact-lang/tact/pull/854)
- Docs: complete overhaul of the exit codes page: PR [#978](https://github.com/tact-lang/tact/pull/978)
- Docs: enhanced Jettons Cookbook page: PR [#944](https://github.com/tact-lang/tact/pull/944)

### Fixed

Expand All @@ -28,6 +31,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Non-null struct fields after null ones are treated correctly in Sandbox tests after updating `@ton/core` to 0.59.0: PR [#933](https://github.com/tact-lang/tact/pull/933)
- Prevent inline code snippets from changing their background color: PR [#935](https://github.com/tact-lang/tact/pull/935)
- Docs: correctly handle next and previous page links at the bottom of the pages when there's a separator item in the sidebar: PR [#949](https://github.com/tact-lang/tact/pull/949)
- Docs: compilation of examples in `data-structures.mdx` and across Cookbook: PR [#917](https://github.com/tact-lang/tact/pull/917)

### Release contributors

Expand Down Expand Up @@ -69,8 +73,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- The `deepEquals` method for the `Map` type: PR [#637](https://github.com/tact-lang/tact/pull/637), PR [#939](https://github.com/tact-lang/tact/pull/939)
- `asm` bodies for module-level functions: PR [#769](https://github.com/tact-lang/tact/pull/769), PR [#825](https://github.com/tact-lang/tact/pull/825)
- Corresponding stdlib functions for new TVM instructions from 2023.07 and 2024.04 upgrades: PR [#331](https://github.com/tact-lang/tact/pull/331). Added the `storeBuilder` extension function and `gasConsumed`, `getComputeFee`, `getStorageFee`, `getForwardFee`, `getSimpleComputeFee`, `getSimpleForwardFee`, `getOriginalFwdFee`, `myStorageDue` functions.
- `slice`, `rawSlice`, `ascii` and `crc32` built-in functions: PR [#787](https://github.com/tact-lang/tact/pull/787), PR [#799](https://github.com/tact-lang/tact/pull/799)
- `Builder.storeMaybeRef`, `parseStdAddress` and `parseVarAddress` stdlib functions: PR [#793](https://github.com/tact-lang/tact/pull/793)
- `slice`, `rawSlice`, `ascii` and `crc32` built-in functions: PR [#787](https://github.com/tact-lang/tact/pull/787), PR [#799](https://github.com/tact-lang/tact/pull/799), PR [#951](https://github.com/tact-lang/tact/pull/951)
- `Builder.storeMaybeRef`, `parseStdAddress` and `parseVarAddress` stdlib functions: PR [#793](https://github.com/tact-lang/tact/pull/793), PR [#950](https://github.com/tact-lang/tact/pull/950)
- The compiler development guide: PR [#833](https://github.com/tact-lang/tact/pull/833)
- Constant evaluator now uses an interpreter: PR [#664](https://github.com/tact-lang/tact/pull/664). This allows calls to user-defined functions and references to declared global constants.

Expand Down
1 change: 1 addition & 0 deletions cspell-fift-words-adjusted.txt
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ Pos
Split
abort
abs
addop
allot
and
anon
Expand Down
2 changes: 2 additions & 0 deletions cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@
"Tarjan",
"testdata",
"Topup",
"Toncoin",
"Toncoins",
"Trunov",
"typechecker",
"uintptr",
Expand Down
4 changes: 4 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,10 @@ All commands are run from the root of the project, from a terminal:
| `yarn astro ...` | Run CLI commands like `astro add`, `astro check`, etc.
| `yarn astro -- --help` | Get help using the Astro CLI.

### ⚠️ Gotchas

- When updating TextMate grammars in `grammars/` (for example, `grammar-tact.json`), make sure that the value for the `"name"` property is written all lowercase, otherwise highlighting will break.

### 👀 Want to learn more about the framework behind Tact docs?

Check out [Starlight’s docs](https://starlight.astro.build/), read [the Astro documentation](https://docs.astro.build), or jump into the [Astro Discord server](https://astro.build/chat).
Expand Down
5 changes: 3 additions & 2 deletions docs/astro.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ export default defineConfig({
behavior: "append",
properties: {
class: "autolink-header",
ariaHidden: true,
ariaHidden: "true",
ariaLabel: "Link to this header",
tabIndex: -1,
},
}],
Expand Down Expand Up @@ -66,7 +67,7 @@ export default defineConfig({
// Per-page Google tag setup
tag: "script",
content: "window.dataLayer=window.dataLayer||[];function gtag(){dataLayer.push(arguments)}gtag('js',new Date());gtag('config','G-ZJ3GZHJ0Z5');",
}
},
],
social: {
github: 'https://github.com/tact-lang/tact',
Expand Down
38 changes: 11 additions & 27 deletions docs/cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,55 +2,39 @@
"$schema": "https://raw.githubusercontent.com/streetsidesoftware/cspell/main/cspell.schema.json",
"version": "0.2",
"language": "en",
"dictionaryDefinitions": [
{
"name": "fift-words",
"path": "../cspell-fift-words-adjusted.txt"
},
{
"name": "tvm-instructions",
"path": "../cspell-tvm-instructions.txt"
}
],
"dictionaries": ["fift-words", "tvm-instructions"],
"words": [
"ADDRAND",
"BBITS",
"BREFS",
"Brujin",
"CHKSIGNS",
"CHKSIGNU",
"CONFIGOPTPARAM",
"CTOS",
"Cheatsheet",
"Cheatsheets",
"Comptime",
"DEBUGSTR",
"DUEPAYMENT",
"Daniil",
"Decompilation",
"Decompiled",
"Descr",
"Domínguez",
"ENDC",
"Epva",
"Fift",
"Fift",
"GASCONSUMED",
"GETFORWARDFEE",
"GETFORWARDFEESIMPLE",
"GETGASFEE",
"GETGASFEESIMPLE",
"GETORIGINALFWDFEE",
"GETSTORAGEFEE",
"Georgiy",
"HASHCU",
"HASHEXT",
"HASHSU",
"Héctor",
"IPFS",
"Jesús",
"Jetton",
"Jettons",
"KECCAK",
"Komarov",
"Korshakov",
"LDDICT",
"LDIX",
"LDREF",
"LDSLICEX",
"LDUX",
"LDVARUINT",
"LTIME",
"Laika",
"MYADDR",
"Masterchain",
Expand Down
4 changes: 2 additions & 2 deletions docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,15 @@
"@astrojs/markdown-remark": "^5.2.0",
"@astrojs/starlight": "^0.28.2",
"astro": "^4.16.1",
"cspell": "^8.14.4",
"hast-util-to-string": "^3.0.0",
"rehype-autolink-headings": "7.1.0",
"rehype-katex": "7.0.1",
"remark-custom-heading-id": "2.0.0",
"remark-math": "6.0.0",
"sharp": "^0.32.5",
"starlight-links-validator": "^0.12.1",
"typescript": "^5.6.2",
"cspell": "^8.14.4",
"hast-util-to-string": "^3.0.0",
"unist-util-visit": "^5.0.0"
},
"packageManager": "[email protected]"
Expand Down
177 changes: 177 additions & 0 deletions docs/scripts/check-cookbook-examples.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
/*─────────────────────────────────────────────────────────────────────────────╗
│ IMPORTANT: │
│ Run this script from the root of the docs, not from the scripts directory! │
╞══════════════════════════════════════════════════════════════════════════════╡
│ The script: │
│ 1. Goes over every file in Cookbook │
│ 2. Extracts the Tact code blocks from them │
│ 3. For every code block, it runs the latest publicly available version │
│ of the Tact compiler, performing the syntax and type checking (--check) │
│ 4. If there are any errors, outputs them and exits │
│ │
│ Checks take ~0.5 seconds per code block, so lets use it for Cookbook only │
╚─────────────────────────────────────────────────────────────────────────────*/

import { spawnSync } from 'node:child_process';
import { tmpdir } from 'node:os';
import {
mkdtempSync,
mkdtemp,
readFileSync,
readdirSync,
statSync,
writeFileSync,
existsSync,
} from 'node:fs';
import { chdir, cwd } from 'node:process';
// TODO(?): check the proper dir (from git) and automatically change the working dir

/*******************/
/* Utility helpers */
/*******************/

/** Default directory for temporary files with / separator (because even PowerShell can use direct slash) */
const globalTmpDir = tmpdir() + '/';

/**
* Obtains the list of files with target extension in the target directory and its
* sub-directories as a flat array of names.
*
* @param dir {string | undefined} defaults to "." (current directory)
* @param extension {string | undefined} defaults to any file
* @returns {string[]}
*/
const getFileNames = (dir, extension) => {
/**
* @param dir {string | undefined}
* @param extension {string | undefined}
* @returns {string[]}
*/
const recGetFileNames = (dir, extension, _files) => {
_files = _files || [];
let files = readdirSync(dir);
for (let i in files) {
let name = dir + '/' + files[i];
if (statSync(name).isDirectory()) {
recGetFileNames(name, extension, _files);
continue;
}
if (extension === undefined || name.endsWith(extension)) {
_files.push(name.trim());
}
}
return _files;
};

return recGetFileNames(dir ?? ".", extension);
};

/**
* @param src {string} source of the .md or .mdx file to extract code blocks from
* @returns {string[]} all Tact code blocks on the page ready to be processed
*/
const extractTactCodeBlocks = (src) => {
/** @type RegExpExecArray[] */
const regexMatches = [...src.matchAll(/```(\w*).*?\n([\s\S]*?)```/gm)];
/** @type string[] */
let res = [];

for (let i = 0; i < regexMatches.length; i += 1) {
// Skip non-Tact matches
if (regexMatches[i].at(1)?.trim() !== "tact") {
continue;
}

// Guard the contents
let code = regexMatches[i].at(2)?.trim();
if (code === undefined || code.length === 0) {
console.log(`Error: regex failed when processing code blocks of:\n\n${src}`);
process.exit(1);
}

// See if the `code` needs additional wrapping in a global function or not
// i.e. if it doesn't contain any module-level items (implicit convention in Tact docs):
const moduleItems = code.split('\n').filter((line) => {
const matchRes = line.match(/^\s*(?:import|primitive|const|asm|fun|extends|mutates|virtual|override|inline|abstract|@name|@interface|contract|trait|struct|message)\b/);

if (matchRes === null) { return false; }
else { return true; }
});

if (moduleItems.length === 0) {
code = `fun _() {\n${code}\n}`;
}

// Save the code
res.push(code);
}

return res;
};

/**
* @requires Node.js 22+ with npm installed
* @param filepath {string} a path to Tact file
* @returns {{ ok: true } | { ok: false, error: string }}
*/
const checkTactFile = (filepath) => {
// Using the latest publicly available compiler to ensure that current users
// can compile and run the code, not just the compiler developers
const res = spawnSync('npx',
['-y', '@tact-lang/compiler@latest', '--check', filepath],
{ encoding: 'utf8' }
);

if (res.status !== 0) {
return {
ok: false,
error: res.stdout + res.stderr,
}
}

return { ok: true };
};

/**********/
/* Script */
/**********/

/** @type string */
const cookbookPath = "src/content/docs/cookbook";

if (!existsSync(cookbookPath)) {
console.log(`Error: path ${cookbookPath} doesn't exist, ensure that you're in the right directory!`);
process.exit(1);
}

/** @type string[] */
const mdxFileNames = getFileNames(cookbookPath, ".mdx");

for (let i = 0; i < mdxFileNames.length; i += 1) {
const file = readFileSync(mdxFileNames[i], { encoding: 'utf8' });
const codeBlocks = extractTactCodeBlocks(file);
const tmpDirForCurrentPage = mkdtempSync(globalTmpDir);
const pageName = mdxFileNames[i].slice(
mdxFileNames[i].lastIndexOf('/') + 1,
mdxFileNames[i].lastIndexOf('.mdx'),
);

for (let j = 0; j < codeBlocks.length; j += 1) {
const tactFile = `${tmpDirForCurrentPage}/${pageName}-block-${(j + 1).toString()}.tact`;
writeFileSync(tactFile, codeBlocks[j], { encoding: 'utf8', mode: '644' });
console.log(`Checking ${tactFile}`);

// TODO(?): Alternative solution would be to prepare a tact.config.json on the fly
const savedCwd = cwd();
chdir(tmpDirForCurrentPage);

// Perform individual checks (see TODO above)
const checkRes = checkTactFile(tactFile);
chdir(savedCwd);

if (checkRes.ok === false) {
console.log(`Error: check of ${tactFile} has failed:\n\n${checkRes.error}`);
process.exit(1);
}
}
}
Loading

0 comments on commit 9748b5a

Please sign in to comment.