@sequenceholdings/artifact-studio 0.2.1 → 0.2.3
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/VERSION-PIN.md +12 -9
- package/dist/active-deploy-policy.d.ts +4 -4
- package/dist/active-deploy-policy.js +9 -6
- package/dist/atlas-ui-css-plugin.d.ts +29 -8
- package/dist/atlas-ui-css-plugin.js +52 -20
- package/dist/build-provenance.d.ts +50 -0
- package/dist/build-provenance.js +44 -0
- package/dist/build-subprocess.d.ts +3 -1
- package/dist/build-subprocess.js +5 -2
- package/dist/build-worker.js +4 -2
- package/dist/build.d.ts +15 -13
- package/dist/build.js +89 -30
- package/dist/cli.js +42 -14
- package/dist/dev-link.d.ts +10 -6
- package/dist/dev-link.js +42 -8
- package/dist/manifest.d.ts +1 -1
- package/dist/reporting-limits.d.ts +17 -0
- package/dist/reporting-limits.js +17 -0
- package/dist/sdk.d.ts +2 -2
- package/dist/source-boundary.d.ts +13 -0
- package/dist/source-boundary.js +54 -0
- package/dist/source-resolver.js +6 -1
- package/dist/templates/react-vite/AGENTS.md +1 -1
- package/dist/templates/react-vite/package.json +3 -3
- package/dist/templates/react-vite/src/styles.css +0 -2
- package/dist/token-contract.d.ts +16 -0
- package/dist/token-contract.js +245 -0
- package/package.json +10 -6
- package/templates/react-vite/AGENTS.md +1 -1
- package/templates/react-vite/package.json +3 -3
- package/templates/react-vite/src/styles.css +0 -2
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
import ts from 'typescript';
|
|
2
|
+
const RETIRED_OPACITY_UTILITY = /(?:^|\s)((?:[^\s"'`]+:)*(?:bg|text|border(?:-[trblxy])?|ring(?:-offset)?|fill|stroke|outline|divide(?:-[xy])?|decoration|accent|caret|shadow)-(?:black|white)-\d+(?:\/[^\s"'`]+)?!?)(?=$|\s)/g;
|
|
3
|
+
const DEPRECATED_TOKEN_IMPORT = /@import\s+(?:url\(\s*)?(?:["'][^"']*@sequenceholdings\/atlas-ui\/|[^"'()\s;]*@sequenceholdings\/atlas-ui\/)(tokens\.v2\.css|theme\.v2\.css)(?:["'])?\s*\)?[^;\n]*;/gi;
|
|
4
|
+
export function collectDeprecatedTokenImportDiagnostics({ files, }) {
|
|
5
|
+
const diagnostics = [];
|
|
6
|
+
for (const file of files) {
|
|
7
|
+
if (!file.path.endsWith('.css'))
|
|
8
|
+
continue;
|
|
9
|
+
const deprecatedImports = new Set([...file.content.matchAll(DEPRECATED_TOKEN_IMPORT)].map((match) => match[1].toLowerCase()));
|
|
10
|
+
if (deprecatedImports.size === 0)
|
|
11
|
+
continue;
|
|
12
|
+
diagnostics.push(`${file.path} imports deprecated ${[...deprecatedImports].join(', ')}; ` +
|
|
13
|
+
'the compiler normalized it to @sequenceholdings/atlas-ui/tokens.css. Update the source import.');
|
|
14
|
+
}
|
|
15
|
+
return diagnostics;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Candidate builds use a source report rather than a build-time ban. A normal
|
|
19
|
+
* CLI release must remain able to rebuild pre-cutover artifacts; an explicit
|
|
20
|
+
* `artifact dev --link <atlas-ui>` preview is the opt-in migration surface.
|
|
21
|
+
*/
|
|
22
|
+
export function collectCandidateTokenCompatibilityDiagnostics({ files, }) {
|
|
23
|
+
const references = [];
|
|
24
|
+
const uncertainFiles = new Set();
|
|
25
|
+
for (const file of files) {
|
|
26
|
+
const analysis = classBearingUtilities({ file });
|
|
27
|
+
for (const utility of analysis.utilities)
|
|
28
|
+
references.push({ path: file.path, utility });
|
|
29
|
+
if (analysis.uncertain)
|
|
30
|
+
uncertainFiles.add(file.path);
|
|
31
|
+
}
|
|
32
|
+
if (references.length === 0 && uncertainFiles.size === 0)
|
|
33
|
+
return [];
|
|
34
|
+
const diagnostics = [
|
|
35
|
+
'Artifact candidate compatibility report (DES-437): canonical tokens omit numbered black/white opacity utilities.',
|
|
36
|
+
];
|
|
37
|
+
for (const { path, utility } of references) {
|
|
38
|
+
diagnostics.push(`${path}: ${utility} is unavailable in canonical tokens; replace it with the semantic role for the element's purpose.`);
|
|
39
|
+
}
|
|
40
|
+
for (const path of uncertainFiles) {
|
|
41
|
+
diagnostics.push(`${path}: dynamic class construction could not be proven compatible; inspect it for numbered black/white opacity utilities before cutover.`);
|
|
42
|
+
}
|
|
43
|
+
return diagnostics;
|
|
44
|
+
}
|
|
45
|
+
function classBearingUtilities({ file }) {
|
|
46
|
+
if (file.path.endsWith('.css'))
|
|
47
|
+
return utilitiesInCss({ content: file.content });
|
|
48
|
+
if (file.path.endsWith('.html'))
|
|
49
|
+
return utilitiesInHtml({ content: file.content });
|
|
50
|
+
if (/\.[jt]sx?$/.test(file.path))
|
|
51
|
+
return utilitiesInScript({ content: file.content, path: file.path });
|
|
52
|
+
return { utilities: [], uncertain: false };
|
|
53
|
+
}
|
|
54
|
+
function utilitiesInCss({ content }) {
|
|
55
|
+
const utilities = [];
|
|
56
|
+
const withoutComments = content.replace(/\/\*[\s\S]*?\*\//g, '');
|
|
57
|
+
for (const apply of withoutComments.matchAll(/@apply\s+([^;]+);/g)) {
|
|
58
|
+
utilities.push(...retiredUtilitiesInClassText({ content: apply[1] }));
|
|
59
|
+
}
|
|
60
|
+
return { utilities, uncertain: false };
|
|
61
|
+
}
|
|
62
|
+
function utilitiesInHtml({ content }) {
|
|
63
|
+
const utilities = [];
|
|
64
|
+
for (const attribute of content.matchAll(/\bclass\s*=\s*(["'])([\s\S]*?)\1/gi)) {
|
|
65
|
+
utilities.push(...retiredUtilitiesInClassText({ content: attribute[2] }));
|
|
66
|
+
}
|
|
67
|
+
return { utilities, uncertain: false };
|
|
68
|
+
}
|
|
69
|
+
function utilitiesInScript({ content, path }) {
|
|
70
|
+
const scriptKind = path.endsWith('.tsx')
|
|
71
|
+
? ts.ScriptKind.TSX
|
|
72
|
+
: path.endsWith('.jsx')
|
|
73
|
+
? ts.ScriptKind.JSX
|
|
74
|
+
: ts.ScriptKind.TS;
|
|
75
|
+
const source = ts.createSourceFile(path, content, ts.ScriptTarget.Latest, true, scriptKind);
|
|
76
|
+
const bindings = new Map();
|
|
77
|
+
const functions = new Map();
|
|
78
|
+
const duplicateBindingNames = new Set();
|
|
79
|
+
const duplicateFunctionNames = new Set();
|
|
80
|
+
const utilities = [];
|
|
81
|
+
let uncertain = false;
|
|
82
|
+
const collectBindings = (node) => {
|
|
83
|
+
if (ts.isVariableDeclaration(node) && ts.isIdentifier(node.name) && node.initializer) {
|
|
84
|
+
if (bindings.has(node.name.text)) {
|
|
85
|
+
duplicateBindingNames.add(node.name.text);
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
bindings.set(node.name.text, node.initializer);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
if (ts.isFunctionDeclaration(node) && node.name) {
|
|
92
|
+
if (functions.has(node.name.text)) {
|
|
93
|
+
duplicateFunctionNames.add(node.name.text);
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
functions.set(node.name.text, node);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
ts.forEachChild(node, collectBindings);
|
|
100
|
+
};
|
|
101
|
+
collectBindings(source);
|
|
102
|
+
const ambiguousNames = new Set([
|
|
103
|
+
...duplicateBindingNames,
|
|
104
|
+
...duplicateFunctionNames,
|
|
105
|
+
...[...bindings.keys()].filter((name) => functions.has(name)),
|
|
106
|
+
]);
|
|
107
|
+
const collectExpression = (node, seen = new Set()) => {
|
|
108
|
+
if (seen.has(node))
|
|
109
|
+
return;
|
|
110
|
+
seen.add(node);
|
|
111
|
+
if (ts.isStringLiteral(node) || ts.isNoSubstitutionTemplateLiteral(node)) {
|
|
112
|
+
utilities.push(...retiredUtilitiesInClassText({ content: node.text }));
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
if (ts.isTemplateExpression(node)) {
|
|
116
|
+
utilities.push(...retiredUtilitiesInClassText({ content: node.head.text }));
|
|
117
|
+
for (const span of node.templateSpans) {
|
|
118
|
+
collectExpression(span.expression, seen);
|
|
119
|
+
utilities.push(...retiredUtilitiesInClassText({ content: span.literal.text }));
|
|
120
|
+
}
|
|
121
|
+
uncertain = true;
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
if (ts.isJsxExpression(node)) {
|
|
125
|
+
if (node.expression)
|
|
126
|
+
collectExpression(node.expression, seen);
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
if (ts.isParenthesizedExpression(node) || ts.isAsExpression(node) || ts.isTypeAssertionExpression(node)) {
|
|
130
|
+
collectExpression(node.expression, seen);
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
if (ts.isBinaryExpression(node) && node.operatorToken.kind === ts.SyntaxKind.PlusToken) {
|
|
134
|
+
collectExpression(node.left, seen);
|
|
135
|
+
collectExpression(node.right, seen);
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
if (ts.isConditionalExpression(node)) {
|
|
139
|
+
collectExpression(node.whenTrue, seen);
|
|
140
|
+
collectExpression(node.whenFalse, seen);
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
if (ts.isIdentifier(node)) {
|
|
144
|
+
// This lightweight preview analyzer does not construct lexical scopes.
|
|
145
|
+
// Never pick one same-named binding arbitrarily: a later declaration in
|
|
146
|
+
// another scope could mask a retired utility in the binding actually used.
|
|
147
|
+
if (ambiguousNames.has(node.text)) {
|
|
148
|
+
uncertain = true;
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
const initializer = bindings.get(node.text);
|
|
152
|
+
if (initializer) {
|
|
153
|
+
collectExpression(initializer, seen);
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
uncertain = true;
|
|
157
|
+
}
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
if (ts.isPropertyAccessExpression(node) && ts.isIdentifier(node.expression)) {
|
|
161
|
+
if (ambiguousNames.has(node.expression.text)) {
|
|
162
|
+
uncertain = true;
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
const object = bindings.get(node.expression.text);
|
|
166
|
+
if (object && ts.isObjectLiteralExpression(object)) {
|
|
167
|
+
const property = object.properties.find((candidate) => ts.isPropertyAssignment(candidate) && candidate.name.getText(source) === node.name.text);
|
|
168
|
+
if (property && ts.isPropertyAssignment(property)) {
|
|
169
|
+
collectExpression(property.initializer, seen);
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
uncertain = true;
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
if (ts.isCallExpression(node)) {
|
|
177
|
+
const name = ts.isIdentifier(node.expression) ? node.expression.text : undefined;
|
|
178
|
+
if (name && ambiguousNames.has(name)) {
|
|
179
|
+
uncertain = true;
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
const declaration = name
|
|
183
|
+
? functions.get(name) ?? functionFromBinding({ binding: bindings.get(name) })
|
|
184
|
+
: undefined;
|
|
185
|
+
if (declaration) {
|
|
186
|
+
// Function helpers can be recursive (directly or through another
|
|
187
|
+
// helper). This is a preview report, so treat an unbounded expansion
|
|
188
|
+
// as uncertain instead of recursing until the compiler crashes.
|
|
189
|
+
if (seen.has(declaration)) {
|
|
190
|
+
uncertain = true;
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
seen.add(declaration);
|
|
194
|
+
collectFunctionReturn({ declaration, collectExpression, seen });
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
for (const argument of node.arguments)
|
|
198
|
+
collectExpression(argument, seen);
|
|
199
|
+
uncertain = true;
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
uncertain = true;
|
|
203
|
+
};
|
|
204
|
+
const visit = (node) => {
|
|
205
|
+
if (ts.isJsxAttribute(node) &&
|
|
206
|
+
(node.name.getText(source) === 'class' || node.name.getText(source) === 'className')) {
|
|
207
|
+
if (node.initializer)
|
|
208
|
+
collectExpression(node.initializer);
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
if (ts.isPropertyAssignment(node) &&
|
|
212
|
+
(node.name.getText(source) === 'class' || node.name.getText(source) === 'className')) {
|
|
213
|
+
collectExpression(node.initializer);
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
ts.forEachChild(node, visit);
|
|
217
|
+
};
|
|
218
|
+
ts.forEachChild(source, visit);
|
|
219
|
+
return { utilities, uncertain };
|
|
220
|
+
}
|
|
221
|
+
function functionFromBinding({ binding }) {
|
|
222
|
+
return binding && (ts.isArrowFunction(binding) || ts.isFunctionExpression(binding)) ? binding : undefined;
|
|
223
|
+
}
|
|
224
|
+
function collectFunctionReturn({ declaration, collectExpression, seen, }) {
|
|
225
|
+
if (!declaration.body)
|
|
226
|
+
return;
|
|
227
|
+
if (!ts.isBlock(declaration.body)) {
|
|
228
|
+
collectExpression(declaration.body, seen);
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
const visit = (node) => {
|
|
232
|
+
if (ts.isReturnStatement(node) && node.expression)
|
|
233
|
+
collectExpression(node.expression, seen);
|
|
234
|
+
ts.forEachChild(node, visit);
|
|
235
|
+
};
|
|
236
|
+
ts.forEachChild(declaration.body, visit);
|
|
237
|
+
}
|
|
238
|
+
function retiredUtilitiesInClassText({ content }) {
|
|
239
|
+
const utilities = [];
|
|
240
|
+
for (const match of content.matchAll(RETIRED_OPACITY_UTILITY)) {
|
|
241
|
+
if (match[1])
|
|
242
|
+
utilities.push(match[1]);
|
|
243
|
+
}
|
|
244
|
+
return utilities;
|
|
245
|
+
}
|
package/package.json
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"publishConfig": {
|
|
10
10
|
"access": "public"
|
|
11
11
|
},
|
|
12
|
-
"version": "0.2.
|
|
12
|
+
"version": "0.2.3",
|
|
13
13
|
"description": "SDK types and CLI library for building Artifact Studio apps. Driven via `seq-studio artifact <sub>` (@sequenceholdings/studio-cli), which runs the `./cli` runCli export.",
|
|
14
14
|
"type": "module",
|
|
15
15
|
"exports": {
|
|
@@ -57,6 +57,10 @@
|
|
|
57
57
|
"types": "./dist/active-deploy-policy.d.ts",
|
|
58
58
|
"default": "./dist/active-deploy-policy.js"
|
|
59
59
|
},
|
|
60
|
+
"./reporting-limits": {
|
|
61
|
+
"types": "./dist/reporting-limits.d.ts",
|
|
62
|
+
"default": "./dist/reporting-limits.js"
|
|
63
|
+
},
|
|
60
64
|
"./child-environment": {
|
|
61
65
|
"types": "./dist/child-environment.d.ts",
|
|
62
66
|
"default": "./dist/child-environment.js"
|
|
@@ -68,26 +72,26 @@
|
|
|
68
72
|
"VERSION-PIN.md"
|
|
69
73
|
],
|
|
70
74
|
"dependencies": {
|
|
75
|
+
"@sequenceholdings/atlas-ui": "2.0.1",
|
|
71
76
|
"@tailwindcss/postcss": "^4.1.8",
|
|
72
77
|
"@tailwindcss/vite": "^4.1.8",
|
|
73
78
|
"@tanstack/react-query": "^4.36.1",
|
|
74
|
-
"js-yaml": "^4.
|
|
79
|
+
"js-yaml": "^4.3.2",
|
|
75
80
|
"react": "^18.2.0",
|
|
76
81
|
"react-dom": "^18.2.0",
|
|
77
|
-
"react-router-dom": "^
|
|
82
|
+
"react-router-dom": "^7.18.2",
|
|
78
83
|
"sonner": "^2.0.7",
|
|
79
84
|
"tailwindcss": "^4.1.8",
|
|
80
85
|
"tw-animate-css": "^1.4.0",
|
|
81
86
|
"vite": "8.0.16",
|
|
82
87
|
"zod": "^4.1.13",
|
|
83
|
-
"@sequenceholdings/lattice-form-renderer": "0.1.2"
|
|
84
|
-
"@sequenceholdings/atlas-ui": "2.0.1"
|
|
88
|
+
"@sequenceholdings/lattice-form-renderer": "0.1.2"
|
|
85
89
|
},
|
|
86
90
|
"devDependencies": {
|
|
87
91
|
"@types/js-yaml": "^4.0.9",
|
|
88
92
|
"@types/node": "^22.0.0",
|
|
89
93
|
"typescript": "^5.6.0",
|
|
90
|
-
"vitest": "^4.1.
|
|
94
|
+
"vitest": "^4.1.11"
|
|
91
95
|
},
|
|
92
96
|
"scripts": {
|
|
93
97
|
"build": "rm -rf dist && tsc && node scripts/copy-templates.mjs",
|
|
@@ -36,7 +36,7 @@ Use **pnpm** for artifacts you will deploy from git — `seq-studio artifact bui
|
|
|
36
36
|
| `src/main.tsx` | Providers: `QueryClientProvider` → `PortalContainerProvider` → `App` |
|
|
37
37
|
| `src/App.tsx` | Entrypoint UI |
|
|
38
38
|
| `src/lib/api.ts` | `unwrap<T>` envelope helper + re-export of `seq` |
|
|
39
|
-
| `src/styles.css` | Tailwind v4 + `@sequenceholdings/atlas-ui/tokens.css`
|
|
39
|
+
| `src/styles.css` | Tailwind v4 + canonical `@sequenceholdings/atlas-ui/tokens.css` |
|
|
40
40
|
| `vite.config.ts` | Vite + React + Tailwind v4 plugin |
|
|
41
41
|
|
|
42
42
|
## Defaults
|
|
@@ -9,15 +9,15 @@
|
|
|
9
9
|
},
|
|
10
10
|
"dependencies": {},
|
|
11
11
|
"devDependencies": {
|
|
12
|
-
"@sequenceholdings/artifact-studio": "^0.1
|
|
13
|
-
"@sequenceholdings/atlas-ui": "^0.1
|
|
12
|
+
"@sequenceholdings/artifact-studio": "^0.2.1",
|
|
13
|
+
"@sequenceholdings/atlas-ui": "^2.0.1",
|
|
14
14
|
"@tailwindcss/postcss": "^4.2.2",
|
|
15
15
|
"@tailwindcss/vite": "^4.2.2",
|
|
16
16
|
"@tanstack/react-query": "^4.36.1",
|
|
17
17
|
"@vitejs/plugin-react": "^5.0.0",
|
|
18
18
|
"react": "^18.2.0",
|
|
19
19
|
"react-dom": "^18.2.0",
|
|
20
|
-
"react-router-dom": "^
|
|
20
|
+
"react-router-dom": "^7.18.2",
|
|
21
21
|
"sonner": "^2.0.7",
|
|
22
22
|
"tailwindcss": "^4.2.2",
|
|
23
23
|
"tw-animate-css": "^1.4.0",
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
@import "tailwindcss";
|
|
2
2
|
@import "tw-animate-css";
|
|
3
3
|
@import "@sequenceholdings/atlas-ui/tokens.css";
|
|
4
|
-
@import "@sequenceholdings/atlas-ui/tokens.v2.css";
|
|
5
|
-
@import "@sequenceholdings/atlas-ui/theme.v2.css";
|
|
6
4
|
|
|
7
5
|
/* Tailwind v4 skips node_modules during automatic source detection, so the
|
|
8
6
|
utility classes compiled into atlas-ui's components are never generated under
|