CodeSampleX

Exemplo

typescript 7.0.2: Clone and duplicate synthesized TypeScript AST nodes using getSynthesizedDeepClone and getSynthesizedDeepClones

Amostra verificada para npm typescript 7.0.2: Clone and duplicate synthesized TypeScript AST nodes using getSynthesizedDeepClone and…

sha256:b825e6f5e2bcc408bb299633fbea559d439d5293dc80b9600075b2746159f6bf

Esta rede oferece uma coisa: uma amostra que compila. Ela a executou em um sandbox e guardou o recibo assinado. Não classifica nem garante nada — se o mesmo código compila onde você está, ela não mediu. Quantas chaves de assinatura distintas enviaram um recibo de contrato aprovado. Uma é só o autor; mais de uma significa que outra pessoa também o compilou. Uma chave é gerada por conta própria e não tem identidade registrada por trás, então conta chaves, não pessoas. MIT-0

Evidência de execução

O ambiente declarado e as execuções assinadas ficam separados, para você ver exatamente o que esta amostra executou e onde.

Base da evidência
Contrato assinado aprovado
Recibos de verificação
1
Chaves de assinatura que o compilaram
1
Ambiente declarado linux 24 · ubuntu · glibc 2.39 x64 npm

Ambientes das execuções de verificação

Ambiente Contrato Etapas Execução
node 22 · linux alpine/x64 · docker ed25519:c1973797be207ac4 PASS compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS
CONTAINER_RUN · node-typescript@1node:22-alpine@sha256:c610fcdfb1d5…
2026-08-28

Caso

HOW
Objetivo
Clone and duplicate synthesized TypeScript AST nodes using getSynthesizedDeepClone and getSynthesizedDeepClones
Pacotes
Símbolos
  • getSynthesizedDeepClone
  • getSynthesizedDeepClones
Criado
2026-08-28T07:00:15Z

Contrato

  1. cloneAstNode creates an independent deep copy of an AST node with identical structure and kind using getSynthesizedDeepClone
  2. cloneAstNodeArray creates an independent array of deep-cloned AST nodes using getSynthesizedDeepClones
  3. cloneAstNode with includeTrivia false resets pos and end text ranges to negative one
  4. duplicateObjectProperty deep-clones object properties and attaches transformed property assignments without mutating the original AST
  5. cloneFunctionWithNewName duplicates complete function declarations with parameters and body while retargeting identifier names

Arquivos

  • PROMPT.md
  • csx.json
  • package-lock.json
  • package.json
  • spec.json
  • src/index.mjs
  • test/contract.mjs

Baixar o artefato de código-fonte (tar.gz)

Código-fonte

PROMPT.md
Clean-room public code sample — generation instructions

Write a brand-new, minimal, self-contained code sample in this clean-room directory.
Do not copy, paraphrase, or reference any existing project source. Work only from this spec.

A csx.json manifest scaffold already exists. Do not recreate it from memory. Preserve its case.goal, packages and symbols; fill its empty case.contract with exact assertions and correct its environment, commands and verifierAdapter for the files you generate.

Goal: Clone and duplicate synthesized TypeScript AST nodes using getSynthesizedDeepClone and getSynthesizedDeepClones
Kind: HOW

Use EXACTLY these public packages and versions:
  - pkg:npm/typescript@7.0.2
Demonstrate these symbols/APIs:
  - getSynthesizedDeepClone
  - getSynthesizedDeepClones

Rules:
  - One focused purpose; the smallest project that proves the goal.
  - Include a contract test (test/contract.*) that runs OFFLINE and exits 0 exactly when the goal behavior works.
  - Pin every dependency with a lockfile so resolution is reproducible.
  - No secrets, credentials, or tokens. No real URLs (only example.com or localhost). No absolute paths.
  - No personal names, emails, company names, or project identifiers of any kind.
  - No binaries and no generated output (node_modules, dist, target, venv, .git, .env).
  - Keep it under 200 files and 256KB packed.
