@aas-dev/stack 0.0.0-stage → 0.1.0

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/verify.js ADDED
@@ -0,0 +1,166 @@
1
+ import { CommandFailed } from "./errors.js";
2
+ import { diagnosticsFrom, failLines, findBin, runTool, succeeded } from "./run.js";
3
+ import { managedFiles, readTemplate } from "./templates.js";
4
+ import { Effect, FileSystem, Result, Schema } from "effect";
5
+ // src/verify.ts
6
+ const checkDrift = (cwd) => Effect.gen(function* () {
7
+ const fs = yield* FileSystem.FileSystem;
8
+ const lines = [];
9
+ for (const file of managedFiles) {
10
+ const expected = yield* readTemplate(file.template);
11
+ const target = `${cwd}/${file.path}`;
12
+ const present = yield* fs.exists(target);
13
+ const actual = present ? yield* fs.readFileString(target) : "";
14
+ if (!present || actual !== expected) lines.push(`${file.path}:1: drifted from the aas template; run aas sync`);
15
+ }
16
+ if (lines.length > 0) return yield* new CommandFailed({ lines });
17
+ });
18
+ const runChecked = (input) => Effect.gen(function* () {
19
+ const result = yield* runTool(input);
20
+ if (succeeded(result.exitCode)) return;
21
+ return yield* new CommandFailed({ lines: failLines(input.label, `${result.stdout}\n${result.stderr}`) });
22
+ });
23
+ const packTargets = (cwd) => Effect.gen(function* () {
24
+ const fs = yield* FileSystem.FileSystem;
25
+ const targets = [];
26
+ const packagesDir = `${cwd}/packages`;
27
+ if (yield* fs.exists(packagesDir)) {
28
+ const sorted = [...yield* fs.readDirectory(packagesDir)].sort();
29
+ for (const name of sorted) {
30
+ const dir = `${packagesDir}/${name}`;
31
+ if (yield* fs.exists(`${dir}/src/index.ts`)) targets.push(dir);
32
+ }
33
+ }
34
+ if (targets.length === 0 && (yield* fs.exists(`${cwd}/src/index.ts`))) targets.push(cwd);
35
+ if (targets.includes(`${cwd}/packages/cli`)) {
36
+ const rest = targets.filter((dir) => dir !== `${cwd}/packages/cli`);
37
+ return [`${cwd}/packages/cli`, ...rest];
38
+ }
39
+ return targets;
40
+ });
41
+ const verify = (cwd) => Effect.gen(function* () {
42
+ yield* checkDrift(cwd);
43
+ const fs = yield* FileSystem.FileSystem;
44
+ const vp = yield* findBin("vp");
45
+ const tsc = yield* findBin("tsc");
46
+ if (yield* fs.exists(`${cwd}/.env.schema`)) {
47
+ const varlock = yield* findBin("varlock");
48
+ yield* runChecked({
49
+ bin: varlock,
50
+ args: ["load"],
51
+ cwd,
52
+ label: "varlock"
53
+ });
54
+ }
55
+ yield* runChecked({
56
+ bin: vp,
57
+ args: [
58
+ "fmt",
59
+ "--check",
60
+ "."
61
+ ],
62
+ cwd,
63
+ label: "fmt"
64
+ });
65
+ yield* runChecked({
66
+ bin: vp,
67
+ args: [
68
+ "lint",
69
+ "--format",
70
+ "unix"
71
+ ],
72
+ cwd,
73
+ label: "lint"
74
+ });
75
+ const targets = yield* packTargets(cwd);
76
+ for (const target of targets) yield* runChecked({
77
+ bin: vp,
78
+ args: [
79
+ "pack",
80
+ "--logLevel",
81
+ "error"
82
+ ],
83
+ cwd: target,
84
+ label: "pack"
85
+ });
86
+ if (yield* fs.exists(`${cwd}/tsconfig.json`)) yield* runChecked({
87
+ bin: tsc,
88
+ args: [
89
+ "--noEmit",
90
+ "--pretty",
91
+ "false",
92
+ "-p",
93
+ "tsconfig.json"
94
+ ],
95
+ cwd,
96
+ label: "tsc"
97
+ });
98
+ const reportPath = `${cwd}/.vitest/aas-report.json`;
99
+ const tested = yield* runTool({
100
+ bin: vp,
101
+ args: [
102
+ "test",
103
+ "run",
104
+ "--reporter=json",
105
+ "--outputFile",
106
+ ".vitest/aas-report.json"
107
+ ],
108
+ cwd
109
+ });
110
+ const report = (yield* fs.exists(reportPath)) ? yield* fs.readFileString(reportPath) : "";
111
+ yield* fs.remove(reportPath).pipe(Effect.ignore);
112
+ if (!succeeded(tested.exitCode)) {
113
+ const parsed = testFailures(report === "" ? tested.stdout : report, cwd);
114
+ return yield* new CommandFailed({ lines: parsed.length > 0 ? parsed : failLines("test", `${tested.stdout}\n${tested.stderr}`) });
115
+ }
116
+ });
117
+ const Assertion = Schema.Struct({
118
+ status: Schema.String,
119
+ title: Schema.optionalKey(Schema.String),
120
+ failureMessages: Schema.optionalKey(Schema.Array(Schema.String))
121
+ });
122
+ const TestFile = Schema.Struct({
123
+ name: Schema.optionalKey(Schema.String),
124
+ status: Schema.optionalKey(Schema.String),
125
+ message: Schema.optionalKey(Schema.String),
126
+ assertionResults: Schema.optionalKey(Schema.Array(Assertion))
127
+ });
128
+ const Report = Schema.Struct({ testResults: Schema.optionalKey(Schema.Array(TestFile)) });
129
+ const decodeReport = (text) => Schema.decodeResult(Schema.fromJsonString(Report))(text);
130
+ const failureLine = /([A-Za-z0-9_./-]+\.ts):(\d+):\d+/u;
131
+ const relativeTo = (file, cwd) => {
132
+ const prefix = `${cwd}/`;
133
+ return file.startsWith(prefix) ? file.slice(prefix.length) : file;
134
+ };
135
+ const firstLine = (text) => text.split("\n")[0] ?? "failed";
136
+ const testFailures = (text, cwd) => {
137
+ const start = text.indexOf("{");
138
+ const end = text.lastIndexOf("}");
139
+ if (start < 0 || end <= start) return diagnosticsFrom(text);
140
+ const decoded = decodeReport(text.slice(start, end + 1));
141
+ if (Result.isFailure(decoded)) return diagnosticsFrom(text);
142
+ const results = decoded.success.testResults;
143
+ if (results === void 0) return diagnosticsFrom(text);
144
+ const lines = [];
145
+ for (const result of results) {
146
+ const assertions = result.assertionResults ?? [];
147
+ let failedAssertions = 0;
148
+ for (const assertion of assertions) {
149
+ if (assertion.status !== "failed") continue;
150
+ failedAssertions += 1;
151
+ const message = assertion.failureMessages?.[0];
152
+ const located = message === void 0 ? null : failureLine.exec(message);
153
+ const locatedFile = located?.[1];
154
+ const file = relativeTo(locatedFile ?? result.name ?? "test", cwd);
155
+ const line = located?.[2] ?? "1";
156
+ const reason = message === void 0 ? assertion.title ?? "failed" : firstLine(message);
157
+ lines.push(`${file}:${line}: ${reason}`);
158
+ }
159
+ if (failedAssertions === 0 && result.status === "failed") {
160
+ const file = relativeTo(result.name ?? "test", cwd);
161
+ lines.push(`${file}:1: ${firstLine(result.message ?? "failed")}`);
162
+ }
163
+ }
164
+ return lines;
165
+ };
166
+ export { verify };
package/package.json CHANGED
@@ -1,6 +1,57 @@
1
1
  {
2
2
  "name": "@aas-dev/stack",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "0.1.0",
4
+ "description": "The aas command. One installable toolchain: Vite+, Effect tsgo, and the fence.",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://origin.cursor.com/git/kristoffer-aas/aas-stack.git",
9
+ "directory": "packages/cli"
10
+ },
11
+ "bin": {
12
+ "aas": "./bin/aas.js"
13
+ },
14
+ "files": [
15
+ "bin",
16
+ "dist",
17
+ "plugin",
18
+ "templates",
19
+ "tsconfig.base.json"
20
+ ],
21
+ "type": "module",
22
+ "exports": {
23
+ ".": {
24
+ "types": "./dist/index.d.ts",
25
+ "import": "./dist/index.js"
26
+ },
27
+ "./config": {
28
+ "types": "./dist/config.d.ts",
29
+ "import": "./dist/config.js"
30
+ },
31
+ "./tsconfig.base.json": "./tsconfig.base.json"
32
+ },
33
+ "publishConfig": {
34
+ "access": "public"
35
+ },
36
+ "dependencies": {
37
+ "@effect/platform-node": "4.0.6",
38
+ "@effect/tsgo": "0.56.0",
39
+ "effect": "4.0.6",
40
+ "typescript": "7.0.2",
41
+ "varlock": "1.23.0",
42
+ "vite-plus": "1.4.0"
43
+ },
44
+ "devDependencies": {
45
+ "@effect/vitest": "4.0.6",
46
+ "@types/node": "22.20.5"
47
+ },
48
+ "engines": {
49
+ "node": ">=22.18.0",
50
+ "pnpm": "11.3.0"
51
+ },
52
+ "scripts": {
53
+ "typecheck": "tsc --noEmit --pretty false -p tsconfig.json",
54
+ "test": "vp test run",
55
+ "build": "vp pack --logLevel error"
56
+ }
6
57
  }
@@ -0,0 +1,8 @@
1
+ export declare const ruleNames: ReadonlyArray<string>
2
+
3
+ declare const plugin: {
4
+ readonly meta: { readonly name: string }
5
+ readonly rules: Readonly<Record<string, object>>
6
+ }
7
+
8
+ export default plugin