openuispec 0.1.27 → 0.1.29
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/README.md +52 -55
- package/cli/configure-target.ts +416 -0
- package/cli/index.ts +14 -3
- package/cli/init.ts +241 -55
- package/cli/target-presets.json +746 -0
- package/docs/implementation-notes.md +47 -10
- package/docs/release-notes-v0.1.26.md +1 -1
- package/docs/release-notes-v0.1.28.md +25 -0
- package/docs/stress-test-maturity-report.md +1 -1
- package/drift/index.ts +31 -11
- package/examples/taskflow/AGENTS.md +113 -0
- package/examples/taskflow/CLAUDE.md +113 -0
- package/examples/taskflow/backend/.gitkeep +1 -0
- package/examples/taskflow/generated/android/TaskFlow/README.md +43 -0
- package/examples/taskflow/generated/android/TaskFlow/app/build.gradle.kts +76 -0
- package/examples/taskflow/generated/android/TaskFlow/app/proguard-rules.pro +1 -0
- package/examples/taskflow/generated/android/TaskFlow/app/src/main/AndroidManifest.xml +21 -0
- package/examples/taskflow/generated/android/TaskFlow/app/src/main/java/uz/rsteam/taskflow/MainActivity.kt +19 -0
- package/examples/taskflow/generated/android/TaskFlow/app/src/main/java/uz/rsteam/taskflow/TaskFlowApp.kt +283 -0
- package/examples/taskflow/generated/android/TaskFlow/app/src/main/java/uz/rsteam/taskflow/model/DomainModels.kt +106 -0
- package/examples/taskflow/generated/android/TaskFlow/app/src/main/java/uz/rsteam/taskflow/model/SampleData.kt +57 -0
- package/examples/taskflow/generated/android/TaskFlow/app/src/main/java/uz/rsteam/taskflow/ui/components/Common.kt +109 -0
- package/examples/taskflow/generated/android/TaskFlow/app/src/main/java/uz/rsteam/taskflow/ui/screens/HomeScreen.kt +112 -0
- package/examples/taskflow/generated/android/TaskFlow/app/src/main/java/uz/rsteam/taskflow/ui/screens/ProjectsScreen.kt +61 -0
- package/examples/taskflow/generated/android/TaskFlow/app/src/main/java/uz/rsteam/taskflow/ui/screens/SettingsScreen.kt +82 -0
- package/examples/taskflow/generated/android/TaskFlow/app/src/main/java/uz/rsteam/taskflow/ui/screens/TaskDetailScreen.kt +111 -0
- package/examples/taskflow/generated/android/TaskFlow/app/src/main/java/uz/rsteam/taskflow/ui/sheets/Sheets.kt +77 -0
- package/examples/taskflow/generated/android/TaskFlow/app/src/main/java/uz/rsteam/taskflow/ui/theme/Color.kt +30 -0
- package/examples/taskflow/generated/android/TaskFlow/app/src/main/java/uz/rsteam/taskflow/ui/theme/Theme.kt +86 -0
- package/examples/taskflow/generated/android/TaskFlow/app/src/main/java/uz/rsteam/taskflow/ui/theme/Type.kt +57 -0
- package/examples/taskflow/generated/android/TaskFlow/app/src/main/res/values/strings.xml +155 -0
- package/examples/taskflow/generated/android/TaskFlow/app/src/main/res/values/themes.xml +4 -0
- package/examples/taskflow/generated/android/TaskFlow/build.gradle.kts +5 -0
- package/examples/taskflow/generated/android/TaskFlow/gradle/gradle-daemon-jvm.properties +12 -0
- package/examples/taskflow/generated/android/TaskFlow/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/examples/taskflow/generated/android/TaskFlow/gradle/wrapper/gradle-wrapper.properties +7 -0
- package/examples/taskflow/generated/android/TaskFlow/gradle.properties +4 -0
- package/examples/taskflow/generated/android/TaskFlow/gradlew +18 -0
- package/examples/taskflow/generated/android/TaskFlow/gradlew.bat +12 -0
- package/examples/taskflow/generated/android/TaskFlow/settings.gradle.kts +18 -0
- package/examples/taskflow/generated/ios/TaskFlow/README.md +21 -0
- package/examples/taskflow/generated/ios/TaskFlow/Resources/en.lproj/Localizable.strings +115 -0
- package/examples/taskflow/generated/ios/TaskFlow/Sources/TaskFlow/App/TaskFlowApp.swift +24 -0
- package/examples/taskflow/generated/ios/TaskFlow/Sources/TaskFlow/Components/AppChrome.swift +150 -0
- package/examples/taskflow/generated/ios/TaskFlow/Sources/TaskFlow/Flows/TaskEditorSheet.swift +220 -0
- package/examples/taskflow/generated/ios/TaskFlow/Sources/TaskFlow/Models/DomainModels.swift +122 -0
- package/examples/taskflow/generated/ios/TaskFlow/Sources/TaskFlow/Screens/CalendarView.swift +21 -0
- package/examples/taskflow/generated/ios/TaskFlow/Sources/TaskFlow/Screens/HomeView.swift +201 -0
- package/examples/taskflow/generated/ios/TaskFlow/Sources/TaskFlow/Screens/ProfileEditView.swift +48 -0
- package/examples/taskflow/generated/ios/TaskFlow/Sources/TaskFlow/Screens/ProjectDetailView.swift +59 -0
- package/examples/taskflow/generated/ios/TaskFlow/Sources/TaskFlow/Screens/ProjectsView.swift +63 -0
- package/examples/taskflow/generated/ios/TaskFlow/Sources/TaskFlow/Screens/SettingsView.swift +85 -0
- package/examples/taskflow/generated/ios/TaskFlow/Sources/TaskFlow/Screens/TaskDetailView.swift +219 -0
- package/examples/taskflow/generated/ios/TaskFlow/Sources/TaskFlow/Support/AppModel.swift +320 -0
- package/examples/taskflow/generated/ios/TaskFlow/Sources/TaskFlow/Support/AppSupport.swift +41 -0
- package/examples/taskflow/generated/ios/TaskFlow/project.yml +26 -0
- package/examples/taskflow/generated/web/TaskFlow/README.md +19 -0
- package/examples/taskflow/generated/web/TaskFlow/index.html +12 -0
- package/examples/taskflow/generated/web/TaskFlow/package-lock.json +1908 -0
- package/examples/taskflow/generated/web/TaskFlow/package.json +24 -0
- package/examples/taskflow/generated/web/TaskFlow/src/App.tsx +58 -0
- package/examples/taskflow/generated/web/TaskFlow/src/AppShell.tsx +55 -0
- package/examples/taskflow/generated/web/TaskFlow/src/components/Common.tsx +82 -0
- package/examples/taskflow/generated/web/TaskFlow/src/components/Modals.tsx +191 -0
- package/examples/taskflow/generated/web/TaskFlow/src/components/Nav.tsx +41 -0
- package/examples/taskflow/generated/web/TaskFlow/src/generated/messages.ts +131 -0
- package/examples/taskflow/generated/web/TaskFlow/src/hooks.ts +25 -0
- package/examples/taskflow/generated/web/TaskFlow/src/i18n.ts +39 -0
- package/examples/taskflow/generated/web/TaskFlow/src/locales.en.json +111 -0
- package/examples/taskflow/generated/web/TaskFlow/src/main.tsx +13 -0
- package/examples/taskflow/generated/web/TaskFlow/src/screens/HomeScreen.tsx +111 -0
- package/examples/taskflow/generated/web/TaskFlow/src/screens/ProjectsScreen.tsx +82 -0
- package/examples/taskflow/generated/web/TaskFlow/src/screens/SettingsScreens.tsx +132 -0
- package/examples/taskflow/generated/web/TaskFlow/src/screens/TaskDetail.tsx +105 -0
- package/examples/taskflow/generated/web/TaskFlow/src/store.ts +216 -0
- package/examples/taskflow/generated/web/TaskFlow/src/styles.css +617 -0
- package/examples/taskflow/generated/web/TaskFlow/src/types.ts +64 -0
- package/examples/taskflow/generated/web/TaskFlow/src/utils.ts +78 -0
- package/examples/taskflow/generated/web/TaskFlow/tsconfig.json +21 -0
- package/examples/taskflow/generated/web/TaskFlow/vite.config.ts +6 -0
- package/examples/taskflow/openuispec/README.md +54 -0
- package/examples/taskflow/{openuispec.yaml → openuispec/openuispec.yaml} +2 -0
- package/examples/todo-orbit/AGENTS.md +48 -22
- package/examples/todo-orbit/CLAUDE.md +48 -22
- package/examples/todo-orbit/backend/.gitkeep +1 -0
- package/examples/todo-orbit/openuispec/README.md +9 -4
- package/examples/todo-orbit/openuispec/openuispec.yaml +2 -0
- package/package.json +1 -1
- package/prepare/index.ts +811 -25
- package/schema/openuispec.schema.json +10 -0
- package/schema/semantic-lint.ts +36 -12
- package/schema/validate.ts +9 -4
- package/status/index.ts +16 -3
- /package/examples/taskflow/{contracts → openuispec/contracts}/README.md +0 -0
- /package/examples/taskflow/{contracts → openuispec/contracts}/action_trigger.yaml +0 -0
- /package/examples/taskflow/{contracts → openuispec/contracts}/collection.yaml +0 -0
- /package/examples/taskflow/{contracts → openuispec/contracts}/data_display.yaml +0 -0
- /package/examples/taskflow/{contracts → openuispec/contracts}/feedback.yaml +0 -0
- /package/examples/taskflow/{contracts → openuispec/contracts}/input_field.yaml +0 -0
- /package/examples/taskflow/{contracts → openuispec/contracts}/nav_container.yaml +0 -0
- /package/examples/taskflow/{contracts → openuispec/contracts}/surface.yaml +0 -0
- /package/examples/taskflow/{contracts → openuispec/contracts}/x_media_player.yaml +0 -0
- /package/examples/taskflow/{flows → openuispec/flows}/create_task.yaml +0 -0
- /package/examples/taskflow/{flows → openuispec/flows}/edit_task.yaml +0 -0
- /package/examples/taskflow/{locales → openuispec/locales}/en.json +0 -0
- /package/examples/taskflow/{platform → openuispec/platform}/android.yaml +0 -0
- /package/examples/taskflow/{platform → openuispec/platform}/ios.yaml +0 -0
- /package/examples/taskflow/{platform → openuispec/platform}/web.yaml +0 -0
- /package/examples/taskflow/{screens → openuispec/screens}/calendar.yaml +0 -0
- /package/examples/taskflow/{screens → openuispec/screens}/home.yaml +0 -0
- /package/examples/taskflow/{screens → openuispec/screens}/profile_edit.yaml +0 -0
- /package/examples/taskflow/{screens → openuispec/screens}/project_detail.yaml +0 -0
- /package/examples/taskflow/{screens → openuispec/screens}/projects.yaml +0 -0
- /package/examples/taskflow/{screens → openuispec/screens}/settings.yaml +0 -0
- /package/examples/taskflow/{screens → openuispec/screens}/task_detail.yaml +0 -0
- /package/examples/taskflow/{tokens → openuispec/tokens}/color.yaml +0 -0
- /package/examples/taskflow/{tokens → openuispec/tokens}/elevation.yaml +0 -0
- /package/examples/taskflow/{tokens → openuispec/tokens}/icons.yaml +0 -0
- /package/examples/taskflow/{tokens → openuispec/tokens}/layout.yaml +0 -0
- /package/examples/taskflow/{tokens → openuispec/tokens}/motion.yaml +0 -0
- /package/examples/taskflow/{tokens → openuispec/tokens}/spacing.yaml +0 -0
- /package/examples/taskflow/{tokens → openuispec/tokens}/themes.yaml +0 -0
- /package/examples/taskflow/{tokens → openuispec/tokens}/typography.yaml +0 -0
|
@@ -111,6 +111,16 @@
|
|
|
111
111
|
"type": "string"
|
|
112
112
|
}
|
|
113
113
|
},
|
|
114
|
+
"code_roots": {
|
|
115
|
+
"type": "object",
|
|
116
|
+
"description": "Additional project code roots used as generation context.",
|
|
117
|
+
"properties": {
|
|
118
|
+
"backend": {
|
|
119
|
+
"type": "string"
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
"additionalProperties": false
|
|
123
|
+
},
|
|
114
124
|
"output_format": {
|
|
115
125
|
"type": "object",
|
|
116
126
|
"description": "Per-target generation config",
|
package/schema/semantic-lint.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { existsSync, readFileSync
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
2
|
import { basename, join, resolve } from "node:path";
|
|
3
3
|
import YAML from "yaml";
|
|
4
|
+
import { listFiles } from "../drift/index.js";
|
|
4
5
|
|
|
5
6
|
type UnknownRecord = Record<string, unknown>;
|
|
6
7
|
|
|
@@ -19,6 +20,7 @@ export interface UsageLint {
|
|
|
19
20
|
}
|
|
20
21
|
|
|
21
22
|
interface SemanticContext {
|
|
23
|
+
manifest: unknown;
|
|
22
24
|
localeFiles: Map<string, Set<string>>;
|
|
23
25
|
formatterNames: Set<string>;
|
|
24
26
|
mapperNames: Set<string>;
|
|
@@ -66,17 +68,6 @@ function loadData(filePath: string): unknown {
|
|
|
66
68
|
return filePath.endsWith(".json") ? loadJson(filePath) : loadYaml(filePath);
|
|
67
69
|
}
|
|
68
70
|
|
|
69
|
-
function listFiles(dir: string, ext: string): string[] {
|
|
70
|
-
try {
|
|
71
|
-
return readdirSync(dir)
|
|
72
|
-
.filter((file) => file.endsWith(ext))
|
|
73
|
-
.sort()
|
|
74
|
-
.map((file) => join(dir, file));
|
|
75
|
-
} catch {
|
|
76
|
-
return [];
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
71
|
function isRecord(value: unknown): value is UnknownRecord {
|
|
81
72
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
82
73
|
}
|
|
@@ -281,6 +272,7 @@ function buildContext(projectDir: string, includes: Includes): SemanticContext {
|
|
|
281
272
|
: localeFiles.keys().next().value ?? null;
|
|
282
273
|
|
|
283
274
|
return {
|
|
275
|
+
manifest,
|
|
284
276
|
localeFiles,
|
|
285
277
|
formatterNames,
|
|
286
278
|
mapperNames,
|
|
@@ -552,6 +544,37 @@ function lintLocaleCoverage(context: SemanticContext): UsageLint[] {
|
|
|
552
544
|
return errors;
|
|
553
545
|
}
|
|
554
546
|
|
|
547
|
+
function lintManifestGenerationContext(projectDir: string, manifest: unknown): UsageLint[] {
|
|
548
|
+
if (!isRecord(manifest)) return [];
|
|
549
|
+
|
|
550
|
+
const hasApiEndpoints =
|
|
551
|
+
isRecord(manifest.api) &&
|
|
552
|
+
isRecord(manifest.api.endpoints) &&
|
|
553
|
+
Object.keys(manifest.api.endpoints).length > 0;
|
|
554
|
+
if (!hasApiEndpoints) return [];
|
|
555
|
+
|
|
556
|
+
const generation = isRecord(manifest.generation) ? manifest.generation : {};
|
|
557
|
+
const codeRoots = isRecord(generation.code_roots) ? generation.code_roots : null;
|
|
558
|
+
const backendRoot = codeRoots && typeof codeRoots.backend === "string" ? codeRoots.backend.trim() : "";
|
|
559
|
+
|
|
560
|
+
if (!backendRoot) {
|
|
561
|
+
return [{
|
|
562
|
+
path: "openuispec.yaml",
|
|
563
|
+
message: 'api endpoints require generation.code_roots.backend to point at the backend folder',
|
|
564
|
+
}];
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
const resolvedBackendRoot = resolve(projectDir, backendRoot);
|
|
568
|
+
if (!existsSync(resolvedBackendRoot)) {
|
|
569
|
+
return [{
|
|
570
|
+
path: "openuispec.yaml",
|
|
571
|
+
message: `generation.code_roots.backend points to a missing folder: ${backendRoot}`,
|
|
572
|
+
}];
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
return [];
|
|
576
|
+
}
|
|
577
|
+
|
|
555
578
|
function printSemanticErrors(label: string, errors: UsageLint[]): number {
|
|
556
579
|
if (errors.length === 0) return 0;
|
|
557
580
|
const previewLimit = 10;
|
|
@@ -572,6 +595,7 @@ export function runSemanticLint(projectDir: string, includes: Includes): number
|
|
|
572
595
|
const contractsDir = resolve(projectDir, includes.contracts);
|
|
573
596
|
|
|
574
597
|
total += printSemanticErrors("locales", lintLocaleCoverage(context));
|
|
598
|
+
total += printSemanticErrors("openuispec.yaml", lintManifestGenerationContext(projectDir, context.manifest));
|
|
575
599
|
|
|
576
600
|
const files = [
|
|
577
601
|
join(projectDir, "openuispec.yaml"),
|
package/schema/validate.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Usage:
|
|
6
6
|
* openuispec validate # validate all spec files
|
|
7
7
|
* openuispec validate tokens screens # validate specific groups
|
|
8
|
-
* npm run validate # from repo (uses examples/taskflow)
|
|
8
|
+
* npm run validate # from repo (uses examples/taskflow/openuispec)
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
import { readFileSync, readdirSync, existsSync } from "node:fs";
|
|
@@ -572,9 +572,14 @@ function findProjectDir(cwd: string): string {
|
|
|
572
572
|
}
|
|
573
573
|
}
|
|
574
574
|
// Fallback for running from repo root with examples/
|
|
575
|
-
const
|
|
576
|
-
|
|
577
|
-
|
|
575
|
+
const exampleCandidates = [
|
|
576
|
+
join(cwd, "examples", "taskflow", "openuispec"),
|
|
577
|
+
join(cwd, "examples", "taskflow"),
|
|
578
|
+
];
|
|
579
|
+
for (const dir of exampleCandidates) {
|
|
580
|
+
if (existsSync(join(dir, "openuispec.yaml"))) {
|
|
581
|
+
return dir;
|
|
582
|
+
}
|
|
578
583
|
}
|
|
579
584
|
console.error(
|
|
580
585
|
"Error: No openuispec.yaml found.\n" +
|
package/status/index.ts
CHANGED
|
@@ -26,6 +26,7 @@ import { readFileSync } from "node:fs";
|
|
|
26
26
|
interface TargetStatus {
|
|
27
27
|
target: string;
|
|
28
28
|
output_dir: string;
|
|
29
|
+
output_exists: boolean;
|
|
29
30
|
snapshot: boolean;
|
|
30
31
|
snapshot_at: string | null;
|
|
31
32
|
baseline: {
|
|
@@ -74,12 +75,14 @@ function readState(statePath: string): StateFile {
|
|
|
74
75
|
|
|
75
76
|
function buildTargetStatus(cwd: string, projectDir: string, projectName: string, target: string): TargetStatus {
|
|
76
77
|
const outputDir = resolveOutputDir(projectDir, projectName, target);
|
|
78
|
+
const outputExists = existsSync(outputDir);
|
|
77
79
|
const path = stateFilePath(projectDir, projectName, target);
|
|
78
80
|
|
|
79
81
|
if (!existsSync(path)) {
|
|
80
82
|
return {
|
|
81
83
|
target,
|
|
82
84
|
output_dir: outputDir,
|
|
85
|
+
output_exists: outputExists,
|
|
83
86
|
snapshot: false,
|
|
84
87
|
snapshot_at: null,
|
|
85
88
|
baseline: {
|
|
@@ -93,7 +96,9 @@ function buildTargetStatus(cwd: string, projectDir: string, projectName: string,
|
|
|
93
96
|
removed: 0,
|
|
94
97
|
behind: false,
|
|
95
98
|
explain_available: false,
|
|
96
|
-
note:
|
|
99
|
+
note: outputExists
|
|
100
|
+
? "No snapshot found for this target."
|
|
101
|
+
: `Output directory not found. Run code generation for "${target}" first.`,
|
|
97
102
|
};
|
|
98
103
|
}
|
|
99
104
|
|
|
@@ -107,6 +112,7 @@ function buildTargetStatus(cwd: string, projectDir: string, projectName: string,
|
|
|
107
112
|
return {
|
|
108
113
|
target,
|
|
109
114
|
output_dir: outputDir,
|
|
115
|
+
output_exists: outputExists,
|
|
110
116
|
snapshot: true,
|
|
111
117
|
snapshot_at: state.snapshot_at,
|
|
112
118
|
baseline: {
|
|
@@ -147,11 +153,18 @@ function printReport(result: StatusResult): void {
|
|
|
147
153
|
for (const target of result.targets) {
|
|
148
154
|
const summary = target.snapshot
|
|
149
155
|
? `${target.changed} changed, ${target.added} added, ${target.removed} removed`
|
|
150
|
-
:
|
|
151
|
-
|
|
156
|
+
: target.output_exists
|
|
157
|
+
? "no snapshot"
|
|
158
|
+
: "output missing";
|
|
159
|
+
const status = target.snapshot
|
|
160
|
+
? (target.behind ? "behind" : "up to date")
|
|
161
|
+
: target.output_exists
|
|
162
|
+
? "needs baseline"
|
|
163
|
+
: "needs generation";
|
|
152
164
|
|
|
153
165
|
console.log(`${target.target}`);
|
|
154
166
|
console.log(` output: ${target.output_dir}`);
|
|
167
|
+
console.log(` output exists: ${target.output_exists ? "yes" : "no"}`);
|
|
155
168
|
console.log(` snapshot: ${target.snapshot ? target.snapshot_at : "missing"}`);
|
|
156
169
|
if (target.baseline.label) {
|
|
157
170
|
console.log(` baseline: ${target.baseline.label}`);
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|