csx.json
{"case":{"caseId":"case:sha256:7b5c21ce860fd5cba7cdc5bd3bac4b9ce3dc96a313944aaf0987c02958f51e57","contract":["cloneAstNode creates an independent deep copy of an AST node with identical structure and kind using getSynthesizedDeepClone","cloneAstNodeArray creates an independent array of deep-cloned AST nodes using getSynthesizedDeepClones","cloneAstNode with includeTrivia false resets pos and end text ranges to negative one","duplicateObjectProperty deep-clones object properties and attaches transformed property assignments without mutating the original AST","cloneFunctionWithNewName duplicates complete function declarations with parameters and body while retargeting identifier names"],"goal":"Clone and duplicate synthesized TypeScript AST nodes using getSynthesizedDeepClone and getSynthesizedDeepClones","kind":"HOW","packages":["pkg:npm/typescript@7.0.2"],"schemaVersion":1,"symbols":["getSynthesizedDeepClone","getSynthesizedDeepClones"]},"contractCommand":["node","test/contract.mjs"],"environment":{"arch":"x64","distro":"ubuntu","ecosystem":"npm","libc":"glibc","libcVersion":"2.39","os":"linux","osVersionBucket":"24","packageManager":"npm","schemaVersion":1},"license":"MIT-0","packages":["pkg:npm/typescript@7.0.2"],"schemaVersion":1,"subject":"pkg:npm/typescript@7.0.2","symbols":["getSynthesizedDeepClone","getSynthesizedDeepClones"],"verifierAdapter":"node-typescript@1"}
package-lock.json
{
  "name": "typescript-ast-clone-sample",
  "version": "1.0.0",
  "lockfileVersion": 3,
  "requires": true,
  "packages": {
    "": {
      "name": "typescript-ast-clone-sample",
      "version": "1.0.0",
      "license": "MIT-0",
      "dependencies": {
        "typescript": "7.0.2"
      }
    },
    "node_modules/@typescript/typescript-aix-ppc64": {
      "version": "7.0.2",
      "resolved": "https://registry.npmjs.org/@typescript/typescript-aix-ppc64/-/typescript-aix-ppc64-7.0.2.tgz",
      "integrity": "sha512-MTKKkWB7p/0E9xi1d1tHtZ5PiLkGEMIq88pK2CubZjOsLtYTLqhgIgi6zepFa+9GHZ6h05NMCkQxGKiPXMxXtQ==",
      "cpu": [
        "ppc64"
      ],
      "license": "Apache-2.0",
      "optional": true,
      "os": [
        "aix"
      ],
      "engines": {
        "node": ">=16.20.0"
      }
    },
    "node_modules/@typescript/typescript-darwin-arm64": {
      "version": "7.0.2",
      "resolved": "https://registry.npmjs.org/@typescript/typescript-darwin-arm64/-/typescript-darwin-arm64-7.0.2.tgz",
      "integrity": "sha512-gowzar9MwS/aRWp6f3a4KUqzRjAZjOsmGNCM6LcTgXum+dBfgsBVMN+AgvOCCbguXyick6LJhpBszxMebJ8syA==",
      "cpu": [
        "arm64"
      ],
      "license": "Apache-2.0",
      "optional": true,
      "os": [
        "darwin"
      ],
      "engines": {
        "node": ">=16.20.0"
      }
    },
    "node_modules/@typescript/typescript-darwin-x64": {
      "version": "7.0.2",
      "resolved": "https://registry.npmjs.org/@typescript/typescript-darwin-x64/-/typescript-darwin-x64-7.0.2.tgz",
      "integrity": "sha512-SZ9xZInqApNlNGc9s0W1VSsktYSOe9cFqNOIqmN1Gs8SmkjKZYFt017G4VwPxASInODuAdbTW7sXiFUf893RgA==",
      "cpu": [
        "x64"
      ],
      "license": "Apache-2.0",
      "optional": true,
      "os": [
        "darwin"
      ],
      "engines": {
        "node": ">=16.20.0"
      }
    },
    "node_modules/@typescript/typescript-freebsd-arm64": {
      "version": "7.0.2",
      "resolved": "https://registry.npmjs.org/@typescript/typescript-freebsd-arm64/-/typescript-freebsd-arm64-7.0.2.tgz",
      "integrity": "sha512-W5NH4y/J0plIIS5b2xvTEkU7JFxyqdMAOgf+Ilhl0vHQXKO5dZoxd+C/jEtq56c4F3wk71RB4BMRQ2XdI+bwYQ==",
      "cpu": [
        "arm64"
      ],
      "license": "Apache-2.0",
      "optional": true,
      "os": [
        "freebsd"
      ],
      "engines": {
        "node": ">=16.20.0"
      }
    },
    "node_modules/@typescript/typescript-freebsd-x64": {
      "version": "7.0.2",
      "resolved": "https://registry.npmjs.org/@typescript/typescript-freebsd-x64/-/typescript-freebsd-x64-7.0.2.tgz",
      "integrity": "sha512-UMGDx5sTpzNw3WiPebH7l90IWfJggEd+egHt/q6p7/Cm3zqoV7VxkGXt+3DxPIw8CcmvAB0j3sVVfbhX+M4Tpw==",
      "cpu": [
        "x64"
      ],
      "license": "Apache-2.0",
      "optional": true,
      "os": [
        "freebsd"
      ],
      "engines": {
        "node": ">=16.20.0"
      }
    },
    "node_modules/@typescript/typescript-linux-arm": {
      "version": "7.0.2",
      "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-arm/-/typescript-linux-arm-7.0.2.tgz",
      "integrity": "sha512-gffT3xPz9sR7j/YJExkyPntrI0P2EP9XbOyWzth2/Gs0RstK+90RBcO0ncXoXy/beYll1SXw846Nf2zdnEz0QQ==",
      "cpu": [
        "arm"
      ],
      "license": "Apache-2.0",
      "optional": true,
      "os": [
        "linux"
      ],
      "engines": {
        "node": ">=16.20.0"
      }
    },
    "node_modules/@typescript/typescript-linux-arm64": {
      "version": "7.0.2",
      "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-arm64/-/typescript-linux-arm64-7.0.2.tgz",
      "integrity": "sha512-Qh4eU4/y3yDjnfjjyPYihMj5/ODIlmt+Bzu17OI+fiSRDW57QmU5SiN63exPRNJPKUzcc1INa1NXdrJ+MqHjUQ==",
      "cpu": [
        "arm64"
      ],
      "license": "Apache-2.0",
      "optional": true,
      "os": [
        "linux"
      ],
      "engines": {
        "node": ">=16.20.0"
      }
    },
    "node_modules/@typescript/typescript-linux-loong64": {
      "version": "7.0.2",
      "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-loong64/-/typescript-linux-loong64-7.0.2.tgz",
      "integrity": "sha512-uEHck9i8hoAzXPiYRib1O7miOnz23SxIeVl6F4LXox+qov1K35jHcEW6VHKvZI+pyvl7fZEP4MCU5LYvIq1GuQ==",
      "cpu": [
        "loong64"
      ],
      "license": "Apache-2.0",
      "optional": true,
      "os": [
        "linux"
      ],
      "engines": {
        "node": ">=16.20.0"
      }
    },
    "node_modules/@typescript/typescript-linux-mips64el": {
      "version": "7.0.2",
      "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-mips64el/-/typescript-linux-mips64el-7.0.2.tgz",
      "integrity": "sha512-R4KvAMnE43W5Qeqb0Ly56O3mWMWIAgsMyz36DCaycd5nbg/9kzm0liw3JocfRqyJY0KPmzFjbswozXyW0DnIYA==",
      "cpu": [
        "mips64el"
      ],
      "license": "Apache-2.0",
      "optional": true,
      "os": [
        "linux"
      ],
      "engines": {
        "node": ">=16.20.0"
      }
    },
    "node_modules/@typescript/typescript-linux-ppc64": {
      "version": "7.0.2",
      "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-ppc64/-/typescript-linux-ppc64-7.0.2.tgz",
      "integrity": "sha512-DORx5b3sd/4S7eayxm4FQv+A7CrkUIGRaHiwI8oiHTAI1fAPWhF4J0vAlkC8biAlHSVVwxMQ3tjZ2/DVbnQiiA==",
      "cpu": [
        "ppc64"
      ],
      "license": "Apache-2.0",
      "optional": true,
      "os": [
        "linux"
      ],
      "engines": {
        "node": ">=16.20.0"
      }
    },
    "node_modules/@typescript/typescript-linux-riscv64": {
      "version": "7.0.2",
      "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-riscv64/-/typescript-linux-riscv64-7.0.2.tgz",
      "integrity": "sha512-wf0jqEDOjrPRnKwYRyyJDRo11KMbvMFrU+q4zqKyChODBzvlkbhNQfKvLxQCcwTpdDaXSHZTVuh0JoCrKCUMHQ==",
      "cpu": [
        "riscv64"
      ],
      "license": "Apache-2.0",
      "optional": true,
      "os": [
        "linux"
      ],
      "engines": {
        "node": ">=16.20.0"
      }
    },
    "node_modules/@typescript/typescript-linux-s390x": {
      "version": "7.0.2",
      "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-s390x/-/typescript-linux-s390x-7.0.2.tgz",
      "integrity": "sha512-IkwJc3L7yhytWd/ewjyxNDfOmswCm9GWMJT/ue/dU4aZNbwZeYAetq42VyLmsmSjvoX7z74X6ZaYCtzAr0EuGw==",
      "cpu": [
        "s390x"
      ],
      "license": "Apache-2.0",
      "optional": true,
      "os": [
        "linux"
      ],
      "engines": {
        "node": ">=16.20.0"
      }
    },
    "node_modules/@typescript/typescript-linux-x64": {
      "version": "7.0.2",
      "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-x64/-/typescript-linux-x64-7.0.2.tgz",
      "integrity": "sha512-EYdf2cNg7rgCWJnxCdJ+F3V39O8ihb37eHAu1LK8oAFizgTQbPOK7zHHXbPt8rX24COqODXeI3sIf0fCXG7H/A==",
      "cpu": [
        "x64"
      ],
      "license": "Apache-2.0",
      "optional": true,
      "os": [
        "linux"
      ],
      "engines": {
        "node": ">=16.20.0"
      }
    },
    "node_modules/@typescript/typescript-netbsd-arm64": {
      "version": "7.0.2",
      "resolved": "https://registry.npmjs.org/@typescript/typescript-netbsd-arm64/-/typescript-netbsd-arm64-7.0.2.tgz",
      "integrity": "sha512-+polYF4MF04aPpO5FTkHran9yUQDSXqy5GiSDKpsll5jy3l3+g9QLhpf39T+ePtefhXLOGrLl0QIjkQP6VnelA==",
      "cpu": [
        "arm64"
      ],
      "license": "Apache-2.0",
      "optional": true,
      "os": [
        "netbsd"
      ],
      "engines": {
        "node": ">=16.20.0"
      }
    },
    "node_modules/@typescript/typescript-netbsd-x64": {
      "version": "7.0.2",
      "resolved": "https://registry.npmjs.org/@typescript/typescript-netbsd-x64/-/typescript-netbsd-x64-7.0.2.tgz",
      "integrity": "sha512-8YIT0EHM/3dq10ZOVF/A7pc/YSMtbcecct4rWtexrnSCHOPcpC2KTLXfTCR6vDpnSiY12heNb1GiN/wu+T/FyA==",
      "cpu": [
        "x64"
      ],
      "license": "Apache-2.0",
      "optional": true,
      "os": [
        "netbsd"
      ],
      "engines": {
        "node": ">=16.20.0"
      }
    },
    "node_modules/@typescript/typescript-openbsd-arm64": {
      "version": "7.0.2",
      "resolved": "https://registry.npmjs.org/@typescript/typescript-openbsd-arm64/-/typescript-openbsd-arm64-7.0.2.tgz",
      "integrity": "sha512-APT8+ClYnuYm1u9+kgGXoMj2VzWzcymwh2gNSQVySHfkRDGOTVkoWLjCmOQSaO+PoqQ57B0flRp9SA+7GnnkzQ==",
      "cpu": [
        "arm64"
      ],
      "license": "Apache-2.0",
      "optional": true,
      "os": [
        "openbsd"
      ],
      "engines": {
        "node": ">=16.20.0"
      }
    },
    "node_modules/@typescript/typescript-openbsd-x64": {
      "version": "7.0.2",
      "resolved": "https://registry.npmjs.org/@typescript/typescript-openbsd-x64/-/typescript-openbsd-x64-7.0.2.tgz",
      "integrity": "sha512-yX7s+Q0Dln0Dt9tEzZsAjXXR/+ytBM7AlglaqyeMPxQszJ1JhlJdZ6jLA+IzldHtflX81em7lDao1xXu+aRRkg==",
      "cpu": [
        "x64"
      ],
      "license": "Apache-2.0",
      "optional": true,
      "os": [
        "openbsd"
      ],
      "engines": {
        "node": ">=16.20.0"
      }
    },
    "node_modules/@typescript/typescript-sunos-x64": {
      "version": "7.0.2",
      "resolved": "https://registry.npmjs.org/@typescript/typescript-sunos-x64/-/typescript-sunos-x64-7.0.2.tgz",
      "integrity": "sha512-dLJDGaLZ1D4HPQn62u1n8mBDkJREwMsAkCdkwd4Ieqw+x3TUyTsqY0YiBCtE6H6OzzgGk3iuZ3vFWRS+E8/d1g==",
      "cpu": [
        "x64"
      ],
      "license": "Apache-2.0",
      "optional": true,
      "os": [
        "sunos"
      ],
      "engines": {
        "node": ">=16.20.0"
      }
    },
    "node_modules/@typescript/typescript-win32-arm64": {
      "version": "7.0.2",
      "resolved": "https://registry.npmjs.org/@typescript/typescript-win32-arm64/-/typescript-win32-arm64-7.0.2.tgz",
      "integrity": "sha512-Gyl1Vy6OsWesLzmq+EP0Fb7b4Nid5232AvcA2SFcdYreldpNtYFFofPjnt62y9hQy7VTaZp65ICJjuAQRaVcIQ==",
      "cpu": [
        "arm64"
      ],
      "license": "Apache-2.0",
      "optional": true,
      "os": [
        "win32"
      ],
      "engines": {
        "node": ">=16.20.0"
      }
    },
    "node_modules/@typescript/typescript-win32-x64": {
      "version": "7.0.2",
      "resolved": "https://registry.npmjs.org/@typescript/typescript-win32-x64/-/typescript-win32-x64-7.0.2.tgz",
      "integrity": "sha512-0BQ3HkAHHlKLSp1qRvf3SUhGpGsDuhB/jgFw75guyqbxJqEaS0Cw/VFO8i2nHglJUzQCRtMMR/IBAKE3ETMC4g==",
      "cpu": [
        "x64"
      ],
      "license": "Apache-2.0",
      "optional": true,
      "os": [
        "win32"
      ],
      "engines": {
        "node": ">=16.20.0"
      }
    },
    "node_modules/typescript": {
      "version": "7.0.2",
      "resolved": "https://registry.npmjs.org/typescript/-/typescript-7.0.2.tgz",
      "integrity": "sha512-8FYau96o3NKOhbjKi/qNvG/W5jhzxkbdm5sj9AbZ/5T5sWqn3hJgLfGx27sRKZWTvyzCP8dLRBTf5tBTSRVUNA==",
      "license": "Apache-2.0",
      "bin": {
        "tsc": "bin/tsc"
      },
      "engines": {
        "node": ">=16.20.0"
      },
      "optionalDependencies": {
        "@typescript/typescript-aix-ppc64": "7.0.2",
        "@typescript/typescript-darwin-arm64": "7.0.2",
        "@typescript/typescript-darwin-x64": "7.0.2",
        "@typescript/typescript-freebsd-arm64": "7.0.2",
        "@typescript/typescript-freebsd-x64": "7.0.2",
        "@typescript/typescript-linux-arm": "7.0.2",
        "@typescript/typescript-linux-arm64": "7.0.2",
        "@typescript/typescript-linux-loong64": "7.0.2",
        "@typescript/typescript-linux-mips64el": "7.0.2",
        "@typescript/typescript-linux-ppc64": "7.0.2",
        "@typescript/typescript-linux-riscv64": "7.0.2",
        "@typescript/typescript-linux-s390x": "7.0.2",
        "@typescript/typescript-linux-x64": "7.0.2",
        "@typescript/typescript-netbsd-arm64": "7.0.2",
        "@typescript/typescript-netbsd-x64": "7.0.2",
        "@typescript/typescript-openbsd-arm64": "7.0.2",
        "@typescript/typescript-openbsd-x64": "7.0.2",
        "@typescript/typescript-sunos-x64": "7.0.2",
        "@typescript/typescript-win32-arm64": "7.0.2",
        "@typescript/typescript-win32-x64": "7.0.2"
      }
    }
  }
}
package.json
{
  "name": "typescript-ast-clone-sample",
  "version": "1.0.0",
  "description": "Clone and duplicate synthesized TypeScript AST nodes using getSynthesizedDeepClone and getSynthesizedDeepClones",
  "type": "module",
  "main": "src/index.mjs",
  "scripts": {
    "test": "node test/contract.mjs"
  },
  "dependencies": {
    "typescript": "7.0.2"
  },
  "license": "MIT-0"
}
spec.json
{
  "schemaVersion": 1,
  "goal": "Clone and duplicate synthesized TypeScript AST nodes using getSynthesizedDeepClone and getSynthesizedDeepClones",
  "kind": "HOW",
  "packages": [
    "pkg:npm/typescript@7.0.2"
  ],
  "symbols": [
    "getSynthesizedDeepClone",
    "getSynthesizedDeepClones"
  ]
}
src/index.mjs
import {
  getSynthesizedDeepClone,
  getSynthesizedDeepClones,
} from 'typescript/unstable/ast/clone';

