@volter/twin-standard 1.0.29 → 1.0.30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/src/gate.js CHANGED
@@ -16,6 +16,7 @@ import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs';
16
16
  import { join } from 'node:path';
17
17
  import ts from 'typescript';
18
18
  import { grade } from "./grade.js";
19
+ import { isPackArtifact } from "./pack-files.js";
19
20
  /** Every unit of a pack repository: each pack (a directory with a package.json) and each lane in it (a directory with
20
21
  * its own src/manifest.ts and no package.json). */
21
22
  export function unitsOf(repo) {
@@ -50,7 +51,7 @@ export function laneRootFailures(dir) {
50
51
  const lanes = readdirSync(dir).filter((n) => existsSync(join(dir, n, 'src', 'manifest.ts')));
51
52
  if (!lanes.length)
52
53
  return ['layout: no src/manifest.ts and no lane: not a Protocol 3 pack'];
53
- const stray = readdirSync(dir).filter((n) => !n.startsWith('.') && !ROOT_ENTRIES.has(n) && !lanes.includes(n));
54
+ const stray = readdirSync(dir).filter((n) => !isPackArtifact(n) && !n.startsWith('.') && !ROOT_ENTRIES.has(n) && !lanes.includes(n));
54
55
  const skip = ignored(dir, stray);
55
56
  const outside = [
56
57
  ...stray.filter((n) => !skip.has(n)),
@@ -0,0 +1,2 @@
1
+ /** Release outputs and runtime state, relative to the pack directory being listed. */
2
+ export declare function isPackArtifact(path: string): boolean;
@@ -0,0 +1,4 @@
1
+ /** Release outputs and runtime state, relative to the pack directory being listed. */
2
+ export function isPackArtifact(path) {
3
+ return /^(dist|node_modules|\.volter)(\/|$)/.test(path) || path === 'generated/pack-facts.json';
4
+ }
@@ -21,6 +21,7 @@ import { gunzipSync } from 'node:zlib';
21
21
  import ts from 'typescript';
22
22
  import { fileURLToPath } from 'node:url';
23
23
  import { sharingLanesIn } from "./lanes.js";
24
+ import { isPackArtifact } from "./pack-files.js";
24
25
  /** The lanes over the unit's vendor's state, when the unit is one of them ("Pack layout"), else none: a lane over its
25
26
  * vendor's state takes the vendor's states, shared helpers, manifest and engine from the vendor's src/, and nothing of
26
27
  * another lane. */
@@ -56,24 +57,36 @@ function specFiles(unit) {
56
57
  const dir = join(unit.dir, 'spec');
57
58
  return filesUnder(dir).filter((f) => !SPEC_METADATA.test(f) && !SPEC_TOOL.test(f)).map((f) => join(dir, f));
58
59
  }
59
- /** Every file under a directory git does not ignore, relative to it (the checkout's tree, never runtime state). */
60
+ /** Files relative to a directory: Git's tree in a checkout, the disk tree of an unpacked package outside one. */
60
61
  function filesUnder(dir, base = dir) {
61
62
  if (!existsSync(dir))
62
63
  return [];
64
+ const checkout = spawnSync('git', ['rev-parse', '--is-inside-work-tree'], { cwd: dir, encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'] });
65
+ if (checkout.status !== 0 || checkout.error || checkout.stdout.trim() !== 'true') {
66
+ if (checkout.status !== null && checkout.status !== 0 && !checkout.error && !checkout.signal
67
+ && /^fatal: not a git repository(?:[ (:]|$)/m.test(String(checkout.stderr ?? '')))
68
+ return allFilesUnder(dir, base, true);
69
+ throw new Error(`git rev-parse failed: directory=${JSON.stringify(dir)} status=${checkout.status} signal=${JSON.stringify(checkout.signal)} error=${JSON.stringify(checkout.error?.message ?? null)} stdout=${JSON.stringify(String(checkout.stdout ?? '').trim())} stderr=${JSON.stringify(String(checkout.stderr ?? '').trim())}`);
70
+ }
63
71
  // tracked and not-yet-added files alike (T0 runs before the commit); ignored runtime state (.volter) never
64
- const run = spawnSync('git', ['ls-files', '-z', '--cached', '--others', '--exclude-standard', '--', '.'], { cwd: dir, stdio: ['ignore', 'pipe', 'ignore'] });
65
- const tracked = run.status === 0 ? [...new Set(String(run.stdout).split('\0').filter(Boolean))] : [];
72
+ const run = spawnSync('git', ['ls-files', '-z', '--cached', '--others', '--exclude-standard', '--', '.'], { cwd: dir, stdio: ['ignore', 'pipe', 'pipe'] });
73
+ if (run.status !== 0 || run.error) {
74
+ throw new Error(`git ls-files failed: directory=${JSON.stringify(dir)} status=${run.status} signal=${JSON.stringify(run.signal)} error=${JSON.stringify(run.error?.message ?? null)} stderr=${JSON.stringify(String(run.stderr ?? '').trim())}`);
75
+ }
76
+ const tracked = [...new Set(String(run.stdout).split('\0').filter(Boolean))];
66
77
  return tracked.map((f) => relative(base, join(dir, f))).filter((f) => existsSync(join(base, f)));
67
78
  }
68
- /** Every file under a directory, tracked or not (a directory the grader itself wrote). */
69
- function allFilesUnder(dir, base = dir) {
79
+ /** Disk files outside a checkout, or the complete output of the grader's own derivation. */
80
+ function allFilesUnder(dir, base = dir, excludeArtifacts = false) {
70
81
  if (!existsSync(dir))
71
82
  return [];
72
83
  const out = [];
73
84
  for (const name of readdirSync(dir)) {
74
85
  const path = join(dir, name);
86
+ if (excludeArtifacts && isPackArtifact(relative(base, path)))
87
+ continue;
75
88
  if (statSync(path).isDirectory())
76
- out.push(...allFilesUnder(path, base));
89
+ out.push(...allFilesUnder(path, base, excludeArtifacts));
77
90
  else
78
91
  out.push(relative(base, path));
79
92
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@volter/twin-standard",
3
- "version": "1.0.29",
3
+ "version": "1.0.30",
4
4
  "description": "The Protocol 3 standard for Volter twin packs: the criteria a pack is graded by, the grader, the gate a pack repository and the twin catalog run on every change and submission, and the spec derivation the grade checks against. Pin a version: every place a pack is judged judges by that standard.",
5
5
  "keywords": [
6
6
  "twin",
package/src/gate.ts CHANGED
@@ -16,6 +16,7 @@ import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs';
16
16
  import { join } from 'node:path';
17
17
  import ts from 'typescript';
18
18
  import { grade } from './grade.ts';
19
+ import { isPackArtifact } from './pack-files.ts';
19
20
 
20
21
  /** Every unit of a pack repository: each pack (a directory with a package.json) and each lane in it (a directory with
21
22
  * its own src/manifest.ts and no package.json). */
@@ -48,7 +49,7 @@ function ignored(dir: string, names: string[]): Set<string> {
48
49
  export function laneRootFailures(dir: string): string[] {
49
50
  const lanes = readdirSync(dir).filter((n) => existsSync(join(dir, n, 'src', 'manifest.ts')));
50
51
  if (!lanes.length) return ['layout: no src/manifest.ts and no lane: not a Protocol 3 pack'];
51
- const stray = readdirSync(dir).filter((n) => !n.startsWith('.') && !ROOT_ENTRIES.has(n) && !lanes.includes(n));
52
+ const stray = readdirSync(dir).filter((n) => !isPackArtifact(n) && !n.startsWith('.') && !ROOT_ENTRIES.has(n) && !lanes.includes(n));
52
53
  const skip = ignored(dir, stray);
53
54
  const outside = [
54
55
  ...stray.filter((n) => !skip.has(n)),
@@ -0,0 +1,4 @@
1
+ /** Release outputs and runtime state, relative to the pack directory being listed. */
2
+ export function isPackArtifact(path: string): boolean {
3
+ return /^(dist|node_modules|\.volter)(\/|$)/.test(path) || path === 'generated/pack-facts.json';
4
+ }
package/src/protocol-3.ts CHANGED
@@ -13,6 +13,7 @@ import { gunzipSync } from 'node:zlib';
13
13
  import ts from 'typescript';
14
14
  import { fileURLToPath } from 'node:url';
15
15
  import { sharingLanesIn } from './lanes.ts';
16
+ import { isPackArtifact } from './pack-files.ts';
16
17
  import type { Criterion, GradeUnit, Standard } from './types.ts';
17
18
 
18
19
  /** The lanes over the unit's vendor's state, when the unit is one of them ("Pack layout"), else none: a lane over its
@@ -46,21 +47,31 @@ function specFiles(unit: GradeUnit): string[] {
46
47
  return filesUnder(dir).filter((f) => !SPEC_METADATA.test(f) && !SPEC_TOOL.test(f)).map((f) => join(dir, f));
47
48
  }
48
49
 
49
- /** Every file under a directory git does not ignore, relative to it (the checkout's tree, never runtime state). */
50
+ /** Files relative to a directory: Git's tree in a checkout, the disk tree of an unpacked package outside one. */
50
51
  function filesUnder(dir: string, base = dir): string[] {
51
52
  if (!existsSync(dir)) return [];
53
+ const checkout = spawnSync('git', ['rev-parse', '--is-inside-work-tree'], { cwd: dir, encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'] });
54
+ if (checkout.status !== 0 || checkout.error || checkout.stdout.trim() !== 'true') {
55
+ if (checkout.status !== null && checkout.status !== 0 && !checkout.error && !checkout.signal
56
+ && /^fatal: not a git repository(?:[ (:]|$)/m.test(String(checkout.stderr ?? ''))) return allFilesUnder(dir, base, true);
57
+ throw new Error(`git rev-parse failed: directory=${JSON.stringify(dir)} status=${checkout.status} signal=${JSON.stringify(checkout.signal)} error=${JSON.stringify(checkout.error?.message ?? null)} stdout=${JSON.stringify(String(checkout.stdout ?? '').trim())} stderr=${JSON.stringify(String(checkout.stderr ?? '').trim())}`);
58
+ }
52
59
  // tracked and not-yet-added files alike (T0 runs before the commit); ignored runtime state (.volter) never
53
- const run = spawnSync('git', ['ls-files', '-z', '--cached', '--others', '--exclude-standard', '--', '.'], { cwd: dir, stdio: ['ignore', 'pipe', 'ignore'] });
54
- const tracked = run.status === 0 ? [...new Set(String(run.stdout).split('\0').filter(Boolean))] : [];
60
+ const run = spawnSync('git', ['ls-files', '-z', '--cached', '--others', '--exclude-standard', '--', '.'], { cwd: dir, stdio: ['ignore', 'pipe', 'pipe'] });
61
+ if (run.status !== 0 || run.error) {
62
+ throw new Error(`git ls-files failed: directory=${JSON.stringify(dir)} status=${run.status} signal=${JSON.stringify(run.signal)} error=${JSON.stringify(run.error?.message ?? null)} stderr=${JSON.stringify(String(run.stderr ?? '').trim())}`);
63
+ }
64
+ const tracked = [...new Set(String(run.stdout).split('\0').filter(Boolean))];
55
65
  return tracked.map((f) => relative(base, join(dir, f))).filter((f) => existsSync(join(base, f)));
56
66
  }
57
- /** Every file under a directory, tracked or not (a directory the grader itself wrote). */
58
- function allFilesUnder(dir: string, base = dir): string[] {
67
+ /** Disk files outside a checkout, or the complete output of the grader's own derivation. */
68
+ function allFilesUnder(dir: string, base = dir, excludeArtifacts = false): string[] {
59
69
  if (!existsSync(dir)) return [];
60
70
  const out: string[] = [];
61
71
  for (const name of readdirSync(dir)) {
62
72
  const path = join(dir, name);
63
- if (statSync(path).isDirectory()) out.push(...allFilesUnder(path, base));
73
+ if (excludeArtifacts && isPackArtifact(relative(base, path))) continue;
74
+ if (statSync(path).isDirectory()) out.push(...allFilesUnder(path, base, excludeArtifacts));
64
75
  else out.push(relative(base, path));
65
76
  }
66
77
  return out;