CodeSampleX

示例

postcss 8.5.26: Node#prev

已验证示例 — npm postcss 8.5.26: Node#prev. contract 在 node 22 · linux alpine/x64 · docker 上运行并通过: assert Node#prev returns undefined for the first child in a…

sha256:749f824d188b090e04c1de57637c1f626c802cf38b03d49c582cb17515de6df4

本网络只提供一件事:能构建的样本。它在沙箱中运行并保留签名回执。它不评级、不担保——同样的代码能否在你的环境构建,它没有测量过。 提交了通过的契约回执的不同签名密钥数量。为 1 表示只有作者;大于 1 表示还有其他人构建过。密钥是自行生成的,背后没有注册身份,因此计的是密钥而非人。 MIT-0

执行证据

声明的环境与签名的运行分开呈现,你可以看到这个样本究竟运行了什么、在哪里运行。

证据依据
签名契约通过
验证回执
1
构建过它的签名密钥
1
声明的环境 node 22.23 linux 24 · ubuntu · glibc 2.39 x64 node 22.23 javascript npm 10

验证运行环境

环境 契约 阶段 运行日期
node 22 · linux alpine/x64 · docker ed25519:d91480838ac982c9 PASS compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS
CONTAINER_RUN · node-typescript@1node:22-alpine@sha256:c610fcdfb1d5…
2026-08-27

案例

HOW
目标
verify Node#prev in pkg:npm/postcss@8.5.26
包
符号
  • Node#prev
环境
node 22.23.2
创建时间
2026-08-27T02:00:43Z

契约

  1. assert Node#prev returns undefined for the first child in a container
  2. assert Node#prev returns undefined for an unattached or standalone node
  3. assert Node#prev returns the previous sibling Node for declarations within a rule
  4. assert Node#prev returns the previous sibling Node for rules and at-rules in root
  5. assert Node#prev enables backward traversal through container children
  6. assert Node#prev reflects AST mutations when siblings are removed or inserted

文件

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

下载源代码构件 (tar.gz)

源代码

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: verify Node#prev in pkg:npm/postcss@8.5.26
Kind: HOW

Use EXACTLY these public packages and versions:
  - pkg:npm/postcss@8.5.26
Demonstrate these symbols/APIs:
  - Node#prev
Constraints:
  - executionContext: node