import {
  createIdentifier,
  createStringLiteral,
  createNumericLiteral,
  createPropertyAssignment,
  createObjectLiteralExpression,
  createArrayLiteralExpression,
  createFunctionDeclaration,
  createParameterDeclaration,
  createBlock,
  createReturnStatement,
  createBinaryExpression,
  createCallExpression,
} from 'typescript/unstable/ast/factory';

import {
  isIdentifier,
  isStringLiteral,
  isNumericLiteral,
  isPropertyAssignment,
  isObjectLiteralExpression,
  isArrayLiteralExpression,
  isFunctionDeclaration,
  isParameterDeclaration,
  isBlock,
  isReturnStatement,
  isBinaryExpression,
  isCallExpression,
} from 'typescript/unstable/ast/is';

import {
  SyntaxKind,
  formatSyntaxKind,
} from 'typescript/unstable/ast';

/**
 * Deep clones a single synthesized AST node.
 *
 * @param {object} node - The AST node to clone.
 * @param {boolean} [includeTrivia=true] - Whether to preserve trivia / text range positions.
 * @returns {object} A distinct deep clone of the input AST node.
 */
export function cloneAstNode(node, includeTrivia = true) {
  if (!node || typeof node !== 'object') {
    throw new TypeError('Expected AST node object to clone');
  }
  return getSynthesizedDeepClone(node, includeTrivia);
}