Required runtime conditions:
  - ecosystem: npm
  - language: javascript
  - moduleSystem: cjs
  - packageManager: npm@10.9.8
  - runtime: node@22.23.2

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:fbeb8a020fac184f0906f44acb03bf5e860c51dc172d1a2784f3e93fbcec21df","constraints":{"executionContext":"node"},"contract":["assert Node#prev returns undefined for the first child in a container","assert Node#prev returns undefined for an unattached or standalone node","assert Node#prev returns the previous sibling Node for declarations within a rule","assert Node#prev returns the previous sibling Node for rules and at-rules in root","assert Node#prev enables backward traversal through container children","assert Node#prev reflects AST mutations when siblings are removed or inserted"],"goal":"verify Node#prev in pkg:npm/postcss@8.5.26","kind":"HOW","packages":["pkg:npm/postcss@8.5.26"],"schemaVersion":1,"symbols":["Node#prev"]},"contractCommand":["node","test/contract.mjs"],"environment":{"arch":"x64","distro":"ubuntu","ecosystem":"npm","executionContext":"node","language":"javascript","libc":"glibc","libcVersion":"2.39","moduleSystem":"esm","os":"linux","osVersionBucket":"24","packageManager":"npm","packageManagerVersion":"10.9.8","runtime":"node","runtimeVersion":"22.23.2","schemaVersion":1},"license":"MIT-0","packages":["pkg:npm/postcss@8.5.26"],"schemaVersion":1,"subject":"pkg:npm/postcss@8.5.26","symbols":["Node#prev"],"verifierAdapter":"node-typescript@1"}
package-lock.json
{
  "name": "sample-postcss-node-prev",
  "version": "1.0.0",
  "lockfileVersion": 3,
  "requires": true,
  "packages": {
    "": {
      "name": "sample-postcss-node-prev",
      "version": "1.0.0",
      "license": "MIT-0",
      "dependencies": {
        "postcss": "8.5.26"
      }
    },
    "node_modules/nanoid": {
      "version": "3.3.18",
      "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.18.tgz",
      "integrity": "sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==",
      "funding": [
        {
          "type": "github",
          "url": "https://github.com/sponsors/ai"
        }
      ],
      "license": "MIT",
      "bin": {
        "nanoid": "bin/nanoid.cjs"
      },
      "engines": {
        "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
      }
    },
    "node_modules/picocolors": {
      "version": "1.1.1",
      "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
      "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
      "license": "ISC"
    },
    "node_modules/postcss": {
      "version": "8.5.26",
      "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.26.tgz",
      "integrity": "sha512-u82N74LFzG8ca+dD8puPnplTXoGH4fTPpVGuIbt36G3qvNlkvfD0lEAZSxaly3KX8TS/L1A1gsCEmvKmBcVbkQ==",
      "funding": [
        {
          "type": "opencollective",
          "url": "https://opencollective.com/postcss/"
        },
        {
          "type": "tidelift",
          "url": "https://tidelift.com/funding/github/npm/postcss"
        },
        {
          "type": "github",
          "url": "https://github.com/sponsors/ai"
        }
      ],
      "license": "MIT",
      "dependencies": {
        "nanoid": "^3.3.17",
        "picocolors": "^1.1.1",
        "source-map-js": "^1.2.1"
      },
      "engines": {
        "node": "^10 || ^12 || >=14"
      }
    },
    "node_modules/source-map-js": {
      "version": "1.2.1",
      "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
      "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
      "license": "BSD-3-Clause",
      "engines": {
        "node": ">=0.10.0"
      }
    }
  }
}
package.json
{
  "name": "sample-postcss-node-prev",
  "version": "1.0.0",
  "description": "Clean-room sample verifying Node#prev in postcss",
  "main": "src/index.js",
  "type": "module",
  "license": "MIT-0",
  "dependencies": {
    "postcss": "8.5.26"
  }
}
spec.json
{
  "schemaVersion": 1,
  "goal": "verify Node#prev in pkg:npm/postcss@8.5.26",
  "kind": "HOW",
  "packages": [
    "pkg:npm/postcss@8.5.26"
  ],
  "symbols": [
    "Node#prev"
  ],
  "constraints": {
    "executionContext": "node"
  },
  "runtimeConditions": {
    "ecosystem": "npm",
    "language": "javascript",
    "moduleSystem": "cjs",
    "packageManager": "npm@10.9.8",
    "runtime": "node@22.23.2"
  }
}
src/index.js
import postcss from 'postcss';

/**
 * Returns the immediate previous sibling of a node in its parent container,
 * or undefined if the node is the first child or unattached.
 *
 * @param {import('postcss').Node} node
 * @returns {import('postcss').Node | undefined}
 */
export function getPreviousSibling(node) {
  if (!node || typeof node.prev !== 'function') {
    return undefined;
  }
  return node.prev();
}

/**
 * Collects all preceding siblings of a node in the container,
 * ordered from closest preceding sibling backwards to the first child.
 *
 * @param {import('postcss').Node} node
 * @returns {import('postcss').Node[]}
 */
export function collectPrecedingSiblings(node) {
  const preceding = [];
  if (!node || typeof node.prev !== 'function') {
    return preceding;
  }

  let current = node.prev();
  while (current) {
    preceding.push(current);
    current = current.prev();
  }

  return preceding;
}

/**
 * Traverses backwards from the given node to find the nearest preceding Declaration
 * matching the given CSS property name.
 *
 * @param {import('postcss').Node} node
 * @param {string} propName
 * @returns {import('postcss').Declaration | undefined}
 */