/**
 * Deep clones an array of synthesized AST nodes.
 *
 * @param {Array<object>} nodes - Array of AST nodes to clone.
 * @param {boolean} [includeTrivia=true] - Whether to preserve trivia / text range positions.
 * @returns {Array<object>} A new array containing distinct deep clones of each node.
 */
export function cloneAstNodeArray(nodes, includeTrivia = true) {
  if (!Array.isArray(nodes)) {
    throw new TypeError('Expected an array of AST nodes to clone');
  }
  return getSynthesizedDeepClones(nodes, includeTrivia);
}

/**
 * Clones an ObjectLiteralExpression and adds or replaces a property assignment with a transformed copy.
 *
 * @param {object} objectLiteral - The source ObjectLiteralExpression AST node.
 * @param {string} sourcePropertyName - The name of the property to duplicate/transform.
 * @param {string} targetPropertyName - The name for the newly cloned property.
 * @param {Function} [transformFn] - Optional transformer for the property initializer.
 * @returns {object} A new ObjectLiteralExpression with cloned and updated properties.
 */
export function duplicateObjectProperty(
  objectLiteral,
  sourcePropertyName,
  targetPropertyName,
  transformFn
) {
  if (!objectLiteral || !isObjectLiteralExpression(objectLiteral)) {
    throw new TypeError('Expected an ObjectLiteralExpression AST node');
  }

  const clonedProps = objectLiteral.properties.map((prop) => {
    const cloned = getSynthesizedDeepClone(prop);
    return cloned;
  });

  const sourceProp = objectLiteral.properties.find(
    (prop) => isPropertyAssignment(prop) && prop.name?.text === sourcePropertyName
  );

  if (!sourceProp) {
    throw new Error(`Property '${sourcePropertyName}' not found in object literal`);
  }

  const clonedInit = getSynthesizedDeepClone(sourceProp.initializer);
  const transformedInit = transformFn ? transformFn(clonedInit) : clonedInit;

  const newProp = createPropertyAssignment(
    undefined,
    createIdentifier(targetPropertyName),
    undefined,
    undefined,
    transformedInit
  );

  return createObjectLiteralExpression([...clonedProps, newProp]);
}