export function findPreviousDeclaration(node, propName) {
  if (!node || typeof node.prev !== 'function') {
    return undefined;
  }

  let current = node.prev();
  while (current) {
    if (current.type === 'decl' && current.prop === propName) {
      return current;
    }
    current = current.prev();
  }

  return undefined;
}

/**
 * Checks if a node is the first child of its parent container.
 *
 * @param {import('postcss').Node} node
 * @returns {boolean}
 */
export function isFirstChild(node) {
  if (!node || !node.parent) {
    return false;
  }
  return node.prev() === undefined;
}
test/contract.mjs
import assert from 'node:assert/strict';
import postcss from 'postcss';
import {
  getPreviousSibling,
  collectPrecedingSiblings,
  findPreviousDeclaration,
  isFirstChild
} from '../src/index.js';

// 1. assert Node#prev returns undefined for the first child in a container
{
  const css = `
    .card {
      display: flex;
      margin: 10px;
      padding: 5px;
    }
  `;
  const root = postcss.parse(css);
  const rule = root.first;
  assert.ok(rule, 'Rule should exist in parsed CSS');

  const firstDecl = rule.first;
  assert.ok(firstDecl, 'Rule first child declaration should exist');
  assert.equal(firstDecl.prop, 'display');

  // Direct Node#prev call
  assert.equal(firstDecl.prev(), undefined, 'First declaration prev() must return undefined');
  assert.equal(getPreviousSibling(firstDecl), undefined, 'Helper must return undefined for first child');
  assert.equal(isFirstChild(firstDecl), true, 'isFirstChild helper must return true for first declaration');

  // Root's first child
  assert.equal(rule.prev(), undefined, 'First child rule in root prev() must return undefined');
  assert.equal(isFirstChild(rule), true, 'isFirstChild helper must return true for first rule in root');
}

// 2. assert Node#prev returns undefined for an unattached or standalone node
{
  const standaloneDecl = postcss.decl({ prop: 'color', value: 'blue' });
  const standaloneRule = postcss.rule({ selector: '.standalone' });

  assert.equal(standaloneDecl.parent, undefined, 'Standalone decl should have no parent');
  assert.equal(standaloneDecl.prev(), undefined, 'Unattached decl prev() must return undefined');
  assert.equal(getPreviousSibling(standaloneDecl), undefined, 'Helper must return undefined for unattached decl');
  assert.equal(isFirstChild(standaloneDecl), false, 'isFirstChild must return false for unattached decl');

  assert.equal(standaloneRule.prev(), undefined, 'Unattached rule prev() must return undefined');
  assert.equal(getPreviousSibling(standaloneRule), undefined, 'Helper must return undefined for unattached rule');
}

// 3. assert Node#prev returns the previous sibling Node for declarations within a rule
{
  const css = `
    .btn {
      color: red;
      /* button spacing */
      margin-top: 4px;
      margin-bottom: 8px;
    }
  `;
  const root = postcss.parse(css);
  const rule = root.first;

  const colorDecl = rule.nodes[0];
  const commentNode = rule.nodes[1];
  const marginTopDecl = rule.nodes[2];
  const marginBottomDecl = rule.nodes[3];

  assert.equal(colorDecl.prev(), undefined, 'First child colorDecl.prev() is undefined');
  assert.equal(commentNode.prev(), colorDecl, 'commentNode.prev() must return colorDecl');
  assert.equal(marginTopDecl.prev(), commentNode, 'marginTopDecl.prev() must return commentNode');
  assert.equal(marginBottomDecl.prev(), marginTopDecl, 'marginBottomDecl.prev() must return marginTopDecl');

  assert.equal(getPreviousSibling(marginBottomDecl), marginTopDecl, 'getPreviousSibling helper returns marginTopDecl');
  assert.equal(isFirstChild(marginBottomDecl), false, 'isFirstChild is false for non-first child');

  // Test findPreviousDeclaration helper
  const foundMarginTop = findPreviousDeclaration(marginBottomDecl, 'margin-top');
  assert.equal(foundMarginTop, marginTopDecl, 'findPreviousDeclaration finds immediate preceding decl');

  const foundColor = findPreviousDeclaration(marginBottomDecl, 'color');
  assert.equal(foundColor, colorDecl, 'findPreviousDeclaration traverses past comment to find color');

  const notFound = findPreviousDeclaration(marginBottomDecl, 'padding');
  assert.equal(notFound, undefined, 'findPreviousDeclaration returns undefined for non-existent prop');
}