/**
 * Creates a cloned function declaration with a modified identifier name.
 *
 * @param {object} functionDecl - Source FunctionDeclaration AST node.
 * @param {string} newName - New name for the cloned function.
 * @returns {object} Cloned FunctionDeclaration AST node with the new name.
 */
export function cloneFunctionWithNewName(functionDecl, newName) {
  if (!functionDecl || !isFunctionDeclaration(functionDecl)) {
    throw new TypeError('Expected a FunctionDeclaration AST node');
  }

  const cloned = getSynthesizedDeepClone(functionDecl);
  const newIdentifier = createIdentifier(newName);

  return createFunctionDeclaration(
    cloned.modifiers,
    cloned.asteriskToken,
    newIdentifier,
    cloned.typeParameters,
    cloned.parameters,
    cloned.type,
    cloned.body
  );
}

export {
  getSynthesizedDeepClone,
  getSynthesizedDeepClones,
  createIdentifier,
  createStringLiteral,
  createNumericLiteral,
  createPropertyAssignment,
  createObjectLiteralExpression,
  createArrayLiteralExpression,
  createFunctionDeclaration,
  createParameterDeclaration,
  createBlock,
  createReturnStatement,
  createBinaryExpression,
  createCallExpression,
  isIdentifier,
  isStringLiteral,
  isNumericLiteral,
  isPropertyAssignment,
  isObjectLiteralExpression,
  isArrayLiteralExpression,
  isFunctionDeclaration,
  isParameterDeclaration,
  isBlock,
  isReturnStatement,
  isBinaryExpression,
  isCallExpression,
  SyntaxKind,
  formatSyntaxKind,
};
test/contract.mjs
import assert from 'node:assert/strict';
import {
  cloneAstNode,
  cloneAstNodeArray,
  duplicateObjectProperty,
  cloneFunctionWithNewName,
  getSynthesizedDeepClone,
  getSynthesizedDeepClones,
  createIdentifier,
  createStringLiteral,
  createNumericLiteral,
  createPropertyAssignment,
  createObjectLiteralExpression,
  createArrayLiteralExpression,
  createFunctionDeclaration,
  createParameterDeclaration,
  createBlock,
  createReturnStatement,
  isIdentifier,
  isStringLiteral,
  isNumericLiteral,
  isPropertyAssignment,
  isObjectLiteralExpression,
  isArrayLiteralExpression,
  isFunctionDeclaration,
  SyntaxKind,
  formatSyntaxKind,
} from '../src/index.mjs';

// Contract 1: cloneAstNode creates an independent deep copy of an AST node with identical structure and kind using getSynthesizedDeepClone
{
  const id = createIdentifier('originalIdentifier');
  const clonedId = cloneAstNode(id);

  assert.ok(clonedId, 'Cloned identifier should be defined');
  assert.strictEqual(isIdentifier(clonedId), true, 'Cloned node should satisfy isIdentifier');
  assert.strictEqual(clonedId.text, 'originalIdentifier', 'Cloned identifier text should match original');
  assert.notStrictEqual(id, clonedId, 'Cloned identifier should be a distinct memory reference');
  assert.strictEqual(formatSyntaxKind(clonedId.kind), 'Identifier', 'Kind name should be Identifier');

  const strLit = createStringLiteral('sample-value');
  const clonedStr = cloneAstNode(strLit);
  assert.strictEqual(isStringLiteral(clonedStr), true, 'Cloned node should satisfy isStringLiteral');
  assert.strictEqual(clonedStr.text, 'sample-value', 'String literal text should match');
  assert.notStrictEqual(strLit, clonedStr, 'String literal should be a distinct instance');

  assert.throws(
    () => cloneAstNode(null),
    { name: 'TypeError' },
    'cloneAstNode should throw TypeError on null input'
  );
}