// 4. assert Node#prev returns the previous sibling Node for rules and at-rules in root
{
  const css = `
    @charset "UTF-8";
    @import "theme.css";
    .header { font-size: 18px; }
    .footer { font-size: 12px; }
  `;
  const root = postcss.parse(css);

  const charsetAtRule = root.nodes[0];
  const importAtRule = root.nodes[1];
  const headerRule = root.nodes[2];
  const footerRule = root.nodes[3];

  assert.equal(charsetAtRule.prev(), undefined, 'charsetAtRule.prev() must be undefined');
  assert.equal(importAtRule.prev(), charsetAtRule, 'importAtRule.prev() must be charsetAtRule');
  assert.equal(headerRule.prev(), importAtRule, 'headerRule.prev() must be importAtRule');
  assert.equal(footerRule.prev(), headerRule, 'footerRule.prev() must be headerRule');
}

// 5. assert Node#prev enables backward traversal through container children
{
  const css = `
    .list {
      item-1: 1;
      item-2: 2;
      item-3: 3;
      item-4: 4;
    }
  `;
  const root = postcss.parse(css);
  const rule = root.first;

  const item4 = rule.nodes[3];
  const preceding = collectPrecedingSiblings(item4);

  assert.equal(preceding.length, 3, 'item4 must have 3 preceding siblings');
  assert.equal(preceding[0].prop, 'item-3', 'Closest preceding sibling is item-3');
  assert.equal(preceding[1].prop, 'item-2', 'Second preceding sibling is item-2');
  assert.equal(preceding[2].prop, 'item-1', 'Third preceding sibling is item-1');

  // Manual while loop traversal
  const traversalOrder = [];
  let curr = rule.last;
  while (curr) {
    traversalOrder.push(curr.prop);
    curr = curr.prev();
  }
  assert.deepEqual(traversalOrder, ['item-4', 'item-3', 'item-2', 'item-1'], 'Backward traversal visits items in reverse order');
}

// 6. assert Node#prev reflects AST mutations when siblings are removed or inserted
{
  const css = `
    .box {
      width: 100px;
      height: 200px;
      opacity: 0.5;
    }
  `;
  const root = postcss.parse(css);
  const rule = root.first;

  const widthDecl = rule.nodes[0];
  const heightDecl = rule.nodes[1];
  const opacityDecl = rule.nodes[2];

  assert.equal(opacityDecl.prev(), heightDecl, 'Before removal, opacity prev is height');

  // Remove height declaration
  heightDecl.remove();

  assert.equal(opacityDecl.prev(), widthDecl, 'After removing height, opacity prev dynamically becomes width');
  assert.equal(heightDecl.prev(), undefined, 'Removed height node has no parent, prev() is undefined');

  // Insert a new declaration before opacity
  const zIndexDecl = postcss.decl({ prop: 'z-index', value: '10' });
  opacityDecl.before(zIndexDecl);

  assert.equal(opacityDecl.prev(), zIndexDecl, 'After inserting zIndex before opacity, opacity prev is zIndex');
  assert.equal(zIndexDecl.prev(), widthDecl, 'zIndex prev is width');
}

console.log('All Node#prev contract assertions passed successfully.');

原始种子者

匿名