// Contract 2: cloneAstNodeArray creates an independent array of deep-cloned AST nodes using getSynthesizedDeepClones
{
  const list = [
    createStringLiteral('entryA'),
    createNumericLiteral('42'),
    createIdentifier('variableX'),
  ];
  const clonedList = cloneAstNodeArray(list);

  assert.ok(Array.isArray(clonedList), 'Cloned list should be an array');
  assert.strictEqual(clonedList.length, 3, 'Cloned list length should match original');
  assert.notStrictEqual(list, clonedList, 'Cloned list array reference should be distinct');

  assert.strictEqual(isStringLiteral(clonedList[0]), true, 'First element should be StringLiteral');
  assert.strictEqual(clonedList[0].text, 'entryA', 'First element text should match');
  assert.notStrictEqual(list[0], clonedList[0], 'First element should be distinct reference');

  assert.strictEqual(isNumericLiteral(clonedList[1]), true, 'Second element should be NumericLiteral');
  assert.strictEqual(clonedList[1].text, '42', 'Second element text should match');
  assert.notStrictEqual(list[1], clonedList[1], 'Second element should be distinct reference');

  assert.strictEqual(isIdentifier(clonedList[2]), true, 'Third element should be Identifier');
  assert.strictEqual(clonedList[2].text, 'variableX', 'Third element text should match');
  assert.notStrictEqual(list[2], clonedList[2], 'Third element should be distinct reference');

  assert.throws(
    () => cloneAstNodeArray('invalid'),
    { name: 'TypeError' },
    'cloneAstNodeArray should throw TypeError on non-array input'
  );
}

// Contract 3: cloneAstNode with includeTrivia false resets pos and end text ranges to negative one
{
  const nodeWithPos = createIdentifier('positionedIdentifier');
  nodeWithPos.pos = 12;
  nodeWithPos.end = 32;

  const cloneWithTrivia = cloneAstNode(nodeWithPos, true);
  assert.strictEqual(cloneWithTrivia.pos, 12, 'Clone with trivia should retain pos');
  assert.strictEqual(cloneWithTrivia.end, 32, 'Clone with trivia should retain end');

  const cloneNoTrivia = cloneAstNode(nodeWithPos, false);
  assert.strictEqual(cloneNoTrivia.pos, -1, 'Clone without trivia should have pos reset to -1');
  assert.strictEqual(cloneNoTrivia.end, -1, 'Clone without trivia should have end reset to -1');
  assert.strictEqual(cloneNoTrivia.text, 'positionedIdentifier', 'Identifier text should still be preserved');
}

// Contract 4: duplicateObjectProperty deep-clones object properties and attaches transformed property assignments without mutating the original AST
{
  const propPort = createPropertyAssignment(
    undefined,
    createIdentifier('port'),
    undefined,
    undefined,
    createNumericLiteral('8080')
  );
  const propHost = createPropertyAssignment(
    undefined,
    createIdentifier('host'),
    undefined,
    undefined,
    createStringLiteral('localhost')
  );
  const originalObj = createObjectLiteralExpression([propPort, propHost]);

  const updatedObj = duplicateObjectProperty(
    originalObj,
    'port',
    'fallbackPort',
    (init) => createNumericLiteral('9090')
  );

  assert.strictEqual(isObjectLiteralExpression(updatedObj), true, 'Updated object should be ObjectLiteralExpression');
  assert.strictEqual(originalObj.properties.length, 2, 'Original object properties count should remain 2');
  assert.strictEqual(updatedObj.properties.length, 3, 'Updated object should contain 3 properties');

  assert.strictEqual(updatedObj.properties[0].name.text, 'port', 'First property should remain port');
  assert.strictEqual(updatedObj.properties[0].initializer.text, '8080', 'First property value should remain 8080');
  assert.notStrictEqual(originalObj.properties[0], updatedObj.properties[0], 'First property should be a deep clone');

  assert.strictEqual(updatedObj.properties[2].name.text, 'fallbackPort', 'Third property should be fallbackPort');
  assert.strictEqual(updatedObj.properties[2].initializer.text, '9090', 'Third property value should be 9090');

  assert.throws(
    () => duplicateObjectProperty(originalObj, 'nonExistentKey', 'newKey'),
    /Property 'nonExistentKey' not found/,
    'duplicateObjectProperty should throw when source property does not exist'
  );
}

// Contract 5: cloneFunctionWithNewName duplicates complete function declarations with parameters and body while retargeting identifier names
{
  const param = createParameterDeclaration(
    undefined,
    undefined,
    createIdentifier('inputVal'),
    undefined,
    undefined,
    undefined
  );
  const bodyReturn = createReturnStatement(createIdentifier('inputVal'));
  const bodyBlock = createBlock([bodyReturn], true);

  const originalFn = createFunctionDeclaration(
    undefined,
    undefined,
    createIdentifier('handlerA'),
    undefined,
    [param],
    undefined,
    bodyBlock
  );

  const clonedFn = cloneFunctionWithNewName(originalFn, 'handlerB');

  assert.strictEqual(isFunctionDeclaration(clonedFn), true, 'Cloned function should satisfy isFunctionDeclaration');
  assert.strictEqual(originalFn.name.text, 'handlerA', 'Original function name should be handlerA');
  assert.strictEqual(clonedFn.name.text, 'handlerB', 'Cloned function name should be handlerB');

  assert.strictEqual(clonedFn.parameters.length, 1, 'Cloned function should retain 1 parameter');
  assert.strictEqual(clonedFn.parameters[0].name.text, 'inputVal', 'Parameter name should match');
  assert.notStrictEqual(originalFn.parameters[0], clonedFn.parameters[0], 'Parameter should be distinct clone');

  assert.notStrictEqual(originalFn.body, clonedFn.body, 'Function body should be distinct clone');
  assert.strictEqual(clonedFn.body.statements.length, 1, 'Body should retain return statement');

  assert.throws(
    () => cloneFunctionWithNewName(null, 'test'),
    { name: 'TypeError' },
    'cloneFunctionWithNewName should throw on invalid function node'
  );
}

Seeder de origem

anônimo